diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/CREDITS linux.19p18/CREDITS
--- linux.vanilla/CREDITS	Mon Dec 11 22:12:31 2000
+++ linux.19p18/CREDITS	Tue Feb 27 16:10:48 2001
@@ -23,6 +23,12 @@
 S: University of Limerick
 S: Ireland
 
+N: Tigran Aivazian
+E: tigran@veritas.com
+W: http://www.moses.uklinux.net/patches
+D: Intel IA32 microcode update driver
+S: United Kingdom
+
 N: Werner Almesberger
 E: werner.almesberger@lrc.di.epfl.ch
 D: dosfs, LILO, some fd features, various other hacks here and there
@@ -235,8 +241,8 @@
 S: Australia
 
 N: Hugh Blemings
-E: hugh@linuxcare.com
-W: http://www.linuxcare.com.au/hugh/
+E: hugh@misc.nu
+W: http://misc.nu/hugh
 D: Author and maintainer of the Keyspan USB to Serial drivers
 S: Po Box 234
 S: Belconnen ACT 2616
@@ -515,13 +521,9 @@
 S: Belgium
 
 N: Cort Dougan
-E: cort@cs.nmt.edu
-W: http://www.cs.nmt.edu/~cort/
+E: cort@fsmlabs.com
+W: http://www.fsmlabs.com/linuxppcbk.html
 D: PowerPC
-S: Computer Science Department
-S: New Mexico Tech
-S: Socorro, New Mexico 87801
-S: USA
 
 N: Oleg Drokin
 E: green@ccssu.crimea.ua
@@ -804,11 +806,11 @@
 S: Canada
 
 N: Richard Günther
-E: richard.guenther@student.uni-tuebingen.de
+E: rguenth@tat.physik.uni-tuebingen.de
+W: http://www.tat.physik.uni-tuebingen.de/~rguenth
 P: 2048/2E829319 2F 83 FC 93 E9 E4 19 E2  93 7A 32 42 45 37 23 57
 D: binfmt_misc
-S: Fichtenweg 3/511
-S: 72076 Tübingen
+S: 72074 Tübingen
 S: Germany
 
 N: Danny ter Haar
@@ -878,13 +880,13 @@
 S: USA
 
 N: Benjamin Herrenschmidt
-E: bh40@calva.net
+E: benh@kernel.crashing.org
 E: benh@mipsys.com
-D: PowerMac booter (BootX)
+D: PowerMac booters (BootX, yaboot)
 D: Additional PowerBook support
 D: Apple "Core99" machines support (ibook,g4,...)
-S: 22, rue des Marguettes
-S: 75012 Paris
+S: 122, blvd. Baille
+S: 13005 Marseille
 S: France
 
 N: Sebastian Hetze
@@ -1335,6 +1337,13 @@
 S: Niwot, Colorado 80503
 S: USA
 
+N: Robert M. Love
+E: rml@tech9.net
+E: rml@ufl.edu
+D: misc. kernel hacking and debugging
+S: Gainesville, Florida 32608
+S: USA
+
 N: H.J. Lu
 E: hjl@gnu.ai.mit.edu
 D: GCC + libraries hacker
@@ -1735,15 +1744,15 @@
 S: USA
 
 N: Kai Petzke
-E: wpp@marie.physik.tu-berlin.de
-W: http://physik.tu-berlin.de/~wpp
-P: 1024/B42868C1 D9 59 B9 98 BB 93 05 38  2E 3E 31 79 C3 65 5D E1 
+E: petzke@teltarif.de
+W: http://www.teltarif.de/
+P: 1024/B42868C1 D9 59 B9 98 BB 93 05 38  2E 3E 31 79 C3 65 5D E1
 D: Driver for Laser Magnetic Storage CD-ROM
 D: Some kernel bug fixes
 D: Port of the database Postgres
-D: "Unix fuer Jedermann" a German introduction to linux (see my web page)
-S: M"ullerstr. 69
-S: 13349 Berlin
+D: Book: "Linux verstehen und anwenden" (Hanser-Verlag)
+S: Triftstra=DFe 55
+S: 13353 Berlin
 S: Germany
 
 N: Ken Pizzini
@@ -1860,7 +1869,7 @@
 S: Germany
 
 N: Stephen Rothwell
-E: sfr@linuxcare.com
+E: sfr@linuxcare.com.au
 W: http://linuxcare.com.au/sfr
 P: 1024/BD8C7805 CD A4 9D 01 10 6E 7E 3B  91 88 FA D9 C8 40 AA 02
 D: Boot/setup/build work for setup > 2K
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/Changes linux.19p18/Documentation/Changes
--- linux.vanilla/Documentation/Changes	Mon Dec 11 22:12:31 2000
+++ linux.19p18/Documentation/Changes	Sat Dec 30 19:42:45 2000
@@ -517,6 +517,28 @@
 Older isdn4k-utils versions don't support EXTRAVERSION into kernel version
 string. A upgrade to isdn4k-utils.v3.1beta7 or later is recomented.
 
+Intel IA32 microcode
+====================
+
+A driver has been added to allow updating of Intel IA32 microcode,
+accessible as both a devfs regular file and as a normal (misc)
+character device.  If you are not using devfs you may need to:
+
+mkdir /dev/cpu
+mknod /dev/cpu/microcode c 10 184
+chmod 0644 /dev/cpu/microcode
+
+as root before you can use this.  You'll probably also want to
+get the user-space microcode_ctl utility to use with this.
+
+If you have compiled the driver as a module you may need to add
+the following line:
+
+alias char-major-10-184 microcode
+
+to your /etc/modules.conf file.
+
+
 Where to get the files
 **********************
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/Configure.help linux.19p18/Documentation/Configure.help
--- linux.vanilla/Documentation/Configure.help	Mon Dec 11 22:12:31 2000
+++ linux.19p18/Documentation/Configure.help	Sat Mar 10 23:05:47 2001
@@ -1530,7 +1530,7 @@
   inserted in and removed from the running kernel whenever you want).
   If you want to compile it as a module, say M here and read
   Documentation/modules.txt. You will get modules called i2o_core.o
-  and i20_config.o. 
+  and i2o_config.o. 
 
   If unsure, say N.
 
@@ -1765,7 +1765,7 @@
    - "586" for generic Pentium CPUs, possibly lacking the TSC 
      (time stamp counter) register.
    - "Pentium" for the Intel Pentium/Pentium MMX, AMD K5, K6 and 
-     K6-3D.
+     K6-3D, as well as the Cyrix/VIA CyrixIII
    - "PPro" for the Cyrix/IBM/National Semiconductor 6x86MX, MII and
      Intel Pentium II/Pentium Pro.
 
@@ -2233,7 +2233,7 @@
   The module will be called parport.o. If you have more than one
   parallel port and want to specify which port and IRQ to be used by
   this driver at module load time, read
-  Documentation/networking/net-modules.txt.
+  Documentation/parport.txt.
 
   If unsure, say Y.
 
@@ -3771,6 +3771,24 @@
   module, say M here and read Documentation/modules.txt and
   Documentation/scsi.txt .
 
+OnStream SC-x0 SCSI tape support
+CONFIG_CHR_DEV_OSST
+  The OnStream SC-x0 SCSI tape drives can not be driven by the 
+  standard st driver, but instead need this special osst driver and 
+  use the  /dev/osstX char device nodes (major 206).
+  For more information, you may have a look at the SCSI-HOWTO
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO  and
+  drivers/scsi/README.osst  in the kernel source. 
+  Most info may be found on http://linux1.onstream.nl/test/
+  Please also have a look at the standard st docu, as most of it
+  applies to osst as well.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called osst.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt and
+  Documentation/scsi.txt .
+
 SCSI CDROM support
 CONFIG_BLK_DEV_SR
   If you want to use a SCSI CDROM under Linux, say Y and read the
@@ -5869,6 +5887,25 @@
   If you want to compile this as a module, say M and read
   Documentation/modules.txt. The module will be called comx-hw-mixcom.o.
 
+i810 TCO support
+CONFIG_I810_TCO
+  Hardware driver for the TCO timer built into the Intel i810 and i815
+  chipset family. The TCO (Total Cost of Ownership) timer is a watchdog
+  timer that will reboot the machine after it's second expiration. The
+  expiration time can be configured by commandline argument
+  "i810_margin=<n>" where <n> is the counter initial value. It is
+  decremented every 0.6 secs, the default is 50 which gives a timeout
+  of 30 seconds and one minute until reset.
+
+  On some motherboards the driver may fail to reset the chipset's
+  NO_REBOOT flag which prevents the watchdog from rebooting the machine.
+  If this is the case you will get a kernel message like
+  "i810tco init: failed to reset NO_REBOOT flag".
+
+  If you want to compile this as a module, say M and read
+  Documentation/modules.txt. The module will be called
+  i810-tco.o.
+
 MultiGate Cisco-HDLC and synchronous PPP protocol support
 CONFIG_COMX_PROTO_PPP
   Cisco-HDLC and synchronous PPP protocol driver for all MultiGate boards. 
@@ -6187,6 +6224,37 @@
   say M here and read Documentation/modules.txt. This is recommended.
   The module will be called rtl8139.o.
 
+Alternative RealTek 8139 driver (8139too) support
+CONFIG_RTL8139TOO
+  This is a sophisticated, multi platform driver for RealTek 8139x
+  based Fast Ethernet cards. It tries to work around several not
+  well documented hardware bugs in these chips and is also
+  usually faster than the original driver. However, 8129 is not
+  supported.
+  If you are sure you have a RTL8139-based card, choose this driver.
+  You can find more information in the Ethernet-HOWTO, available by
+  anonymous FTP from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO .
+
+  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),
+  say M here and read Documentation/modules.txt. This is recommended.
+  The module will be called rtl8139too.o .
+
+Use PIO instead of MMIO
+CONFIG_8139TOO_PIO
+  This instructs the driver to use PIO (only on i386 architecture)
+  instead of memory mapped IO. This can possibly solve some problems
+  in case your mainboard has memory consistency issues. If unsure,
+  say n.
+
+Support for automatic channel equalization
+CONFIG_8139TOO_TUNE_TWISTER
+  This implements a function which might come in handy in case
+  you are using low quality on long cabling. It tries to match
+  the transceiver to the cable characteristics. This is experimental
+  since hardly documented by the manufacturer.
+  If unsure, say n.
+
 SiS 900/7016 support
 CONFIG_SIS900
   This is a driver for the Fast Ethernet PCI network cards based on
@@ -6238,6 +6306,18 @@
 
   If you don't have this card, of course say N.
 
+Adaptec Starfire support (EXPERIMENTAL)
+CONFIG_ADAPTEC_STARFIRE
+  Say Y here if you have an Adaptec Starfire (or DuraLAN) PCI network
+  adapter. The DuraLAN chip is used on the 64 bit PCI boards from
+  Adaptec e.g. the ANA-6922A. The older 32 bit boards use the tulip
+  driver.
+  
+  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),
+  say M here and read Documentation/modules.txt. This is recommended.
+  The module will be called starfire.o.
+  
 Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support
 CONFIG_ACENIC
   Say Y here if you have an Alteon AceNIC or 3Com 3C985 PCI Gigabit
@@ -6790,6 +6870,16 @@
   Documentation/networking/net-modules.txt. The module will be called
   apricot.o.
 
+LP486E on board Ethernet
+CONFIG_LP486E
+  If you have an Intel Panther motherboard with on board 82596 network
+  (Ethernet) controller, say Y here.
+  The initialization code tries to guess the ethernet address by looking
+  at the EISA configuration area. Probably it finds precisely one thing
+  that looks like an address, but if this fails use the command
+    ifconfig eth0 hw ether a1:a2:a3:a4:a5:a6
+  to assign the address (revealed by the BIOS Setup) by hand.
+
 Generic DECchip & DIGITAL EtherWORKS PCI/EISA
 CONFIG_DE4X5
   This is support for the DIGITAL series of PCI/EISA Ethernet cards.
@@ -7475,13 +7565,6 @@
   ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini. Probably the quota
   support is only useful for multi user systems. If unsure, say N.
 
-Acorn's ADFS filesystem support (read only) (EXPERIMENTAL)
-CONFIG_ADFS_FS
-  The Advanced Disk File System is the filesystem used on floppy and
-  hard disks by Acorn Systems.  Currently in development, as a read-
-  only driver for hard disks.  These should be the first partition
-  (eg. /dev/[sh]d?1) on each of your drives.  If unsure, say N.
-
 Support for USB
 CONFIG_USB
   Universal Serial Bus (USB) is a specification for a serial bus
@@ -7854,6 +7937,16 @@
   The module will be called digi_acceleport.o. If you want to compile 
   it as a module, say M here and read Documentation/modules.txt.
 
+USB Empeg empeg-car Mark I/II Driver
+CONFIG_USB_SERIAL_EMPEG
+  Say Y here if you want to connect to your Empeg empeg-car Mark I/II
+  mp3 player via USB.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called empeg.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt.
+
 USB Serial Converter verbose debug
 CONFIG_USB_SERIAL_DEBUG
   Say Y here if you want verbose debug messages from the USB Serial
@@ -8423,10 +8516,10 @@
   The module is called nfsd.o. If you want to compile it as a module,
   say M here and read Documentation/modules.txt. If unsure, say N.
 
-Provide NFSv3 server support (EXPERIMENTAL)
+Provide NFSv3 server support
 CONFIG_NFSD_V3
   If you would like to include the NFSv3 server as well as the NFSv2
-  server, say Y here.  File locking, via the NLMv4 protocol, is now
+  server, say Y here.  File locking, via the NLMv4 protocol, is also
   supported. If unsure, say N.
 
 OS/2 HPFS filesystem support (read only)
@@ -8730,6 +8823,12 @@
   partition tables of Macintosh hard drives, and thus use partitions
   on those drives.
 
+Minix subpartition support
+CONFIG_MINIX_SUBPARTITION
+  Minix 2.0.0/2.0.2 subpartition table support for Linux.
+  Say Y here if you want to mount and use Minix 2.0.0/2.0.2
+  subpartitions.
+
 SMB filesystem support (to mount Windows shares etc...)
 CONFIG_SMB_FS
   SMB (Server Message Block) is the protocol Windows for Workgroups
@@ -9262,6 +9361,14 @@
   input/output character sets. Say Y here for the preferred Russian
   character set.
 
+nls koi8-ru
+CONFIG_NLS_KOI8_RU
+  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 preferred Russian
+  character set.
+
 Virtual terminal
 CONFIG_VT
   If you say Y here, you will get support for terminal devices with
@@ -9654,6 +9761,24 @@
   If you have more than 3 printers, you need to increase the LP_NO
   variable in lp.c.
 
+Amiga built-in parallel port support
+CONFIG_PARPORT_AMIGA
+  Say Y here if you need support for the parallel port hardware on
+  Amiga machines. This code is also available as a module (say M),
+  called parport_amiga.o. If in doubt, saying N is the safe plan.
+
+Atari built-in parallel port support
+CONFIG_PARPORT_ATARI
+  Say Y here if you need support for the parallel port hardware on
+  Atari machines. This code is also available as a module (say M),
+  called parport_atari.o. If in doubt, saying N is the safe plan.
+
+Multiface 3 parallel port card support
+CONFIG_PARPORT_MFC3
+  Say Y here if you need parallel port support for the MFC3 card.
+  This code is also available as a module (say M), called
+  parport_mfc3.o. If in doubt, saying N is the safe plan.
+
 Support IEEE1284 status readback
 CONFIG_PRINTER_READBACK
   If your printer conforms to IEEE 1284, it may be able to provide a
@@ -10411,12 +10536,12 @@
  it as a module.  The module will be called sbc60xxwdt.o.
 
 CONFIG_MICROCODE
-  /dev/cpu/microcode - Intel P6 CPU microcode support
+  /dev/cpu/microcode - Intel IA32 CPU microcode support
 
   If you say Y here you will be able to update the microcode on
-  Intel processors in the P6 family, e.g. Pentium Pro, Pentium II,
-  Pentium III, Xeon etc. You will obviously need the actual microcode
-  binary data itself which is not shipped with the Linux kernel.
+  Intel processors in the IA32 family, e.g. Pentium Pro, Pentium II,
+  Pentium III, Xeon, Pentium 4 etc. You will obviously need the actual
+  microcode binary data itself which is not shipped with the Linux kernel.
  
   For latest news and information on obtaining all the required
   ingredients for this driver, check:
@@ -10425,7 +10550,9 @@
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
   The module will be called microcode.o. If you want to compile it as
-  a module, say M here and read Documentation/modules.txt.
+  a module, say M here and read Documentation/modules.txt. If you use
+  modprobe or kmod you may also want to add the line
+  'alias char-major-10-184 microcode' to your /etc/modules.conf file.
 
 /dev/cpu/*/msr - Model-specific register support
 CONFIG_X86_MSR
@@ -10476,8 +10603,8 @@
 
 Intel 440LX/BX/GX support
 CONFIG_AGP_INTEL
-  This option give you AGP support for the GLX component of the
-  "soon to be released" XFree86-4 on Intel 440LX/BX/GX chipsets.
+  This option gives you AGP support for the GLX component of
+  XFree86 4.x on Intel 440LX/BX/GX, 815, and 840 chipsets.
 
   For the moment, most people should say no, unless you want to
   test the GLX component which can be downloaded from
@@ -10485,9 +10612,9 @@
 
 Intel I810/I810 DC100/I810e support
 CONFIG_AGP_I810
-  This option give you AGP support for the Xserver for the intel
-  810 chipset boards. This is required to do any useful video
-  modes.
+  This option gives you AGP support for XFree86 on the Intel 810
+  and 815 chipsets for their on-board integrated graphics. This
+  is required to do any useful video modes with these boards.
 
 VIA VP3/MVP3/Apollo Pro support
 CONFIG_AGP_VIA
@@ -10698,17 +10825,6 @@
   to it. For more information on how to use the driver please read
   Documentation/joystick.txt
 
-Atomwide Serial Support
-CONFIG_ATOMWIDE_SERIAL
-  If you have an Atomwide Serial card for an Acorn system, say Y to
-  this option. The driver can handle 1, 2, or 3 port cards.
-  If unsure, say N
-
-The Serial Port Dual Serial Port
-CONFIG_DUALSP_SERIAL
-  If you have the Serial Port's dual serial card for an Acorn system,
-  say Y to this option. If unsure, say N
-
 NetWinder Button
 CONFIG_NWBUTTON
   If you enable this driver and create a character device node
@@ -10976,8 +11092,7 @@
 Support for OPTi MAD16 and/or Mozart based cards
 CONFIG_SOUND_MAD16
   Answer Y if your card has a Mozart (OAK OTI-601) or MAD16 (OPTi
-  82C928 or 82C929 or 82C931) audio interface chip. For the 82C931,
-  please read drivers/sound/README.C931. These chips are currently
+  82C928 or 82C929 or 82C931) audio interface chip. These chips are 
   quite common so it's possible that many no-name cards have one of
   them. In addition the MAD16 chip is used in some cards made by known
   manufacturers such as Turtle Beach (Tropez), Reveal (some models)
@@ -11377,7 +11492,15 @@
 CONFIG_SOUND_MAESTRO
   Say Y or M if you have a sound system driven by ESS's Maestro line
   of PCI sound chips.  These include the Maestro 1, Maestro 2, and
-  Maestro 2E.  See Documentation/sound/Maestro for more details.
+  Maestro 2E, but _does not_ include the Maestro 3 and Allegro 
+  line of chips.  See Documentation/sound/Maestro for more details
+  on the 1/2/2e line.
+
+ESS Maestro3/Allegro sound chipsets
+CONFIG_SOUND_MAESTRO3
+  Say Y or M if you have a sound system driven by ESS's Maestro3 line
+  of PCI sound chips.  This includes the Allegro sound chip that is
+  a lighter version of the Maestro3.
 
 Are you using a crosscompiler
 CONFIG_CROSSCOMPILE
@@ -11560,6 +11683,10 @@
 CONFIG_HISAX_1TR6
   Enable this if you have a old german 1TR6 line.
 
+HiSax Support for US NI1
+CONFIG_HISAX_NI1
+  Enable this if you like to use ISDN in US on a NI1 basic rate interface.
+
 Teles 16.0/8.0
 CONFIG_HISAX_16_0
   This enables HiSax support for the Teles ISDN-cards S0-16.0, S0-8
@@ -11688,6 +11815,13 @@
   See Documentation/isdn/README.HiSax on how to configure it using a
   different D-channel protocol, or non-standard IRQ/port settings.
 
+NETspider U card
+CONFIG_HISAX_NETJET_U
+  This enables HiSax support for the Netspider U interface ISDN card from
+  Traverse Technologies.
+  See Documentation/isdn/README.HiSax on how to configure it using a
+  different D-channel protocol, or non-standard IRQ/port settings.
+
 Niccy PnP/PCI card
 CONFIG_HISAX_NICCY
   This enables HiSax support for the Dr. Neuhaus Niccy PnP or PCI. 
@@ -11776,7 +11910,7 @@
   called sc.o. See Documentation/isdn/README.sc and
   http://www.spellcast.com for more information.
 
-Eicon.Diehl active card support
+Eicon active card support
 CONFIG_ISDN_DRV_EICON
   Say Y here if you have an Eicon active ISDN card. In order to use
   this card, additional firmware is necessary, which has to be loaded
@@ -11784,6 +11918,16 @@
   latest isdn4k-utils package. Please read the file
   Documentation/isdn/README.eicon for more information.
   
+Eicon legacy driver
+CONFIG_ISDN_DRV_EICON_OLD
+  Say Y here to use your Eicon active ISDN card with ISDN4Linux
+  isdn module.
+
+Eicon Diva Server card support
+CONFIG_ISDN_DRV_EICON_PCI
+  Say Y here if you have an Eicon Diva Server (BRI/PRI/4BRI) ISDN card.
+  Please read Documentation/isdn/README.eicon for more information.
+
 Eicon old-type card support
 CONFIG_ISDN_DRV_EICON_ISA
   Say Y here if you have an old-type Eicon active ISDN card. In order
@@ -11792,6 +11936,14 @@
   the latest isdn4k-utils package. Please read the file
   Documentation/isdn/README.eicon for more information.
 
+Eicon driver type standalone
+CONFIG_ISDN_DRV_EICON_DIVAS
+  Enable this option if you want the eicon driver as standalone
+  version with no interface to the ISDN4Linux isdn module. If you
+  say Y here, the eicon module only supports the Diva Server PCI
+  cards and will provide its own IDI interface. You should say N
+  here.
+
 Support AT-Fax Class 2 commands
 CONFIG_ISDN_TTY_FAX
   If you say Y here, the modem-emulator will support a subset of the
@@ -11800,22 +11952,19 @@
   an ISDN-fax-machine. This must be supported by the lowlevel driver
   also. See Documentation/isdn/README.fax for more information.
 
-AVM CAPI2.0 support
-CONFIG_ISDN_DRV_AVMB1
-  This enables support for the AVM B1/T1 ISDN networking cards.In
-  addition, a CAPI (Common ISDN Application Programming Interface, a
-  standard making it easy for programs to access ISDN hardware, see
-  http://www.capi.org/; to browse the WWW, you need to have access to
-  a machine on the Internet that has a program like lynx or netscape)
-  interface for this card is provided. In order to use this card,
-  additional firmware is necessary, which has to be downloaded into
-  the card using a utility which is distributed separately. Please
-  read the file Documentation/isdn/README.avmb1. 
-  
-  This code is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called avmb1.o. If you want to compile it as a
-  module, say M here and read Documentation/modules.txt.
+CAPI2.0 support
+CONFIG_ISDN_CAPI
+  This option enables a CAPI2.0 (Common ISDN Application Programming
+  Interface), a standard making it easy for programs to access ISDN
+  hardware, see http://www.capi.org/
+
+CAPI2.0 Middleware support
+CONFIG_ISDN_CAPI_MIDDLEWARE
+  This option enables CAPI2.0 Middleware support
+
+CAPI2.0 filesystem support
+CONFIG_ISDN_CAPIFS
+  This option enables CAPI CAPI2.0 filesystem support 
 
 AVM B1 ISA support
 CONFIG_ISDN_DRV_AVMB1_B1ISA
@@ -12764,22 +12913,6 @@
 CONFIG_RADIO_ZOLTRIX_PORT
   Enter the I/O port of your Zoltrix radio card.
 
-ADS Cadet AM/FM Tuner
-CONFIG_RADIO_CADET
-  Say Y here if this is your AM/FM radio card.
-
-  In order to control your radio card, you will need to use programs
-  that are compatible with the Video for Linux API. Information on 
-  this API and pointers to "v4l" programs may be found on the WWW at
-  http://roadrunner.swansea.uk.linux.org/v4l.shtml; to browse the WWW,
-  you need to have access to a machine on the Internet that has a 
-  program like lynx or netscape.
-
-  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),
-  say M here and read Documentation/modules.txt. The module will be
-  called radio-cadet.o
-
 Miro PCM20 Radio
 CONFIG_RADIO_MIROPCM20
   Choose Y here if you have this FM radio card. You also need to say Y
@@ -13086,6 +13219,10 @@
   it as a module, say M here and read Documentation/modules.txt. The
   module will be called 
 
+IrDA protocol options
+CONFIG_IRDA_OPTIONS
+  Say Y here if you want to configure any of the following IrDA options.
+
 IrDA Cache last LSAP
 CONFIG_IRDA_CACHE_LAST_LSAP
   Say Y here if you want IrLMP to cache the last LSAP used. This makes
@@ -13505,6 +13642,20 @@
   If you do not have a CompactPCI model CP1400 or CP1500, or 
   another UltraSPARC-IIi-cEngine boardset with digital display,
   you should say N to this option.
+
+CP1XXX Hardware Watchdog support
+CONFIG_WATCHDOG_CP1XXX
+  This is the driver for the hardware watchdog timers present on
+  Sun Microsystems CompactPCI models CP1400 and CP1500.
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called cpwatchdog.o. If you want to compile it
+  as a module, say M here and read Documentation/modules.txt.
+ 
+  If you do not have a CompactPCI model CP1400 or CP1500, or
+  another UltraSPARC-IIi-cEngine boardset with hardware watchdog,
+  you should say N to this option. 
    
 #
 # A couple of things I keep forgetting:
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/README.DAC960 linux.19p18/Documentation/README.DAC960
--- linux.vanilla/Documentation/README.DAC960	Mon Dec 11 22:12:31 2000
+++ linux.19p18/Documentation/README.DAC960	Wed Feb 14 14:23:34 2001
@@ -1,17 +1,17 @@
    Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers
 
-			Version 2.2.9 for Linux 2.2.17
-			Version 2.4.9 for Linux 2.4.0
+			Version 2.2.10 for Linux 2.2.18
+			Version 2.4.10 for Linux 2.4.1
 
 			      PRODUCTION RELEASE
 
-			       7 September 2000
+			       1 February 2001
 
 			       Leonard N. Zubkoff
 			       Dandelion Digital
 			       lnz@dandelion.com
 
-	 Copyright 1998-2000 by Leonard N. Zubkoff <lnz@dandelion.com>
+	 Copyright 1998-2001 by Leonard N. Zubkoff <lnz@dandelion.com>
 
 
 				 INTRODUCTION
@@ -197,19 +197,19 @@
 properly initializes the AcceleRAID 250, AcceleRAID 200, AcceleRAID 150,
 DAC960PJ, and DAC960PG because the Intel i960RD/RP is a multi-function device.
 If in doubt, contact Mylex RAID Technical Support (support@mylex.com) to verify
-compatibility.  Mylex makes available a hard disk compatibility list by FTP at
-ftp://ftp.mylex.com/pub/dac960/diskcomp.html.
+compatibility.  Mylex makes available a hard disk compatibility list at
+http://www.mylex.com/support/hdcomp/hd-lists.html.
 
 
 			      DRIVER INSTALLATION
 
-This distribution was prepared for Linux kernel version 2.2.17 or 2.4.0.
+This distribution was prepared for Linux kernel version 2.2.18 or 2.4.1.
 
 To install the DAC960 RAID driver, you may use the following commands,
 replacing "/usr/src" with wherever you keep your Linux kernel source tree:
 
   cd /usr/src
-  tar -xvzf DAC960-2.2.9.tar.gz (or DAC960-2.4.9.tar.gz)
+  tar -xvzf DAC960-2.2.10.tar.gz (or DAC960-2.4.10.tar.gz)
   mv README.DAC960 linux/Documentation
   mv DAC960.[ch] linux/drivers/block
   patch -p0 < DAC960.patch (if DAC960.patch is included)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/binfmt_misc.txt linux.19p18/Documentation/binfmt_misc.txt
--- linux.vanilla/Documentation/binfmt_misc.txt	Fri Apr 21 12:45:49 2000
+++ linux.19p18/Documentation/binfmt_misc.txt	Tue Feb 27 16:11:14 2001
@@ -81,6 +81,6 @@
 
 
 There is a web page about binfmt_misc at
-http://www.anatom.uni-tuebingen.de/~richi/linux/binfmt_misc.html
+http://www.tat.physik.uni-tuebingen.de/~rguenth/linux/binfmt_misc.html
 
-Richard Günther, richard.guenther@student.uni-tuebingen.de
+Richard Günther <rguenth@tat.physik.uni-tuebingen.de>
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/devices.txt linux.19p18/Documentation/devices.txt
--- linux.vanilla/Documentation/devices.txt	Fri Apr 21 12:45:49 2000
+++ linux.19p18/Documentation/devices.txt	Sat Dec 30 19:25:47 2000
@@ -1,8 +1,8 @@
 
 		       LINUX ALLOCATED DEVICES
-	     Maintained by H. Peter Anvin <hpa@zytor.com>
+	     Maintained by H. Peter Anvin <device@lanana.org>
 
-		     Last revised: March 23, 2000
+		   Last revised: December 29, 2000
 
 This list is the Linux Device List, the official registry of allocated
 device numbers and /dev directory nodes for the Linux operating
@@ -37,7 +37,7 @@
 reply.
 
 
-     **** PLEASE READ THIS BEFORE SUBMITTING A DEVICE ENTRY ****
+	  **** DEVICE DRIVERS AUTHORS PLEASE READ THIS ****
 
 To have a major number allocated, or a minor number in situations
 where that applies (e.g. busmice), please contact me with the
@@ -45,24 +45,32 @@
 information regarding any of the devices listed below, or if I have
 made a mistake, I would greatly appreciate a note.
 
-I do, however, make two requests about the nature of your report.
+I do, however, make a few requests about the nature of your report.
 This is necessary for me to be able to keep this list up to date and
-correct in a timely manner.  First of all, *please* include the word
-"device" in the subject so your mail won't accidentally get buried!  I
-receive hundreds of email messages a day, so mail sent with other
-subjects may very well get lost in the avalanche.
+correct in a timely manner.  First of all, *please* send it to the
+correct address... <device@lanana.org>.  I receive hundreds of email
+messages a day, so mail sent to other addresses may very well get lost
+in the avalanche.  Please put in a descriptive subject, so I can find
+your mail again should I need to.  Too many people send me email
+saying just "device number request" in the subject.
 
 Second, please include a description of the device *in the same format
 as this list*.	The reason for this is that it is the only way I have
 found to ensure I have all the requisite information to publish your
 device and avoid conflicts.
 
+Third, please don't assume that the distributed version of the list is
+up to date.  Due to the number of registrations I have to maintain it
+in "batch mode", so there is likely additional registrations that
+haven't been listed yet.
+
 Finally, sometimes I have to play "namespace police."  Please don't be
 offended.  I often get submissions for /dev names that would be bound
 to cause conflicts down the road.  I am trying to avoid getting in a
 situation where we would have to suffer an incompatible forward
-change.
-
+change.  Therefore, please consult with me *before* you make your
+device names and numbers in any way public, at least to the point
+where it would be at all difficult to get them changed.
 
 Your cooperation is appreciated.
 
@@ -80,16 +88,18 @@
 		  7 = /dev/full		Returns ENOSPC on write
 		  8 = /dev/random	Nondeterministic random number gen.
 		  9 = /dev/urandom	Faster, less secure random number gen.
+		 10 = /dev/aio		Asyncronous I/O notification interface
     block	RAM disk
 		  0 = /dev/ram0		First RAM disk
+		  1 = /dev/ram1		Second RAM disk
 		    ...
-		  7 = /dev/ram7		Eighth RAM disk
-		250 = /dev/initrd	Initial RAM disk
+		250 = /dev/initrd	Initial RAM disk {2.6}
 
 		Older kernels had /dev/ramdisk (1, 1) here.
 		/dev/initrd refers to a RAM disk which was preloaded
-		by the boot loader.
-		    
+		by the boot loader; newer kernels use /dev/ram0 for
+		the initrd.
+
   2 char	Pseudo-TTY masters
 		  0 = /dev/ptyp0	First PTY master
 		  1 = /dev/ptyp1	Second PTY master
@@ -200,6 +210,8 @@
 		    ...
 		255 = /dev/ttyS191	192nd UART serial port
 
+		UART serial ports refer to 8250/16450/16550 series devices.
+
 		Older versions of the Linux kernel used this major
 		number for BSD PTY devices.  As of Linux 2.1.115, this
 		is no longer supported.	 Use major numbers 2 and 3.
@@ -311,6 +323,8 @@
 		 10 = /dev/adbmouse	Apple Desktop Bus mouse
 		 11 = /dev/vrtpanel	Vr41xx embedded touch panel
 		 13 = /dev/vpcmouse	Connectix Virtual PC Mouse
+		 14 = /dev/touchscreen/ucb1x00  UCB 1x00 touchscreen
+		 15 = /dev/touchscreen/mk712	MK712 touchscreen
 		128 = /dev/beep		Fancy beep device
 		129 = /dev/modreq	Kernel module load request {2.6}
 		130 = /dev/watchdog	Watchdog timer port
@@ -322,7 +336,7 @@
 		139 = /dev/openprom	SPARC OpenBoot PROM
 		140 = /dev/relay8	Berkshire Products Octal relay card
 		141 = /dev/relay16	Berkshire Products ISO-16 relay card
-		142 = /dev/msr		x86 model-specific registers
+		142 = /dev/msr		x86 model-specific registers {2.6}
 		143 = /dev/pciconf	PCI configuration space
 		144 = /dev/nvram	Non-volatile configuration RAM
 		145 = /dev/hfmodem	Soundcard shortwave modem control {2.6}
@@ -364,6 +378,26 @@
 		182 = /dev/perfctr	Performance-monitoring counters
 		183 = /dev/intel_rng	Intel i8x0 random number generator
 		184 = /dev/cpu/microcode CPU microcode update interface
+		186 = /dev/atomicps	Atomic shapshot of process state data
+		187 = /dev/irnet	IrNET device
+		188 = /dev/smbusbios	SMBus BIOS
+		189 = /dev/ussp_ctl	User space serial port control
+		190 = /dev/crash	Mission Critical Linux crash dump facility
+		191 = /dev/pcl181	<information missing>
+		192 = /dev/nas_xbus	NAS xbus LCD/buttons access
+		193 = /dev/d7s		SPARC 7-segment display
+		194 = /dev/zkshim	Zero-Knowledge network shim control
+		195 = /dev/elographics/e2201	Elographics touchscreen E271-2201
+		198 = /dev/sexec	Signed executable interface
+		199 = /dev/scanners/cuecat :CueCat barcode scanner
+		200 = /dev/net/tun	TAP/TUN network device
+		201 = /dev/button/gulpb	Transmeta GULP-B buttons
+		204 = /dev/video/em8300	    EM8300 DVD decoder control
+		205 = /dev/video/em8300_mv  EM8300 DVD decoder video
+		206 = /dev/video/em8300_ma  EM8300 DVD decoder audio
+		207 = /dev/video/em8300_sp  EM8300 DVD decoder subpicture
+		208 = /dev/compaq/cpqphpc Compaq PCI Hot Plug Controller
+		209 = /dev/compaq/cpqrid  Compaq Remote Insight Driver
 		240-255			Reserved for local use
 
  11 char	Raw keyboard device
@@ -902,29 +936,62 @@
 		  0 = /dev/ttyL0	First RISCom port
 		  1 = /dev/ttyL1	Second RISCom port
 		    ...
-    block	Reserved for Mylex DAC960 PCI RAID controller
+    block	Mylex DAC960 PCI RAID controller; first controller
+		  0 = /dev/rd/c0d0	First disk, whole disk
+		  8 = /dev/rd/c0d1	Second disk, whole disk
+		    ...
+		248 = /dev/rd/c0d15	16th disk, whole disk
+
+		For partitions add:
+		  0 = /dev/rd/c?d?	Whole disk
+		  1 = /dev/rd/c?d?p1	First partition
+		    ...
+		  7 = /dev/rd/c?d?p7	Seventh partition
 
  49 char	SDL RISCom serial card - alternate devices
 		  0 = /dev/cul0		Callout device for ttyL0
 		  1 = /dev/cul1		Callout device for ttyL1
 		    ...
-    block	Reserved for Mylex DAC960 PCI RAID controller
+    block	Mylex DAC960 PCI RAID controller; second controller
+		  0 = /dev/rd/c1d0	First disk, whole disk
+		  8 = /dev/rd/c1d1	Second disk, whole disk
+		    ...
+		248 = /dev/rd/c1d15	16th disk, whole disk
+
+		Partitions are handled as for major 48.
 
  50 char	Reserved for GLINT
-    block	Reserved for Mylex DAC960 PCI RAID controller
+
+    block	Mylex DAC960 PCI RAID controller; third controller
+		  0 = /dev/rd/c2d0	First disk, whole disk
+		  8 = /dev/rd/c2d1	Second disk, whole disk
+		    ...
+		248 = /dev/rd/c2d15	16th disk, whole disk
 
  51 char	Baycom radio modem
 		  0 = /dev/bc0		First Baycom radio modem
 		  1 = /dev/bc1		Second Baycom radio modem
 		    ...
-    block	Reserved for Mylex DAC960 PCI RAID controller
+    block	Mylex DAC960 PCI RAID controller; fourth controller
+		  0 = /dev/rd/c3d0	First disk, whole disk
+		  8 = /dev/rd/c3d1	Second disk, whole disk
+		    ...
+		248 = /dev/rd/c3d15	16th disk, whole disk
+
+		Partitions are handled as for major 48.
 
  52 char	Spellcaster DataComm/BRI ISDN card
 		  0 = /dev/dcbri0	First DataComm card
 		  1 = /dev/dcbri1	Second DataComm card
 		  2 = /dev/dcbri2	Third DataComm card
 		  3 = /dev/dcbri3	Fourth DataComm card
-    block	Reserved for Mylex DAC960 PCI RAID controller
+    block	Mylex DAC960 PCI RAID controller; fifth controller
+		  0 = /dev/rd/c4d0	First disk, whole disk
+		  8 = /dev/rd/c4d1	Second disk, whole disk
+		    ...
+		248 = /dev/rd/c4d15	16th disk, whole disk
+
+		Partitions are handled as for major 48.
 
  53 char	BDM interface for remote debugging MC683xx microcontrollers
 		  0 = /dev/pd_bdm0	PD BDM interface on lp0
@@ -940,7 +1007,13 @@
 		Domain Interface and ICD is the commercial interface
 		by P&E.
 
-    block	Reserved for Mylex DAC960 PCI RAID controller
+    block	Mylex DAC960 PCI RAID controller; sixth controller
+		  0 = /dev/rd/c5d0	First disk, whole disk
+		  8 = /dev/rd/c5d1	Second disk, whole disk
+		    ...
+		248 = /dev/rd/c5d15	16th disk, whole disk
+
+		Partitions are handled as for major 48.
 
  54 char	Electrocardiognosis Holter serial card
 		  0 = /dev/holter0	First Holter port
@@ -951,11 +1024,23 @@
 		<mseritan@ottonel.pub.ro> to transfer data from Holter
 		24-hour heart monitoring equipment.
 
-    block	Reserved for Mylex DAC960 PCI RAID controller
+    block	Mylex DAC960 PCI RAID controller; seventh controller
+		  0 = /dev/rd/c6d0	First disk, whole disk
+		  8 = /dev/rd/c6d1	Second disk, whole disk
+		    ...
+		248 = /dev/rd/c6d15	16th disk, whole disk
+
+		Partitions are handled as for major 48.
 
  55 char	DSP56001 digital signal processor
 		  0 = /dev/dsp56k	First DSP56001
-    block	Reserved for Mylex DAC960 PCI RAID controller
+    block	Mylex DAC960 PCI RAID controller; eigth controller
+		  0 = /dev/rd/c7d0	First disk, whole disk
+		  8 = /dev/rd/c7d1	Second disk, whole disk
+		    ...
+		248 = /dev/rd/c7d15	16th disk, whole disk
+
+		Partitions are handled as for major 48.
 
  56 char	Apple Desktop Bus
 		  0 = /dev/adb		ADB bus control
@@ -1002,6 +1087,8 @@
 		running small fs translation drivers) through serial /
 		IRDA / parallel links.
 
+		NAMING CONFLICT -- PROPOSED REVISED NAME /dev/rpda0 etc
+
  60-63		LOCAL/EXPERIMENTAL USE
 		Allocated for local/experimental use.  For devices not
 		assigned official numbers, these ranges should be
@@ -1176,6 +1263,16 @@
 		    ...
 		255 = /dev/cuf255	Callout device for ttyF255
 
+    block	Compaq Intelligent Drive Array, first controller
+		  0 = /dev/ida/c0d0	First logical drive whole disk
+		 16 = /dev/ida/c0d1	Second logical drive whole disk
+		    ...
+		240 = /dev/ida/c0d15	16th logical drive whole disk
+
+		Partitions are handled the same way as for Mylex
+		DAC960 (see major number 48) except that the limit on
+		partitions is 15.
+
  73 char	Computone IntelliPort II serial card - control devices
 		  0 = /dev/ip2ipl0	Loadware device for board 0
 		  1 = /dev/ip2stat0	Status device for board 0
@@ -1186,6 +1283,16 @@
 		 12 = /dev/ip2ipl3	Loadware device for board 3
 		 13 = /dev/ip2stat3	Status device for board 3
 
+    block	Compaq Intelligent Drive Array, second controller
+		  0 = /dev/ida/c1d0	First logical drive whole disk
+		 16 = /dev/ida/c1d1	Second logical drive whole disk
+		    ...
+		240 = /dev/ida/c1d15	16th logical drive whole disk
+
+		Partitions are handled the same way as for Mylex
+		DAC960 (see major number 48) except that the limit on
+		partitions is 15.
+
  74 char	SCI bridge
 		  0 = /dev/SCI/0	SCI device 0
 		  1 = /dev/SCI/1	SCI device 1
@@ -1194,6 +1301,16 @@
 		Currently for Dolphin Interconnect Solutions' PCI-SCI
 		bridge.
 
+    block	Compaq Intelligent Drive Array, third controller
+		  0 = /dev/ida/c2d0	First logical drive whole disk
+		 16 = /dev/ida/c2d1	Second logical drive whole disk
+		    ...
+		240 = /dev/ida/c2d15	16th logical drive whole disk
+
+		Partitions are handled the same way as for Mylex
+		DAC960 (see major number 48) except that the limit on
+		partitions is 15.
+
  75 char	Specialix IO8+ serial card
 		  0 = /dev/ttyW0	First IO8+ port, first card
 		  1 = /dev/ttyW1	Second IO8+ port, first card
@@ -1201,6 +1318,16 @@
 		  8 = /dev/ttyW8	First IO8+ port, second card
 		    ...
 
+    block	Compaq Intelligent Drive Array, fourth controller
+		  0 = /dev/ida/c3d0	First logical drive whole disk
+		 16 = /dev/ida/c3d1	Second logical drive whole disk
+		    ...
+		240 = /dev/ida/c3d15	16th logical drive whole disk
+
+		Partitions are handled the same way as for Mylex
+		DAC960 (see major number 48) except that the limit on
+		partitions is 15.
+
  76 char	Specialix IO8+ serial card - alternate devices
 		  0 = /dev/cuw0		Callout device for ttyW0
 		  1 = /dev/cuw1		Callout device for ttyW1
@@ -1208,19 +1335,63 @@
 		  8 = /dev/cuw8		Callout device for ttyW8
 		    ...
 
+    block	Compaq Intelligent Drive Array, fifth controller
+		  0 = /dev/ida/c4d0	First logical drive whole disk
+		 16 = /dev/ida/c4d1	Second logical drive whole disk
+		    ...
+		240 = /dev/ida/c4d15	16th logical drive whole disk
+
+		Partitions are handled the same way as for Mylex
+		DAC960 (see major number 48) except that the limit on
+		partitions is 15.
+
+
  77 char	ComScire Quantum Noise Generator
 		  0 = /dev/qng		ComScire Quantum Noise Generator
 
+    block	Compaq Intelligent Drive Array, sixth controller
+		  0 = /dev/ida/c5d0	First logical drive whole disk
+		 16 = /dev/ida/c5d1	Second logical drive whole disk
+		    ...
+		240 = /dev/ida/c5d15	16th logical drive whole disk
+
+		Partitions are handled the same way as for Mylex
+		DAC960 (see major number 48) except that the limit on
+		partitions is 15.
+
+
  78 char	PAM Software's multimodem boards
 		  0 = /dev/ttyM0	First PAM modem
 		  1 = /dev/ttyM1	Second PAM modem
 		    ...
 
+    block	Compaq Intelligent Drive Array, seventh controller
+		  0 = /dev/ida/c6d0	First logical drive whole disk
+		 16 = /dev/ida/c6d1	Second logical drive whole disk
+		    ...
+		240 = /dev/ida/c6d15	16th logical drive whole disk
+
+		Partitions are handled the same way as for Mylex
+		DAC960 (see major number 48) except that the limit on
+		partitions is 15.
+
+
  79 char	PAM Software's multimodem boards - alternate devices
 		  0 = /dev/cum0		Callout device for ttyM0
 		  1 = /dev/cum1		Callout device for ttyM1
 		    ...
 
+    block	Compaq Intelligent Drive Array, eigth controller
+		  0 = /dev/ida/c7d0	First logical drive whole disk
+		 16 = /dev/ida/c7d1	Second logical drive whole disk
+		    ...
+		240 = /dev/ida/c715	16th logical drive whole disk
+
+		Partitions are handled the same way as for Mylex
+		DAC960 (see major number 48) except that the limit on
+		partitions is 15.
+
+
  80 char	Photometrics AT200 CCD camera
 		  0 = /dev/at200	Photometrics AT200 CCD camera
 
@@ -1497,14 +1668,13 @@
 		  1 = /dev/parport1	Second parallel port
 		    ...
 
-100 char	POTS (analogue telephone) A/B port {2.6}
-		  0 = /dev/phone0	First telephone port
-		  1 = /dev/phone1	Second telephone port
-		    ...
+    block	JavaStation flash disk
+		  0 = /dev/jsfd		JavaStation flash disk
 
-		The names have been reallocated to Telephony For
-		Linux, major 159.  All use of major 100 should be
-		considered legacy and deprecated.
+100 char	Telephony for Linux
+		  0 = /dev/phone0	First telephony device
+		  1 = /dev/phone1	Second telephony device
+		    ...
 
 101 char	Motorola DSP 56xxx board
 		  0 = /dev/mdspstat	Status information
@@ -1512,6 +1682,19 @@
 		    ...
 		 16 = /dev/mdsp16	16th DSP board I/O controls
 
+    block	AMI HyperDisk RAID controller
+		  0 = /dev/amiraid/ar0	First array whole disk
+		 16 = /dev/amiraid/ar1	Second array whole disk
+		    ...
+		240 = /dev/amiraid/ar15	16th array whole disk
+
+		For each device, partitions are added as:
+		  0 = /dev/amiraid/ar?	  Whole disk
+		  1 = /dev/amiraid/ar?p1  First partition
+		  2 = /dev/amiraid/ar?p2  Second partition
+		    ...
+		 15 = /dev/amiraid/ar?p15 15th partition
+
 102 char	Philips SAA5249 Teletext signal decoder {2.6}
 		  0 = /dev/tlk0		First Teletext decoder
 		  1 = /dev/tlk1		Second Teletext decoder
@@ -1528,36 +1711,119 @@
 		to the arla announce mailing list by sending a mail to
 		<arla-announce-request@stacken.kth.se>.
 
+    block	Audit device
+		  0 = /dev/audit	Audit device
+
 104 char	Flash BIOS support
 
+    block	Compaq Next Generation Drive Array, first controller
+		  0 = /dev/cciss/c0d0	First logical drive, whole disk
+		 16 = /dev/cciss/c0d1	Second logical drive, whole disk
+		    ...
+		240 = /dev/cciss/c0d15	16th logical drive, whole disk
+
+		Partitions are handled the same way as for Mylex
+		DAC960 (see major number 48) except that the limit on
+		partitions is 15.
+
 105 char	Comtrol VS-1000 serial controller
 		  0 = /dev/ttyV0	First VS-1000 port
 		  1 = /dev/ttyV1	Second VS-1000 port
 		    ...
 
+    block	Compaq Next Generation Drive Array, second controller
+		  0 = /dev/cciss/c1d0	First logical drive, whole disk
+		 16 = /dev/cciss/c1d1	Second logical drive, whole disk
+		    ...
+		240 = /dev/cciss/c1d15	16th logical drive, whole disk
+
+		Partitions are handled the same way as for Mylex
+		DAC960 (see major number 48) except that the limit on
+		partitions is 15.
+
 106 char	Comtrol VS-1000 serial controller - alternate devices
 		  0 = /dev/cuv0		First VS-1000 port
 		  1 = /dev/cuv1		Second VS-1000 port
 		    ...
 
+    block	Compaq Next Generation Drive Array, third controller
+		  0 = /dev/cciss/c2d0	First logical drive, whole disk
+		 16 = /dev/cciss/c2d1	Second logical drive, whole disk
+		    ...
+		240 = /dev/cciss/c2d15	16th logical drive, whole disk
+
+		Partitions are handled the same way as for Mylex
+		DAC960 (see major number 48) except that the limit on
+		partitions is 15.
+
 107 char	3Dfx Voodoo Graphics device
 		  0 = /dev/3dfx		Primary 3Dfx graphics device
 
+    block	Compaq Next Generation Drive Array, fourth controller
+		  0 = /dev/cciss/c3d0	First logical drive, whole disk
+		 16 = /dev/cciss/c3d1	Second logical drive, whole disk
+		    ...
+		240 = /dev/cciss/c3d15	16th logical drive, whole disk
+
+		Partitions are handled the same way as for Mylex
+		DAC960 (see major number 48) except that the limit on
+		partitions is 15.
+
 108 char	Device independent PPP interface
 		  0 = /dev/ppp		Device independent PPP interface
 
+    block	Compaq Next Generation Drive Array, fifth controller
+		  0 = /dev/cciss/c4d0	First logical drive, whole disk
+		 16 = /dev/cciss/c4d1	Second logical drive, whole disk
+		    ...
+		240 = /dev/cciss/c4d15	16th logical drive, whole disk
+
+		Partitions are handled the same way as for Mylex
+		DAC960 (see major number 48) except that the limit on
+		partitions is 15.
+
 109 char	Reserved for logical volume manager
 
+    block	Compaq Next Generation Drive Array, sixth controller
+		  0 = /dev/cciss/c5d0	First logical drive, whole disk
+		 16 = /dev/cciss/c5d1	Second logical drive, whole disk
+		    ...
+		240 = /dev/cciss/c5d15	16th logical drive, whole disk
+
+		Partitions are handled the same way as for Mylex
+		DAC960 (see major number 48) except that the limit on
+		partitions is 15.
+
 110 char	miroMEDIA Surround board
 		  0 = /dev/srnd0	First miroMEDIA Surround board
 		  1 = /dev/srnd1	Second miroMEDIA Surround board
 		    ...
 
+    block	Compaq Next Generation Drive Array, seventh controller
+		  0 = /dev/cciss/c6d0	First logical drive, whole disk
+		 16 = /dev/cciss/c6d1	Second logical drive, whole disk
+		    ...
+		240 = /dev/cciss/c6d15	16th logical drive, whole disk
+
+		Partitions are handled the same way as for Mylex
+		DAC960 (see major number 48) except that the limit on
+		partitions is 15.
+
 111 char	Philips SAA7146-based audio/video card {2.6}
 		  0 = /dev/av0		First A/V card
 		  1 = /dev/av1		Second A/V card
 		    ...
 
+    block	Compaq Next Generation Drive Array, eigth controller
+		  0 = /dev/cciss/c7d0	First logical drive, whole disk
+		 16 = /dev/cciss/c7d1	Second logical drive, whole disk
+		    ...
+		240 = /dev/cciss/c7d15	16th logical drive, whole disk
+
+		Partitions are handled the same way as for Mylex
+		DAC960 (see major number 48) except that the limit on
+		partitions is 15.
+
 112 char	ISI serial card
 		  0 = /dev/ttyM0	First ISI port
 		  1 = /dev/ttyM1	Second ISI port
@@ -1718,10 +1984,7 @@
 		  1 = /dev/gfax1	GammaLink channel 1
 		    ...
 
-159 char	Telephony for Linux
-		  0 = /dev/phone0	First telephony device
-		  1 = /dev/phone1	Second telephony device
-		    ...
+159		RESERVED
 
 160 char	General Purpose Instrument Bus (GPIB)
 		  0 = /dev/gpib0	First GPIB bus
@@ -1945,7 +2208,244 @@
 		240 = /dev/mvideo/status15	16th device 
 		    ...
 
-195-239		UNALLOCATED
+195 char	Nvidia graphics devices
+		  0 = /dev/nvidia0		First Nvidia card
+		  1 = /dev/nvidia1		Second Nvidia card
+		    ...
+		255 = /dev/nvidiactl		Nvidia card control device
+
+196-197		UNASSIGNED
+
+198 char	Total Impact TPMP2 quad coprocessor PCI card
+		  0 = /dev/tpmp2/0		First card
+		  1 = /dev/tpmp2/1		Second card
+		    ...
+
+199 char	Veritas volume manager (VxVM) volumes
+		  0 = /dev/vx/rdsk/*/*		First volume
+		  1 = /dev/vx/rdsk/*/*		Second volume
+		    ...
+    block	Veritas volume manager (VxVM) volumes
+		  0 = /dev/vx/dsk/*/*		First volume
+		  1 = /dev/vx/dsk/*/*		First volume
+		    ...
+
+		The namespace in these directories is maintained by
+		the user space VxVM software.
+
+200 char	Veritas VxVM configuration interface
+                  0 = /dev/vx/config		Configuration access node
+                  1 = /dev/vx/trace		Volume i/o trace access node
+                  2 = /dev/vx/iod		Volume i/o daemon access node
+                  3 = /dev/vx/info		Volume information access node
+                  4 = /dev/vx/task		Volume tasks access node
+                  5 = /dev/vx/taskmon		Volume tasks monitor daemon
+
+201 char	Veritas VxVM dynamic multipathing driver
+		  0 = /dev/vx/rdmp/*		First multipath device
+		  1 = /dev/vx/rdmp/*		Second multipath device
+		    ...
+    block	Veritas VxVM dynamic multipathing driver
+		  0 = /dev/vx/dmp/*		First multipath device
+		  1 = /dev/vx/dmp/*		Second multipath device
+		    ...
+
+		The namespace in these directories is maintained by
+		the user space VxVM software.
+
+202 char	CPU model-specific registers
+		  0 = /dev/cpu/0/msr		MSRs on CPU 0
+		  1 = /dev/cpu/1/msr		MSRs on CPU 1
+		    ...
+
+203 char	CPU CPUID information
+		  0 = /dev/cpu/0/cpuid		CPUID on CPU 0
+		  1 = /dev/cpu/1/cpuid		CPUID on CPU 1
+		    ...
+
+204 char	Low-density serial ports
+		  0 = /dev/ttyLU0		LinkUp Systems L72xx UART - port 0
+		  1 = /dev/ttyLU1		LinkUp Systems L72xx UART - port 1
+		  2 = /dev/ttyLU2		LinkUp Systems L72xx UART - port 2
+		  3 = /dev/ttyLU3		LinkUp Systems L72xx UART - port 3
+		  4 = /dev/ttyFB0		Intel Footbridge (ARM)
+		  5 = /dev/ttySA0		StrongARM builtin serial port 0
+		  6 = /dev/ttySA1		StrongARM builtin serial port 1
+		  7 = /dev/ttySA2		StrongARM builtin serial port 2
+		  8 = /dev/ttySC0		SCI serial port (SuperH) - port 0
+		  9 = /dev/ttySC1		SCI serial port (SuperH) - port 1
+		 10 = /dev/ttySC2		SCI serial port (SuperH) - port 2
+		 11 = /dev/ttySC3		SCI serial port (SuperH) - port 3
+		 12 = /dev/ttyFW0		Firmware console - port 0
+		 13 = /dev/ttyFW1		Firmware console - port 1
+		 14 = /dev/ttyFW2		Firmware console - port 2
+		 15 = /dev/ttyFW3		Firmware console - port 3
+		 16 = /dev/ttyAM0		ARM "AMBA" serial port 0
+		    ...
+		 31 = /dev/ttyAM15		ARM "AMBA" serial port 15
+
+205 char	Low-density serial ports (alternate device)
+		  0 = /dev/culu0		Callout device for ttyLU0
+		  1 = /dev/culu1		Callout device for ttyLU1
+		  2 = /dev/culu2		Callout device for ttyLU2
+		  3 = /dev/culu3		Callout device for ttyLU3
+		  4 = /dev/cufb0		Callout device for ttyFB0
+		  5 = /dev/cusa0		Callout device for ttySA0
+		  6 = /dev/cusa1		Callout device for ttySA1
+		  7 = /dev/cusa2		Callout device for ttySA2
+		  8 = /dev/cusc0		Callout device for ttySC0
+		  9 = /dev/cusc1		Callout device for ttySC1
+		 10 = /dev/cusc2		Callout device for ttySC2
+		 11 = /dev/cusc3		Callout device for ttySC3
+		 12 = /dev/cufw0		Callout device for ttyFW0
+		 13 = /dev/cufw1		Callout device for ttyFW1
+		 14 = /dev/cufw2		Callout device for ttyFW2
+		 15 = /dev/cufw3		Callout device for ttyFW3
+		 16 = /dev/cuam0		Callout device for ttyAM0
+		    ...
+		 31 = /dev/cuam15		Callout device for ttyAM15
+
+206 char	OnStream SC-x0 tape devices
+		  0 = /dev/osst0		First OnStream SCSI tape, mode 0
+		  1 = /dev/osst1		Second OnStream SCSI tape, mode 0
+		    ...
+		 32 = /dev/osst0l		First OnStream SCSI tape, mode 1
+		 33 = /dev/osst1l		Second OnStream SCSI tape, mode 1
+		    ...
+		 64 = /dev/osst0m		First OnStream SCSI tape, mode 2
+		 65 = /dev/osst1m		Second OnStream SCSI tape, mode 2
+		    ...
+		 96 = /dev/osst0a		First OnStream SCSI tape, mode 3
+		 97 = /dev/osst1a		Second OnStream SCSI tape, mode 3
+		    ...
+		128 = /dev/nosst0		No rewind version of /dev/osst0
+		129 = /dev/nosst1		No rewind version of /dev/osst1
+		    ...
+		160 = /dev/nosst0l		No rewind version of /dev/osst0l
+		161 = /dev/nosst1l		No rewind version of /dev/osst1l
+		    ...
+		192 = /dev/nosst0m		No rewind version of /dev/osst0m
+		193 = /dev/nosst1m		No rewind version of /dev/osst1m
+		    ...
+		224 = /dev/nosst0a		No rewind version of /dev/osst0a
+		225 = /dev/nosst1a		No rewind version of /dev/osst1a
+		    ...
+
+		The OnStream SC-x0 SCSI tapes do not support the
+		standard SCSI SASD command set and therefore need
+		their own driver "osst". Note that the IDE, USB (and
+		maybe ParPort) versions may be driven via ide-scsi or
+		usb-storage SCSI emulation and this osst device and
+		driver as well.  The ADR-x0 drives are QIC-157
+		compliant and don't need osst.
+
+207 char	Compaq ProLiant health feature indicate
+		  0 = /dev/cpqhealth/cpqw	Redirector interface
+		  1 = /dev/cpqhealth/crom	EISA CROM
+		  2 = /dev/cpqhealth/cdt	Data Table
+		  3 = /dev/cpqhealth/cevt	Event Log
+		  4 = /dev/cpqhealth/casr	Automatic Server Recovery
+		  5 = /dev/cpqhealth/cecc	ECC Memory
+		  6 = /dev/cpqhealth/cmca	Machine Check Architecture
+		  7 = /dev/cpqhealth/ccsm	Deprecated CDT
+		  8 = /dev/cpqhealth/cnmi	NMI Handling
+		  9 = /dev/cpqhealth/css	Sideshow Management
+		 10 = /dev/cpqhealth/cram	CMOS interface
+		 11 = /dev/cpqhealth/cpci	PCI IRQ interface
+
+208 char	User space serial ports
+		  0 = /dev/ttyU0		First user space serial port
+		  1 = /dev/ttyU1		Second user space serial port
+		    ...
+
+209 char	User space serial ports (alternate devices)
+		  0 = /dev/cuu0			Callout device for ttyU0
+		  1 = /dev/cuu1			Callout device for ttyU1
+		    ...
+
+210 char	SBE, Inc. sync/async serial card
+		  0 = /dev/sbei/wxcfg0		Configuration device for board 0
+		  1 = /dev/sbei/dld0		Download device for board 0
+		  2 = /dev/sbei/wan00		WAN device, port 0, board 0
+		  3 = /dev/sbei/wan01		WAN device, port 1, board 0
+		  4 = /dev/sbei/wan02		WAN device, port 2, board 0
+		  5 = /dev/sbei/wan03		WAN device, port 3, board 0
+		  6 = /dev/sbei/wanc00		WAN clone device, port 0, board 0
+		  7 = /dev/sbei/wanc01		WAN clone device, port 1, board 0
+		  8 = /dev/sbei/wanc02		WAN clone device, port 2, board 0
+		  9 = /dev/sbei/wanc03		WAN clone device, port 3, board 0
+		 10 = /dev/sbei/wxcfg1		Configuration device for board 1
+		 11 = /dev/sbei/dld1		Download device for board 1
+		 12 = /dev/sbei/wan10		WAN device, port 0, board 1
+		 13 = /dev/sbei/wan11		WAN device, port 1, board 1
+		 14 = /dev/sbei/wan12		WAN device, port 2, board 1
+		 15 = /dev/sbei/wan13		WAN device, port 3, board 1
+		 16 = /dev/sbei/wanc10		WAN clone device, port 0, board 1
+		 17 = /dev/sbei/wanc11		WAN clone device, port 1, board 1
+		 18 = /dev/sbei/wanc12		WAN clone device, port 2, board 1
+		 19 = /dev/sbei/wanc13		WAN clone device, port 3, board 1
+		    ...
+
+		Yes, each board is really spaced 10 (decimal) apart.
+
+211 char	Addinum CPCI1500 digital I/O card
+		  0 = /dev/addinum/cpci1500/0	First CPCI1500 card
+		  1 = /dev/addinum/cpci1500/1	Second CPCI1500 card
+		    ...
+
+216 char	USB BlueTooth devices
+		  0 = /dev/ttyUB0		First USB BlueTooth device
+		  1 = /dev/ttyUB1		Second USB BlueTooth device
+		    ...
+
+217 char	USB BlueTooth devices (alternate devices)
+		  0 = /dev/cuub0		Callout device for ttyUB0
+		  1 = /dev/cuub1		Callout device for ttyUB1
+		    ...
+
+218 char	The Logical Company bus Unibus/Qbus adapters
+		  0 = /dev/logicalco/bci/0	First bus adapter
+		  1 = /dev/logicalco/bci/1	First bus adapter
+		    ...
+
+219 char	The Logical Company DCI-1300 digital I/O card
+		  0 = /dev/logicalco/dci1300/0	First DCI-1300 card
+		  1 = /dev/logicalco/dci1300/1	Second DCI-1300 card
+		    ...
+
+220 char	Myricom Myrinet "GM" board
+		  0 = /dev/myricom/gm0		First Myrinet GM board
+		  1 = /dev/myricom/gmp0		First board "root access"
+		  2 = /dev/myricom/gm1		Second Myrinet GM board
+		  3 = /dev/myricom/gmp1		Second board "root access"
+		    ...
+
+221 char	VME bus
+		  0 = /dev/bus/vme/m0		First master image
+		  1 = /dev/bus/vme/m1		Second master image
+		  2 = /dev/bus/vme/m2		Third master image
+		  3 = /dev/bus/vme/m3		Fourth master image
+		  4 = /dev/bus/vme/s0		First slave image
+		  5 = /dev/bus/vme/s1		Second slave image
+		  6 = /dev/bus/vme/s2		Third slave image
+		  7 = /dev/bus/vme/s3		Fourth slave image
+		  8 = /dev/bus/vme/ctl		Control
+
+		It is expected that all VME bus drivers will use the
+		same interface.  For interface documentation see
+		http://www.vmelinux.org/.
+
+224 char	A2232 serial card
+		  0 = /dev/ttyY0		First A2232 port
+		  1 = /dev/cuy0			Second A2232 port
+		    ...
+
+225 char	A2232 serial card (alternate devices)
+		  0 = /dev/cuy0			Callout device for ttyY0
+		  1 = /dev/cuy1			Callout device for ttyY1
+		    ...
+
+226-239		UNASSIGNED
 
 240-254		LOCAL/EXPERIMENTAL USE
 
@@ -2026,6 +2526,14 @@
 /dev/log	socket		syslog local socket
 /dev/gpmdata	socket		gpm mouse multiplexer
 
+	Mount points
+
+The following names are reserved for mounting special filesystems
+under /dev.  These special filesystems provide kernel interfaces that
+cannot be provided with standard device nodes.
+
+/dev/pts	devpts		PTY slave filesystem
+/dev/shm	shmfs		POSIX shared memory maintenance access
 
  ****	TERMINAL DEVICES
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/filesystems/minix-part.txt linux.19p18/Documentation/filesystems/minix-part.txt
--- linux.vanilla/Documentation/filesystems/minix-part.txt	Thu Jan  1 01:00:00 1970
+++ linux.19p18/Documentation/filesystems/minix-part.txt	Wed Dec 13 22:43:46 2000
@@ -0,0 +1,43 @@
+Minix 2.0.0/2.0.2 subpartition support.
+=======================================
+
+  Minix subpartition support is provided in `linux/drivers/block/genhd.c'.
+Minix partitions are shown with the device name suffixed with an `@'
+followed by any detected subpartitions inside angle brackets, like this:
+
+Partition check:
+ hda: hda1 hda2@ < hda5 hda6 > hda3 hda4
+
+Usage
+=====
+
+Add entries to /etc/fstab, change for your setup:
+ /dev/hda5	/mnt/minix	minix	rw,noauto	0	0
+ /dev/hda6	/mnt/minix/usr	minix	rw,noauto	0	0
+
+To mount your Minix filesystems:
+ mount /mnt/minix		# mount /
+ mount /mnt/minix/usr		# mount /usr
+
+
+Note
+====
+
+The first sector of a Minix 2.0.0/2.0.2 partition containing 
+subpartitions looks like the master boot record (MBR) on the first 
+sector of the hard disk. 
+
+It has
+ 1) a small loader program which loads the boot sector from
+          the Minix root partition (usually hd?a).
+ 2) a small partition table which gives the starting 
+	  C/H/S values and sizes for the 4 Minix subpartitions.
+
+If there are no subpartitions then the first sector of the Minix
+partition contains the usual boot sector.
+
+Bug Reports
+===========
+
+Anand Krishnamurthy <anandk@wiproge.med.ge.com>
+Rajeev V. Pillai    <rajeevvp@yahoo.com> 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/ioctl-number.txt linux.19p18/Documentation/ioctl-number.txt
--- linux.vanilla/Documentation/ioctl-number.txt	Mon Dec 11 22:12:32 2000
+++ linux.19p18/Documentation/ioctl-number.txt	Tue Feb 20 13:26:25 2001
@@ -66,6 +66,7 @@
 0x22	all	scsi/sg.h
 'A'	all	linux/apm_bios.h
 'C'	all	linux/soundcard.h
+'D'	all	asm-s390/dasd.h
 'F'	all	linux/fb.h
 'I'	all	linux/isdn.h
 'K'	all	linux/kd.h
@@ -113,6 +114,8 @@
 					<mailto:hdstich@connectu.ulm.circular.de>
 'z'	40-7F	CAN bas card		in development:
 					<mailto:oe@port.de>
+'6'	00-10	<asm-i386/processor.h>	Intel IA32 microcode update driver
+					<mailto:tigran@veritas.com>
 0x89	00-0F	asm-i386/sockios.h
 0x89	10-DF	linux/sockios.h
 0x89	E0-EF	linux/sockios.h		SIOCPROTOPRIVATE range
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/isdn/00-INDEX linux.19p18/Documentation/isdn/00-INDEX
--- linux.vanilla/Documentation/isdn/00-INDEX	Mon Dec 11 22:12:32 2000
+++ linux.19p18/Documentation/isdn/00-INDEX	Mon Feb 19 18:28:19 2001
@@ -38,3 +38,6 @@
 	- info on driver for Spellcaster cards.
 README.x25
     _ info for running X.25 over ISDN.
+README.hysdn
+        - info on driver for Hypercope active HYSDN cards
+ 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/isdn/README.HiSax linux.19p18/Documentation/isdn/README.HiSax
--- linux.vanilla/Documentation/isdn/README.HiSax	Mon Dec 11 22:12:32 2000
+++ linux.19p18/Documentation/isdn/README.HiSax	Sat Dec 30 19:33:51 2000
@@ -53,7 +53,8 @@
 Sedlbauer ISDN-Controller PC/104
 USR Sportster internal TA (compatible Stollmann tina-pp V3)
 ith Kommunikationstechnik GmbH MIC 16 ISA card
-Traverse Technologie NETjet PCI S0 card
+Traverse Technologie NETjet PCI S0 card and NETspider U card
+Ovislink ISDN sc100-p card (NETjet driver)
 Dr. Neuhaus Niccy PnP/PCI
 Siemens I-Surf 1.0
 Siemens I-Surf 2.0 (with IPAC, try type 12 asuscom) 
@@ -134,7 +135,12 @@
 
 The parameter for the D-Channel protocol may be omitted if you selected the
 correct one during kernel config. Valid values are "1" for German 1TR6,
-"2" for EDSS1 (Euro ISDN) and "3" for leased lines (no D-Channel).
+"2" for EDSS1 (Euro ISDN), "3" for leased lines (no D-Channel) and "4"
+for US NI1.
+With US NI1 you have to include your SPID into the MSN setting in the form
+<MSN>:<SPID> for example (your phonenumber is 1234 your SPID 5678):
+AT&E1234:5678                       on ttyI interfaces
+isdnctrl eaz ippp0 1234:5678        on network devices
 
 The Creatix/Teles PnP cards use io1= and io2= instead of io= for specifying
 the I/O addresses of the ISAC and HSCX chips, respectively.
@@ -186,8 +192,9 @@
    34	Gazel ISDN cards (PCI)   none
    35	HFC 2BDS0 PCI            none
    36	W6692 based PCI cards    none
-   37   HFC 2BDS0 S+, SP/PCMCIA  irq,io (pcmcia must be set with cardmgr)
-
+   37	HFC 2BDS0 S+, SP         irq,io 
+   38	NETspider U PCI card     none
+   39	HFC 2BDS0 SP/PCMCIA      irq,io (set with cardmgr)
 
 At the moment IRQ sharing is only possible with PCI cards. Please make sure
 that your IRQ is free and enabled for ISA use.
@@ -291,7 +298,9 @@
    34	Gazel ISDN cards (PCI)  no parameter
    35	HFC 2BDS0 PCI           no parameter
    36	W6692 based PCI cards   none
-   37   HFC 2BDS0 S+,SP/PCMCIA  pa=irq, pb=io
+   37	HFC 2BDS0 S+,SP/PCMCIA  ONLY WORKS AS A MODULE !
+   38	NETspider U PCI card    none
+
 
 Running the driver
 ------------------
@@ -433,6 +442,7 @@
 	Enrik Berkhan (enrik@starfleet.inka.de) for S0BOX specific stuff
 	Ton van Rosmalen for Teles PCI
 	Petr Novak <petr.novak@i.cz> for Winbond W6692 support
+	Werner Cornelius <werner@isdn4linux.de> for HFC-PCI, HFC-S(+/P) and supplementary services support
         and more people who are hunting bugs. (If I forgot somebody, please
 	send me a mail).
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/isdn/README.diversion linux.19p18/Documentation/isdn/README.diversion
--- linux.vanilla/Documentation/isdn/README.diversion	Mon Dec 11 22:12:32 2000
+++ linux.19p18/Documentation/isdn/README.diversion	Tue Feb 13 18:50:48 2001
@@ -6,7 +6,7 @@
 the HiSax driver.
 The diversion kernel interface and controlling tool divertctrl were written
 by Werner Cornelius (werner@isdn4linux.de or werner@titro.de) under the
-GNU Public License.
+GNU General Public License.
 
     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
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/isdn/README.eicon linux.19p18/Documentation/isdn/README.eicon
--- linux.vanilla/Documentation/isdn/README.eicon	Fri Apr 21 12:45:49 2000
+++ linux.19p18/Documentation/isdn/README.eicon	Sat Mar 10 23:05:47 2001
@@ -1,4 +1,4 @@
-$Id: README.eicon,v 1.6 2000/01/27 09:54:44 armin Exp $
+$Id: README.eicon,v 1.10 2000/08/13 12:19:15 armin Exp $
 
 (c) 1999,2000 Armin Schindler (mac@melware.de)
 (c) 1999,2000 Cytronics & Melware (info@melware.de)
@@ -40,6 +40,7 @@
 ------------------
 - DIVA Server BRI/PCI 2M
 - DIVA Server PRI/PCI 2M (9M 23M 30M)
+- DIVA Server 4BRI/PCI
 	supported functions of onboard DSPs:
 	- analog modem
 	- fax group 2/3 (Fax Class 2 commands)
@@ -78,6 +79,10 @@
 
 	eiconctrl [-d DriverId] load etsi
 
+Example for a BRI card with E-DSS1 Protocol with PtP configuration.
+
+	eiconctrl [-d DriverId] load etsi -n -t1 -s1
+
 
 Example for loading and starting a PRI card with E-DSS1 Protocol.
 
@@ -95,6 +100,7 @@
 the necessary D-Channel traces for isdnlog.
 
 
+
 Thanks to 
 	Deutsche Mailbox Saar-Lor-Lux GmbH
 	for sponsoring and testing fax
@@ -109,3 +115,4 @@
 Armin Schindler
 mac@melware.de
 http://www.melware.de
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/isdn/README.fax linux.19p18/Documentation/isdn/README.fax
--- linux.vanilla/Documentation/isdn/README.fax	Fri Apr 21 12:45:49 2000
+++ linux.19p18/Documentation/isdn/README.fax	Mon Feb 19 18:28:19 2001
@@ -24,6 +24,9 @@
 Eicon DIVA Server BRI/PCI
 	- full support with both B-channels.
 
+Eicon DIVA Server 4BRI/PCI
+	- full support with all B-channels.
+
 Eicon DIVA Server PRI/PCI
 	- full support on amount of B-channels
 		depending on DSPs on board.
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/isdn/README.hfc-pci linux.19p18/Documentation/isdn/README.hfc-pci
--- linux.vanilla/Documentation/isdn/README.hfc-pci	Fri Apr 21 12:45:49 2000
+++ linux.19p18/Documentation/isdn/README.hfc-pci	Sat Dec 30 19:33:51 2000
@@ -35,7 +35,7 @@
 supplied else the parameter is assumed 0 and a auto search for a free card is
 invoked which may not give the wanted result. 
 
-Comments and reports to werner@isdn4linux.de or werner@titro.de .
+Comments and reports to werner@isdn4linux.de or werner@isdn-development.de
 
 
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/isdn/README.hysdn linux.19p18/Documentation/isdn/README.hysdn
--- linux.vanilla/Documentation/isdn/README.hysdn	Thu Jan  1 01:00:00 1970
+++ linux.19p18/Documentation/isdn/README.hysdn	Tue Feb 13 18:49:43 2001
@@ -0,0 +1,195 @@
+$Id: README.hysdn,v 1.3.6.1 2001/02/10 14:41:19 kai Exp $
+The hysdn driver has been written by
+by Werner Cornelius (werner@isdn4linux.de or werner@titro.de) 
+for Hypercope GmbH Aachen Germany. Hypercope agreed to publish this driver
+under the GNU General Public License.
+
+The CAPI 2.0-support was added by Ulrich Albrecht (ualbrecht@hypercope.de)
+for Hypercope GmbH Aachen, Germany.
+
+
+    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.
+
+Table of contents
+=================
+
+1. About the driver
+
+2. Loading/Unloading the driver
+
+3. Entries in the /proc filesystem
+
+4. The /proc/net/hysdn/cardconfX file
+
+5. The /proc/net/hysdn/cardlogX file
+
+6. Where to get additional info and help
+
+
+1. About the driver
+
+   The drivers/isdn/hysdn subdir contains a driver for HYPERCOPEs active 
+   PCI isdn cards Champ, Ergo and Metro. To enable support for this cards
+   enable ISDN support in the kernel config and support for HYSDN cards in
+   the active cards submenu. The driver may only be compiled and used if 
+   support for loadable modules and the process filesystem have been enabled.
+
+   These cards provide two different interfaces to the kernel. Without the
+   optional CAPI 2.0 support, they register as ethernet card. IP-routing
+   to a ISDN-destination is performed on the card itself. All necessary
+   handlers for various protocols like ppp and others as well as config info
+   and firmware may be fetched from Hypercopes WWW-Site www.hypercope.de.
+
+   With CAPI 2.0 support enabled, the card can also be used as a CAPI 2.0 
+   compliant devices with either CAPI 2.0 applications 
+   (check isdn4k-utils) or -using the capidrv module- as a regular
+   isdn4linux device. This is done via the same mechanism as with the 
+   active AVM cards and in fact uses the same module.
+   
+
+2. Loading/Unloading the driver
+
+   The module has no command line parameters and auto detects up to 10 cards
+   in the id-range 0-9.
+   If a loaded driver shall be unloaded all open files in the /proc/net/hysdn
+   subdir need to be closed and all ethernet interfaces allocated by this 
+   driver must be shut down. Otherwise the module counter will avoid a module
+   unload.
+   
+   If you are using the CAPI 2.0-interface, make sure to load/modprobe the
+   kernelcapi-module first.
+
+   If you plan to use the capidrv-link to isdn4linux, make sure to load
+   capidrv.o after all modules using this driver (i.e. after hysdn and
+   any avm-specific modules).
+
+3. Entries in the /proc filesystem
+
+   When the module has been loaded it adds the directory hysdn in the 
+   /proc/net tree. This directory contains exactly 2 file entries for each 
+   card. One is called cardconfX and the other cardlogX, where X is the
+   card id number from 0 to 9. 
+   The cards are numbered in the order found in the PCI config data.
+
+4. The /proc/net/hysdn/cardconfX file
+
+   This file may be read to get by everyone to get info about the cards type, 
+   actual state, available features and used resources.
+   The first 3 entries (id, bus and slot) are PCI info fields, the following
+   type field gives the information about the cards type:
+
+   4 -> Ergo card (server card with 2 b-chans)
+   5 -> Metro card (server card with 4 or 8 b-chans)
+   6 -> Champ card (client card with 2 b-chans)   
+
+   The following 3 fields show the hardware assignments for irq, iobase and the
+   dual ported memory (dp-mem).
+   The fields b-chans and fax-chans announce the available card resources of
+   this types for the user.
+   The state variable indicates the actual drivers state for this card with the
+   following assignments.
+
+   0 -> card has not been booted since driver load
+   1 -> card booting is actually in progess
+   2 -> card is in an error state due to a previous boot failure
+   3 -> card is booted and active
+
+   And the last field (device) shows the name of the ethernet device assigned
+   to this card. Up to the first successful boot this field only shows a -
+   to tell that no net device has been allocated up to now. Once a net device
+   has been allocated it remains assigned to this card, even if a card is
+   rebooted and an boot error occurs. 
+
+   Writing to the cardconfX file boots the card or transfers config lines to 
+   the cards firmware. The type of data is automatically detected when the 
+   first data is written. Only root has write access to this file.
+   The firmware boot files are normally called hyclient.pof for client cards
+   and hyserver.pof for server cards.
+   After successfully writing the boot file, complete config files or single
+   config lines may be copied to this file.
+   If an error occurs the return value given to the writing process has the 
+   following additional codes (decimal):
+
+   1000 Another process is currently bootng the card
+   1001 Invalid firmware header
+   1002 Boards dual-port RAM test failed
+   1003 Internal firmware handler error
+   1004 Boot image size invalid
+   1005 First boot stage (bootstrap loader) failed
+   1006 Second boot stage failure
+   1007 Timeout waiting for card ready during boot
+   1008 Operation only allowed in booted state
+   1009 Config line to long 
+   1010 Invalid channel number 
+   1011 Timeout sending config data
+
+   Additional info about error reasons may be fetched from the log output. 
+
+5. The /proc/net/hysdn/cardlogX file
+   	  
+   The cardlogX file entry may be opened multiple for reading by everyone to 
+   get the cards and drivers log data. Card messages always start with the
+   keyword LOG. All other lines are output from the driver. 
+   The driver log data may be redirected to the syslog by selecting the 
+   appropriate bitmask. The cards log messages will always be send to this
+   interface but never to the syslog.
+
+   A root user may write a decimal or hex (with 0x) value t this file to select
+   desired output options. As mentioned above the cards log dat is always 
+   written to the cardlog file independent of the following options only used
+   to check and debug the driver itself:
+
+   For example: 
+   echo "0x34560078" > /proc/net/hysdn/cardlog0
+   to output the hex log mask 34560078 for card 0.
+ 
+   The written value is regarded as an unsigned 32-Bit value, bit ored for 
+   desired output. The following bits are already assigned:
+
+   0x80000000   All driver log data is alternatively via syslog 
+   0x00000001   Log memory allocation errors
+   0x00000010   Firmware load start and close are logged
+   0x00000020   Log firmware record parser
+   0x00000040   Log every firmware write actions
+   0x00000080   Log all card related boot messages
+   0x00000100   Output all config data sent for debugging purposes
+   0x00000200   Only non comment config lines are shown wth channel
+   0x00000400   Additional conf log output
+   0x00001000   Log the asynchronous scheduler actions (config and log)
+   0x00100000   Log all open and close actions to /proc/net/hysdn/card files
+   0x00200000   Log all actions from /proc file entries
+   0x00010000   Log network interface init and deinit
+   
+6. Where to get additional info and help
+
+   If you have any problems concerning the driver or configuration contact 
+   the Hypercope support team (support@hypercope.de) and or the authors
+   Werner Cornelius (werner@isdn4linux or cornelius@titro.de) or
+   Ulrich Albrecht (ualbrecht@hypercope.de).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/networking/cs89x0.txt linux.19p18/Documentation/networking/cs89x0.txt
--- linux.vanilla/Documentation/networking/cs89x0.txt	Fri Apr 21 12:45:49 2000
+++ linux.19p18/Documentation/networking/cs89x0.txt	Wed Feb  7 09:41:34 2001
@@ -205,9 +205,8 @@
 * mmode=#####         - specify memory base address
 * dma=#               - specify DMA channel
 * media=rj45          - specify media type
-   or media=2
+   or media=bnc
    or media=aui
-   or medai=auto
 * duplex=f            - specify forced half/full/autonegotiate duplex
    or duplex=h
    or duplex=auto
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/networking/ip_masq/rc.masqfw linux.19p18/Documentation/networking/ip_masq/rc.masqfw
--- linux.vanilla/Documentation/networking/ip_masq/rc.masqfw	Thu Jan  1 01:00:00 1970
+++ linux.19p18/Documentation/networking/ip_masq/rc.masqfw	Wed Dec 13 22:22:39 2000
@@ -0,0 +1,106 @@
+#!/bin/sh
+#
+#	rc.masqfw	v0.2
+#
+#	Author: Juanjo Ciarlante <jjo@mendoza.gov.ar>
+#	03-Oct-00	
+#
+# 	Setup reverse masquerading (ala portfw) with using firewall mark-ing
+#	_AND_ userspace "redir" support for complete redirection (even local
+#	connects).
+#
+# Semantics:
+#	Let ip_masq_mfw intercept truly "forward-able" packets based
+#	on ipchains ruling _AND_ leave the rest for redir tool.
+#
+# Requirement:
+#	- ipmasqadm	http://juanjox.kernelnotes.org/
+#			. setups kernel mark forwarding)
+#	- redir 2.2.x	http://freshmeat.net/search/?q=redir
+#			. setups "local" socket forwarding)
+#	- ip_masq_ftp	PATCHED for firewall marking (module parm "in_mark")
+#			. support internal server forwarding for PASV clients)
+#
+# Setup:
+# EXT_IP, EXT_PORT:	external (visible) IP address (can be '0') and port. 
+# INT_IP, INT_PORT:	internal server address and port
+# IN_MARK:		arbitrary value to use when marking pkts (ipchains -m)
+# FTP:			if not-null activate ftp support
+# REDIR:		path to redir-2.2.x (set to "" to avoid using)
+
+export PATH="/sbin:/usr/sbin:$PATH"
+
+EXT_IP=192.168.2.16
+EXT_PORT=2021
+INT_IP=10.1.1.128
+INT_PORT=21
+IN_MARK=4321
+FTP=1
+REDIR="/usr/sbin/redir"
+
+FW_IPCHAINS="-i eth0 -d $EXT_IP $EXT_PORT -p tcp"
+PID_FILE="/var/run/redir-$EXT_IP-$EXT_PORT"
+
+# seems ascii art... but it runs!!  =)
+#
+run() {
+	$* || {
+		echo "->	'$*'"
+		return 1
+	}
+}
+
+get_pid() {
+	test -f $PID_FILE || return 1
+	typeset pid=`cat $PID_FILE`
+	test -n "$pid" || return 1
+	kill -0 $pid || return 1
+	echo $pid
+}
+exit_err() {
+	ERR=$1;shift
+	echo $@ >&2
+	exit $ERR
+}	
+redir_on() {
+	test -n "$REDIR"  || return 1
+	test -n "$FTP" && REDIR="$REDIR --ftp=both"
+	$SHELL -c 'echo $$ > '"$PID_FILE
+		exec $REDIR \
+		--laddr $EXT_IP --lport $EXT_PORT \
+		--caddr $INT_IP --cport $INT_PORT 
+	" &
+
+}
+redir_off() {
+	test -n "$REDIR"  || return 1
+	if pid=`get_pid`;then
+		kill $pid 
+		rm $PID_FILE
+	fi
+	fuser -k -n tcp $EXT_PORT
+}
+
+case "$1" in
+start)
+	#run modprobe ip_masq_mfw
+	run ipmasqadm mfw -I -m $IN_MARK -r $INT_IP $INT_PORT
+	if test -n "$FTP";then
+		run modprobe ip_masq_ftp in_mark=$IN_MARK || \
+			exit_err 1 "Incorrect ftp module version ?"
+	fi
+	run ipchains -m $IN_MARK -I input $FW_IPCHAINS
+	redir_on
+	;;
+stop)
+	run ipchains -m $IN_MARK -D input $FW_IPCHAINS
+	if test -n "$FTP";then
+		run rmmod ip_masq_ftp
+	fi
+	run ipmasqadm mfw -D -m $IN_MARK -r $INT_IP $INT_PORT
+	#run ipmasqadm mfw -F
+	#run rmmod ip_masq_mfw
+	redir_off
+	;;
+
+esac
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/networking/vortex.txt linux.19p18/Documentation/networking/vortex.txt
--- linux.vanilla/Documentation/networking/vortex.txt	Fri Apr 21 12:45:49 2000
+++ linux.19p18/Documentation/networking/vortex.txt	Mon Feb 19 18:23:03 2001
@@ -1,35 +1,348 @@
+Documentation/networking/vortex.txt
+Andrew Morton <andrewm@uow.edu.au>
+18 Feb 2001
+
+
 This document describes the usage and errata of the 3Com "Vortex" device
-driver for Linux.
+driver for Linux, 3c59x.c.
+
+The driver was written by Donald Becker <becker@scyld.com>
+
+Don is no longer the prime maintainer of this version of the driver. 
+Please report problems to one or more of:
+
+  Andrew Morton <andrewm@uow.edu.au>
+  Netdev mailing list <netdev@oss.sgi.com>
+  Linux kernel mailing list <linux-kernel@vger.kernel.org>
+
+Please note the 'Reporting and Diagnosing Problems' section at the end
+of this file.
 
 This driver supports the following hardware:
-	3c590, 3c592, 3c595, 3c597
 
-When loaded as a module the following variables may be set:
- name	 type	description
- debug	 int	The debug message level, 0 (no messages) to 6 (wordy).
- options int[]	The media type override and card operation settings
-		(See list below.)
-
-An example of loading the vortex module is
-	insmod 3c59x.o debug=1 options=0,,12
-This sets the debug message level to minimal messages, sets the first card to
-the 10baseT transceiver, the second to the EEPROM-set transceiver, and the
-third card to operate in full-duplex mode using its 100baseTx transceiver.
-(Note: card ordering is set by the PCI BIOS.)
+	3c590 Vortex 10Mbps
+	3c592 EISA 10mbps Demon/Vortex
+	3c597 EISA Fast Demon/Vortex
+	3c595 Vortex 100baseTx
+	3c595 Vortex 100baseT4
+	3c595 Vortex 100base-MII
+	3Com Vortex
+	3c900 Boomerang 10baseT
+	3c900 Boomerang 10Mbps Combo
+	3c900 Cyclone 10Mbps Combo
+	3c900B-FL Cyclone 10base-FL
+	3c900 Cyclone 10Mbps TPO
+	3c900 Cyclone 10Mbps TPC
+	3c905 Boomerang 100baseTx
+	3c905 Boomerang 100baseT4
+	3c905B Cyclone 100baseTx
+	3c905B Cyclone 10/100/BNC
+	3c905B-FX Cyclone 100baseFx
+	3c905C Tornado
+	3c980 Cyclone
+	3cSOHO100-TX Hurricane
+	3c555 Laptop Hurricane
+	3c556 10/100 Mini PCI Adapter
+	3c556B Laptop Hurricane
+	3c575 Boomerang CardBus
+	3CCFE575 Cyclone CardBus
+	3CCFE656 Cyclone CardBus
+	3CCFEM656 Cyclone CardBus
+	3c575 series CardBus (unknown version)
+	3c450 HomePNA Tornado
+	3Com Boomerang (unknown version)
+
+Module parameters
+=================
+
+There are several parameters which may be provided to the driver when
+its module is loaded.  These are usually placed in /etc/modules.conf
+(used to be conf.modules).  Example:
+
+options 3c59x debug=3 rx_copybreak=300
+
+The supported parameters are:
+
+debug=N
+
+  Where N is a number from 0 to 7.  Anything above 3 produces a lot
+  of output in your system logs.  debug=1 is default.
+
+options=N1,N2,N3,...
 
-Possible media type settings
+  Each number in the list provides an option to the corresponding
+  network card.  So if you have two 3c905's and you wish to provide
+  them with option 0x204 you would use:
+
+    options=0x204,0x204
+
+  The individual options are composed of a number of bitfields which
+  have the following meanings:
+
+  ssible media type settings
 	0	10baseT
 	1	10Mbs AUI
 	2	undefined
 	3	10base2 (BNC)
 	4	100base-TX
 	5	100base-FX
-	6	MII (not yet available)
-	7	<Use default setting>
-	
-	8	Full-duplex bit
-		8 10baseT full-duplex
-		12 100baseTx full-duplex 
-	16	Bus-master enable bit (experimental use only!)
+	6	MII (Media Independent Interface)
+	7	Use default setting from EEPROM
+	8       Autonegotiate
+	9       External MII
+	10      Use default setting from EEPROM
+
+  When generating a value for the 'options' setting, the above media
+  selection values may be OR'ed (or added to) the following:
+
+  512  (0x200)	Force full duplex mode.
+  16   (0x10)	Bus-master enable bit (Old Vortex cards only)
+
+  For example:
+
+    insmod 3c59x options=0x204
+
+  will force full-duplex 100base-TX, rather than allowing the usual
+  autonegotiation.
+
+full_duplex=N1,N2,N3...
+
+  Similar to bit 9 of 'options'.  Forces the corresponding card into
+  full-duplex mode.  Please use this in preference to the `options'
+  parameter.
+
+  In fact, please don't use this at all! You're better off getting
+  autonegotiation working properly.
+
+rx_copybreak=M
+
+  The driver preallocates 32 full-sized (1536 byte) network buffers
+  for receiving.  When a packet arrives, the driver has to decide
+  whether to leave the packet in its full-sized buffer, or to allocate
+  a smaller buffer and copy the packet across into it.
+
+  This is a speed/space tradeoff.
+
+  The value of rx_copybreak is used to decide when to make the copy. 
+  If the packet size is less than rx_copybreak, the packet is copied. 
+  The default value for rx_copybreak is 200 bytes.
+
+max_interrupt_work=N
+
+  The driver's interrupt service routine can handle many receive and
+  transmit packets in a single invocation.  It does this in a loop. 
+  The value of max_interrupt_work governs how mnay times the interrupt
+  service routine will loop.  The default value is 32 loops.  If this
+  is exceeded the interrupt service routine gives up and generates a
+  warning message "eth0: Too much work in interrupt".
+
+compaq_ioaddr=N
+compaq_irq=N
+compaq_device_id=N
+
+  "Variables to work-around the Compaq PCI BIOS32 problem"....
+
+enable_wol=N1,N2,N3,...
+
+  Enable Wake-on-LAN support for the relevant interface.  Donald
+  Becker's `ether-wake' application may be used to wake suspended
+  machines.
+
+
+Media selection
+---------------
+
+A number of the older NICs such as the 3c590 and 3c900 series have
+10base2 and AUI interfaces.
+
+Prior to January, 2001 this driver would autoeselect the 10base2 or AUI
+port if it didn't detect activity on the 10baseT port.  It would then
+get stuck on the 10base2 port and a driver reload was necessary to
+switch back to 10baseT.  This behaviour could not be prevented with a
+module option override.
+
+Later (current) versions of the driver _do_ support locking of the
+media type.  So if you load the driver module with
+
+	modprobe 3c59x options=0
+
+it will permanently select the 10baseT port.  Automatic selection of
+other media types does not occur.
+
+
+Additional resources
+--------------------
 
 Details of the device driver implementation are at the top of the source file.
+
+Additional documentation is available at Don Becker's Linux Drivers site:
+
+  http://www.scyld.com/network/vortex.html
+
+Donald Becker's driver development site:
+
+     http://www.scyld.com/network
+
+Donald's vortex-diag program is useful for inspecting the NIC's state:
+
+     http://www.scyld.com/diag/#pci-diags
+
+Donald's mii-diag program may be used for inspecting and manipulating
+the NIC's Media Independent Interface subsystem:
+
+     http://www.scyld.com/diag/#mii-diag
+
+Donald's wake-on-LAN page:
+
+     http://www.scyld.com/expert/wake-on-lan.html
+
+3Com's documentation for many NICs, including the ones supported by
+this driver is available at 
+
+     http://support.3com.com/partners/developer/developer_form.html
+
+3Com's DOS-based application for setting up the NICs EEPROMs:
+
+	ftp://ftp.3com.com/pub/nic/3c90x/3c90xx2.exe
+
+Driver updates and a detailed changelog for the modifications which
+were made for the 2.3/2,4 series kernel is available at
+
+     http://www.uow.edu.au/~andrewm/linux/#3c59x-2.3
+
+
+Autonegotiation notes
+---------------------
+
+  The driver uses a one-minute heartbeat for adapting to changes in
+  the external LAN environment.  This means that when, for example, a
+  machine is unplugged from a hubbed 10baseT LAN plugged into a
+  switched 100baseT LAN, the throughput will be quite dreadful for up
+  to sixty seconds.  Be patient.
+
+  Cisco interoperability note from Walter Wong <wcw+@CMU.EDU>:
+
+  On a side note, adding HAS_NWAY seems to share a problem with the
+  Cisco 6509 switch.  Specifically, you need to change the spanning
+  tree parameter for the port the machine is plugged into to 'portfast'
+  mode.  Otherwise, the negotiation fails.  This has been an issue
+  we've noticed for a while but haven't had the time to track down.
+
+  Cisco switches    (Jeff Busch <jbusch@deja.com>)
+
+    My "standard config" for ports to which PC's/servers connect directly:
+
+        interface FastEthernet0/N
+        description machinename
+        load-interval 30
+        spanning-tree portfast
+
+    If autonegotiation is a problem, you may need to specify "speed
+    100" and "duplex full" as well (or "speed 10" and "duplex half").
+
+    WARNING: DO NOT hook up hubs/switches/bridges to these
+    specially-configured ports! The switch will become very confused.
+
+
+Reporting and diagnosing problems
+---------------------------------
+
+Maintainers find that accurate and complete problem reports are
+invaluable in resolving driver problems.  We are frequently not able to
+reproduce problems and must rely on your patience and efforts to get to
+the bottom of the problem.
+
+If you believe you have a driver problem here are some of the
+steps you should take:
+
+- Is it really a driver problem?
+
+   Eliminate some variables: try different cards, different
+   computers, different cables, different ports on the switch/hub,
+   different versions of the kernel or ofthe driver, etc.
+
+- OK, it's a driver problem.
+
+   You need to generate a report.  Typically this is an email to the
+   maintainer and/or linux-net@vger.kernel.org.  The maintainer's
+   email address will be inthe driver source or in the MAINTAINERS file.
+
+- The contents of your report will vary a lot depending upon the
+  problem.  If it's a kernel crash then you should refer to the
+  REPORTING-BUGS file.
+
+  But for most problems it is useful to provide the following:
+
+   o Kernel version, driver version
+
+   o A copy of the banner message which the driver generates when
+     it is initialised.  For example:
+
+     eth0: 3Com PCI 3c905C Tornado at 0xa400,  00:50:da:6a:88:f0, IRQ 19
+     8K byte-wide RAM 5:3 Rx:Tx split, autoselect/Autonegotiate interface.
+     MII transceiver found at address 24, status 782d.
+     Enabling bus-master transmits and whole-frame receives.
+
+   o If it is a PCI device, the relevant output from 'lspci -vx', eg:
+
+     00:09.0 Ethernet controller: 3Com Corporation 3c905C-TX [Fast Etherlink] (rev 74)
+             Subsystem: 3Com Corporation: Unknown device 9200
+             Flags: bus master, medium devsel, latency 32, IRQ 19
+             I/O ports at a400 [size=128]
+             Memory at db000000 (32-bit, non-prefetchable) [size=128]
+             Expansion ROM at <unassigned> [disabled] [size=128K]
+             Capabilities: [dc] Power Management version 2
+     00: b7 10 00 92 07 00 10 02 74 00 00 02 08 20 00 00
+     10: 01 a4 00 00 00 00 00 db 00 00 00 00 00 00 00 00
+     20: 00 00 00 00 00 00 00 00 00 00 00 00 b7 10 00 10
+     30: 00 00 00 00 dc 00 00 00 00 00 00 00 05 01 0a 0a
+
+   o A description of the environment: 10baseT? 100baseT?
+     full/half duplex? switched or hubbed?
+
+   o Any additional module parameters which you may be providing to the driver.
+
+   o Any kernel logs which are produced.  The more the merrier. 
+     If this is a large file and you are sending your report to a
+     mailing list, mention that you have the logfile, but don't send
+     it.  If you're reporting direct to the maintainer then just send
+     it.
+
+     To ensure that all kernel logs are available, add the
+     following line to /etc/syslog.conf:
+
+         kern.* /var/log/messages
+
+     Then restart syslogd with:
+
+         /etc/rc.d/init.d/syslog restart
+
+     (The above may vary, depending upon which Linux distribution you use).
+
+    o If your problem is reproducible then that's great.  Try the
+      following:
+
+      1) Increase the debug level.  Usually this is done via:
+
+         a) modprobe driver.o debug=7
+         b) In /etc/conf.modules (or modules.conf):
+            options driver_name debug=7
+
+      2) Recreate the problem with the higher debug level,
+         send all logs to the maintainer.
+
+      3) Download you card's diagnostic tool from Donald
+         Backer's website http://www.scyld.com/diag.  Download
+         mii-diag.c as well.  Build these.
+
+         a) Run 'vortex-diag -aaee' and 'mii-diag -v' when the card is
+            working correctly.  Save the output.
+
+         b) Run the above commands when the card is malfunctioning.  Send
+            both sets of output.
+
+Finally, please be patient and be prepared to do some work.  You may end up working on
+this problem for a week or more as the maintainer asks more questions, asks for more
+tests, asks for patches to be applied, etc.  At the end of it all, the problem may even
+remain unresolved.
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/powerpc/00-INDEX linux.19p18/Documentation/powerpc/00-INDEX
--- linux.vanilla/Documentation/powerpc/00-INDEX	Fri Apr 21 12:45:49 2000
+++ linux.19p18/Documentation/powerpc/00-INDEX	Thu Feb  1 15:07:06 2001
@@ -1,7 +1,7 @@
 Index of files in Documentation/powerpc.  If you think something about
 Linux/PPC needs an entry here, needs correction or you've written one
 please mail me.
-                                        Cort Dougan (cort@cs.nmt.edu)
+                                        Cort Dougan (cort@fsmlabs.com)
 
 00-INDEX
 	- this file
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/powerpc/ppc_htab.txt linux.19p18/Documentation/powerpc/ppc_htab.txt
--- linux.vanilla/Documentation/powerpc/ppc_htab.txt	Fri Apr 21 12:45:49 2000
+++ linux.19p18/Documentation/powerpc/ppc_htab.txt	Thu Feb  1 15:07:06 2001
@@ -2,7 +2,7 @@
 =====================================================================
 
 This document and the related code was written by me (Cort Dougan), please
-email me (cort@cs.nmt.edu) if you have questions, comments or corrections.
+email me (cort@fsmlabs.com) if you have questions, comments or corrections.
 
 Last Change: 2.16.98
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/powerpc/smp.txt linux.19p18/Documentation/powerpc/smp.txt
--- linux.vanilla/Documentation/powerpc/smp.txt	Fri Apr 21 12:45:49 2000
+++ linux.19p18/Documentation/powerpc/smp.txt	Thu Feb  1 15:07:06 2001
@@ -2,7 +2,7 @@
 =====================================================================
 
 This document and the related code was written by me
-(Cort Dougan, cort@cs.nmt.edu) please email me if you have questions,
+(Cort Dougan, cort@fsmlabs.com) please email me if you have questions,
 comments or corrections.
 
 Last Change: 3.31.99
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/powerpc/sound.txt linux.19p18/Documentation/powerpc/sound.txt
--- linux.vanilla/Documentation/powerpc/sound.txt	Fri Apr 21 12:45:49 2000
+++ linux.19p18/Documentation/powerpc/sound.txt	Thu Feb  1 15:07:06 2001
@@ -1,7 +1,7 @@
             Information about PowerPC Sound support
 =====================================================================
 
-Please mail me (Cort Dougan, cort@cs.nmt.edu) if you have questions,
+Please mail me (Cort Dougan, cort@fsmlabs.com) if you have questions,
 comments or corrections.
 
 Last Change: 6.16.99
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/powerpc/zImage_layout.txt linux.19p18/Documentation/powerpc/zImage_layout.txt
--- linux.vanilla/Documentation/powerpc/zImage_layout.txt	Fri Apr 21 12:45:49 2000
+++ linux.19p18/Documentation/powerpc/zImage_layout.txt	Thu Feb  1 15:07:06 2001
@@ -1,7 +1,7 @@
           Information about the Linux/PPC kernel images
 =====================================================================
 
-Please mail me me (Cort Dougan, cort@cs.nmt.edu) if you have questions,
+Please mail me me (Cort Dougan, cort@fsmlabs.com) if you have questions,
 comments or corrections.
 
 This document is meant to answer several questions I've had about how
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/rtc.txt linux.19p18/Documentation/rtc.txt
--- linux.vanilla/Documentation/rtc.txt	Fri Apr 21 12:45:49 2000
+++ linux.19p18/Documentation/rtc.txt	Tue Jan  9 12:14:00 2001
@@ -56,7 +56,7 @@
 exclusive access to the device for your applications.
 
 The alarm and/or interrupt frequency are programmed into the RTC via
-various ioctl(2) calls as listed in ./include/linux/mc146818rtc.h
+various ioctl(2) calls as listed in ./include/linux/rtc.h
 Rather than write 50 pages describing the ioctl() and so on, it is
 perhaps more useful to include a small test program that demonstrates
 how to use them, and demonstrates the features of the driver. This is
@@ -81,7 +81,7 @@
  */
 
 #include <stdio.h>
-#include <linux/mc146818rtc.h>
+#include <linux/rtc.h>
 #include <sys/ioctl.h>
 #include <sys/time.h>
 #include <sys/types.h>
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/s390/cds.txt linux.19p18/Documentation/s390/cds.txt
--- linux.vanilla/Documentation/s390/cds.txt	Mon Dec 11 22:12:32 2000
+++ linux.19p18/Documentation/s390/cds.txt	Wed Dec 13 22:43:46 2000
@@ -241,7 +241,7 @@
 
 The get_dev_info_by_irq() / get_dev_info_by_devno() functions return:
 
-      0 - sucessful completion
+      0 - successful completion
 -ENODEV - irq or devno don't specify a known subchannel or device
           number.
 -EINVAL - invalid devinfo value.
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/sound/ChangeLog.ymfsb linux.19p18/Documentation/sound/ChangeLog.ymfsb
--- linux.vanilla/Documentation/sound/ChangeLog.ymfsb	Sun Jun 11 21:44:08 2000
+++ linux.19p18/Documentation/sound/ChangeLog.ymfsb	Thu Jan  1 01:00:00 1970
@@ -1,19 +0,0 @@
-Sun May 21 15:14:37 2000  Daisuke Nagano  <breeze.nagano@nifty.ne.jp>
-
-	* ymf_sb.c: Add 'master_vol' module parameter to change
-	'PCM out Vol" of AC'97.
-	Should I support AC'97 mixer by implementing original mixer
-	codes... ?
-
-	* ymf_sb.c: remove native UART401 support. External MIDI port
-	should be supported by sb_midi driver.
-
-	*ymf_sb.c: add support for SPDIF OUT. Module parameter
-	'spdif_out' is now available.
-
-
-Tue May 16 19:29:29 2000  Daisuke Nagano  <breeze.nagano@nifty.ne.jp>
-
-	* ymf_sb.c (checkCodec): add a little delays for reset devices.
-	
-	* ymf_sb.c (readRegWord): fixed addressing bug.
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/sound/Maestro3 linux.19p18/Documentation/sound/Maestro3
--- linux.vanilla/Documentation/sound/Maestro3	Thu Jan  1 01:00:00 1970
+++ linux.19p18/Documentation/sound/Maestro3	Wed Jan  3 01:01:13 2001
@@ -0,0 +1,84 @@
+	An OSS/Lite Driver for the ESS Maestro3 family of sound chips
+
+			Zach Brown, December 2000
+
+Driver Status and Availability
+------------------------------
+
+The most recent version of this driver will hopefully always be available at
+	http://www.zabbo.net/maestro3/
+
+I will try and maintain the most recent stable version of the driver
+in both the stable and development kernel lines.
+
+Historically I've sucked pretty hard at actually doing that, however.
+
+ESS Maestro3 Chip Family
+-----------------------
+
+The 'Maestro3' is much like the Maestro2 chip.  The noted improvement
+is the removal of the silicon in the '2' that did PCM mixing.  All that
+work is now done through a custom DSP called the ASSP, the Asynchronus
+Specific Signal Processor.
+
+The 'Allegro' is a baby version of the Maestro3.  I'm not entirely clear
+on the extent of the differences, but the driver supports them both :)
+
+The 'Allegro' shows up as PCI ID 0x1988 and the Maestro3 as 0x1998,
+both under ESS's vendor ID of 0x125D.  The Maestro3 can also show up as
+0x199a when hardware strapping is used.
+
+The chip can also act as a multi function device.  The modem IDs follow
+the audio multimedia device IDs.  (so the modem part of an Allegro shows
+up as 0x1989)
+
+Driver OSS Behavior
+--------------------
+
+This OSS driver exports /dev/mixer and /dev/dsp to applications, which
+mostly adhere to the OSS spec.   This driver doesn't register itself
+with /dev/sndstat, so don't expect information to appear there.
+
+The /dev/dsp device exported behaves as expected.  Playback is
+supported in all the various lovely formats.  8/16bit stereo/mono from
+8khz to 48khz, with both read()/write(), and mmap().
+
+/dev/mixer is an interface to the AC'97 codec on the Maestro3.  It is
+worth noting that there are a variety of AC'97s that can be wired to
+the Maestro3.  Which is used is entirely up to the hardware implementor.
+This should only be visible to the user by the presence, or lack, of
+'Bass' and 'Treble' sliders in the mixer.  Not all AC'97s have them.
+The Allegro has an onchip AC'97.
+
+The driver doesn't support MIDI or FM playback at the moment.
+
+Compiling and Installing
+------------------------
+
+With the drivers inclusion into the kernel, compiling and installing
+is the same as most OSS/Lite modular sound drivers.  Compilation
+of the driver is enabled through the CONFIG_SOUND_MAESTRO3 variable
+in the config system.  
+
+It may be modular or statically linked.  If it is modular it should be
+installed with the rest of the modules for the kernel on the system.
+Typically this will be in /lib/modules/ somewhere.  'alias sound-slot-0
+maestro3' should also be added to your module configs (typically
+/etc/modules.conf) if you're using modular OSS/Lite sound and want to
+default to using a maestro3 chip.
+
+There are very few options to the driver.  One is 'debug' which will 
+tell the driver to print minimal debugging information as it runs.  This
+can be collected with 'dmesg' or through the klogd daemon.
+
+The other is 'external_amp', which tells the driver to attempt to enable
+an external amplifier.  This defaults to '1', you can tell the driver
+not to bother enabling such an amplifier by setting it to '0'.
+
+Power Management
+----------------
+
+This driver has a minimal understanding of PCI Power Management.  It will
+try and power down the chip when the system is suspended, and power
+it up with it is resumed.  It will also try and power down the chip
+when the machine is shut down.  
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/sound/README.ymfsb linux.19p18/Documentation/sound/README.ymfsb
--- linux.vanilla/Documentation/sound/README.ymfsb	Sat Sep  9 18:42:32 2000
+++ linux.19p18/Documentation/sound/README.ymfsb	Thu Jan  1 01:00:00 1970
@@ -1,127 +0,0 @@
-Legacy audio driver for YMF7xx PCI cards.
-
-
-FIRST OF ALL
-============
-
-  This code references YAMAHA's sample codes and data sheets.
-  I respect and thank for all people they made open the informations
-  about YMF7xx cards.
-
-  And this codes heavily based on Jeff Garzik <jgarzik@pobox.com>'s
-  old VIA 82Cxxx driver (via82cxxx.c). I also respect him.
-
-
-DISCLIMER
-=========
-
- This driver is currently at early ALPHA stage. It may cause serious
- damage to your computer when used.
- PLEASE USE IT AT YOUR OWN RISK.
-
-
-ABOUT THIS DRIVER
-=================
-
-  This code enables you to use your YMF724[A-F], YMF740[A-C], YMF744, YMF754
- cards as "SoundBlaster Pro" compatible card. It can only play 22.05kHz /
- 8bit / Stereo samples, control external MIDI port.
- And it can handle AC'97 mixer of these cards.
-
-  If you want to use your card as recent "16-bit" card, you should use
- Alsa or OSS/Linux driver. Ofcource you can write native PCI driver for
- your cards :)
-
-
-INSTALL
-=======
-
-  First, it requires some sound driver modules in Linux kernel 
- (soundcore.o , sound.o, sb.o and uart401.o), so you should enable
- these modules at kernel configuration (please refer some other 
- documentations for configuration of kernel).
- And add the following line in /etc/modules.conf:
-
-  options sb support=1
-
- (NOTE: There are no need any configuration of sb modules)
-
- To compile ymfsb module, type 'make'.
- And copy it to /lib/modules/(kernel_version)/misc, type 'depmod -a'.
- 
-  This module also requires /usr/src/linux/drivers/sound/ac97.[ch].
- If your kernel doesn't have these files, you should upgrade your kernel.
-
-
-USAGE
-=====
-
- # modprobe ymfsb (options)
-
-
-OPTIONS FOR YMFSB
-=================
-
-  io           : SB base address     (0x220, 0x240, 0x260, 0x280)
-  synth_io     : OPL3 base address   (0x388, 0x398, 0x3a0, 0x3a8)
-  dma          : DMA number          (0,1,3)
-  spdif_out    : SPDIF-out flag      (0:disable 1:enable)
-
- These options will change in future...
-
-
-FREQUENCY
-=========
-
-  When playing sounds via this driver, you will hear its pitch is slightly
- lower than original sounds. Since this driver recognizes your card acts
- with 21.739kHz sample rates rather than 22.050kHz (I think it must be
- hardware restriction). So many players become tone deafness.
- To prevent this, you should express some options to your sound player
- that specify correct sample frequency. For example, to play your MP3 file
- correctly with mpg123, specify the frequency like following:
-
-  %  mpg123 -r 21739 foo.mp3
-
-
-SPDIF OUT
-=========
-
-  With installing modules with option 'spdif_out=1', you can enjoy your
- sounds from SPDIF-out of your card (if it had).
- Its Fs is fixed to 48kHz (It never means the sample frequency become 
- up to 48kHz. All sounds via SPDIF-out also 22kHz samples). So your
- digital-in capable components has to be able to handle 48kHz Fs.
-
-
-COPYING
-=======
-
- 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, 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.
-
-
-TODO
-====
- * support for multiple cards
-   (set the different SB_IO,MPU_IO,OPL_IO for each cards)
-
- * support for OPL (dmfm) : There will be no requirements... :-<
-
-
-AUTHOR
-======
-
- Daisuke Nagano <breeze.nagano@nifty.ne.jp>
-
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Documentation/usb/usb-serial.txt linux.19p18/Documentation/usb/usb-serial.txt
--- linux.vanilla/Documentation/usb/usb-serial.txt	Mon Dec 11 22:12:32 2000
+++ linux.19p18/Documentation/usb/usb-serial.txt	Tue Dec 19 02:30:27 2000
@@ -185,6 +185,15 @@
   -- Add everything else that is missing :)
 
 
+Empeg empeg-car Mark I/II Driver (empeg.c)
+
+  This is an experimental driver to provide connectivity support for the
+  client synchronization tools for an Empeg empeg-car mp3 player.
+
+  The driver is still pretty new, so some testing 'in the wild' would be
+  helpful. :)
+
+
 Generic Serial driver
 
   If your device is not one of the above listed devices, compatible with
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/MAINTAINERS linux.19p18/MAINTAINERS
--- linux.vanilla/MAINTAINERS	Mon Dec 11 22:12:32 2000
+++ linux.19p18/MAINTAINERS	Sat Mar 10 23:05:47 2001
@@ -87,6 +87,12 @@
 L:	linux-hams@vger.kernel.org
 S:	Maintained
 
+8139too NETWORK DRIVER
+P:	Jeff Garzik, Jens David (Linux-2.2 port)
+M:	dg1kjd@afthd.tu-darmstadt.de
+L:	linux-net@vger.rutgers.edu
+S:	Maintained
+
 8390 NETWORK DRIVERS [WD80x3/SMC-ELITE, SMC-ULTRA, NE2000, 3C503, etc.]
 P:	Paul Gortmaker
 M:	p_gortmaker@yahoo.com
@@ -251,7 +257,7 @@
 
 DC390/AM53C974 SCSI driver
 P:	Kurt Garloff
-M:	kurt@garloff.de
+M:	garloff@suse.de
 W:	http://www.garloff.de/kurt/linux/dc390/
 S:	Maintained
 
@@ -493,6 +499,13 @@
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 
+INTEL IA32 MICROCODE UPDATE DRIVER
+P:	Tigran Aivazian
+M:	Tigran Aivazian <tigran@veritas.com>
+W:      http://www.urbanmyth.org/microcode
+L:	linux-kernel@vger.kernel.org
+S:	Maintained
+
 IP FIREWALL
 P:	Paul Russell
 M:	Paul.Russell@rustcorp.com.au
@@ -532,6 +545,13 @@
 L:	isdn4linux@listserv.isdn4linux.de
 S:	Maintained
 
+ISDN SUBSYSTEM (Eicon active card driver)
+P:	Armin Schindler
+M:	mac@melware.de
+L:	isdn4linux@listserv.isdn4linux.de
+W:	http://www.melware.net
+S:	Maintained
+
 JOYSTICK DRIVER
 P:	Vojtech Pavlik
 M:	vojtech@suse.cz
@@ -559,10 +579,12 @@
 S:	Maintained
 
 KERNEL NFSD
-P:	G. Allen Morris III
-M:	gam3@acm.org
+P:	Neil Brown
+M:	neilb@cse.unsw.edu.au
 L:	nfs-devel@linux.kernel.org (Linux NFS)
-W:	http://csua.berkeley.edu/~gam3/knfsd
+L:	nfs@lists.sourceforge.net
+W:	http://nfs.sourceforge.net/
+W:	http://www.cse.unsw.edu.au/~neilb/patches/knfsd-2.2/
 S:	Maintained
 
 LANMEDIA WAN CARD DRIVER
@@ -579,8 +601,8 @@
 
 LINUX FOR POWERPC (PREP)
 P:	Cort Dougan
-M:	cort@cs.nmt.edu
-W:	http://linuxppc.cs.nmt.edu/
+M:	cort@fsmlabs.com
+W:	http://www.fsmlabs.com/linuxppcbk.html
 S:	Maintained
 
 LINUX FOR POWER MACINTOSH
@@ -725,6 +747,13 @@
 W:	http://www.linuxtr.net
 S:	Maintained
 
+ONSTREAM SCSI TAPE DRIVER
+P:	Willem Riede
+M:	osst@riede.org
+L:	osst@linux1.onstream.nl
+L:	linux-scsi@vger.rutgers.edu
+S:	Maintained
+
 OPL3-SA2, SA3, and SAx DRIVER
 P:	Scott Murray
 M:	scott@spiteful.org
@@ -915,6 +944,11 @@
 M:	support@stallion.oz.au
 W:	http://www.stallion.com
 S:	Supported
+
+STARFIRE/DURALAN NETWORK DRIVER
+P:	Ion Badulescu
+M:	ionut@cs.columbia.edu
+S:	Maintained
 
 STARMODE RADIO IP (STRIP) PROTOCOL DRIVER
 W:	http://mosquitonet.Stanford.EDU/strip.html
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/Makefile linux.19p18/Makefile
--- linux.vanilla/Makefile	Mon Dec 11 22:12:32 2000
+++ linux.19p18/Makefile	Sat Mar 10 23:15:31 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
-SUBLEVEL = 18
-EXTRAVERSION =
+SUBLEVEL = 19
+EXTRAVERSION = pre17
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
@@ -25,7 +25,7 @@
 #
 #	foo-bar-gcc for cross builds
 #	gcc272 for Debian's old compiler for kernels
-#	kgcc for Conectiva and Red Hat 7
+#	kgcc for Conectiva, Mandrake and Red Hat 7
 #	otherwise 'cc'
 #
 CC	=$(shell if [ -n "$(CROSS_COMPILE)" ]; then echo $(CROSS_COMPILE)gcc; else \
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/alpha/config.in linux.19p18/arch/alpha/config.in
--- linux.vanilla/arch/alpha/config.in	Mon Dec 11 22:12:33 2000
+++ linux.19p18/arch/alpha/config.in	Thu Feb 15 16:19:20 2001
@@ -252,9 +252,11 @@
 mainmenu_option next_comment
 comment 'ISDN subsystem'
 
-tristate 'ISDN support' CONFIG_ISDN
-if [ "$CONFIG_ISDN" != "n" ]; then
-  source drivers/isdn/Config.in
+if [ "$CONFIG_NET" != "n" ]; then
+   tristate 'ISDN support' CONFIG_ISDN
+   if [ "$CONFIG_ISDN" != "n" ]; then
+      source drivers/isdn/Config.in
+   fi
 fi
 endmenu
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/alpha/kernel/alpha_ksyms.c linux.19p18/arch/alpha/kernel/alpha_ksyms.c
--- linux.vanilla/arch/alpha/kernel/alpha_ksyms.c	Mon Dec 11 22:12:33 2000
+++ linux.19p18/arch/alpha/kernel/alpha_ksyms.c	Wed Jan  3 13:34:35 2001
@@ -169,6 +169,7 @@
 EXPORT_SYMBOL(global_bh_lock);
 EXPORT_SYMBOL(global_bh_count);
 EXPORT_SYMBOL(synchronize_bh);
+EXPORT_SYMBOL(alpha_bh_lock);
 EXPORT_SYMBOL(global_irq_holder);
 EXPORT_SYMBOL(__global_cli);
 EXPORT_SYMBOL(__global_sti);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/alpha/kernel/entry.S linux.19p18/arch/alpha/kernel/entry.S
--- linux.vanilla/arch/alpha/kernel/entry.S	Fri Apr 21 12:45:44 2000
+++ linux.19p18/arch/alpha/kernel/entry.S	Wed Feb 14 14:25:46 2001
@@ -272,7 +272,11 @@
 	stq	$26,0($30)
 	stq	$19,8($30)
 	.prologue 1
+#ifdef __SMP__	
+	jsr	$26,___kernel_execve
+#else
 	jsr	$26,do_execve
+#endif	/* __SMP__ */
 	bne	$0,1f		/* error! */
 	ldq	$30,8($30)
 	br	$31,ret_from_sys_call
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/alpha/kernel/irq.c linux.19p18/arch/alpha/kernel/irq.c
--- linux.vanilla/arch/alpha/kernel/irq.c	Sun Jun 11 21:44:09 2000
+++ linux.19p18/arch/alpha/kernel/irq.c	Wed Jan  3 13:34:35 2001
@@ -385,6 +385,7 @@
 /* This protects BH software state (masks, things like that). */
 atomic_t global_bh_lock = ATOMIC_INIT(0);
 atomic_t global_bh_count = ATOMIC_INIT(0);
+spinlock_t alpha_bh_lock = SPIN_LOCK_UNLOCKED;
 
 static void *previous_irqholder = NULL;
 
@@ -650,6 +651,7 @@
 void
 synchronize_bh(void)
 {
+	mb();
 	if (atomic_read(&global_bh_count) && !in_interrupt())
 			wait_on_bh();
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/alpha/kernel/osf_sys.c linux.19p18/arch/alpha/kernel/osf_sys.c
--- linux.vanilla/arch/alpha/kernel/osf_sys.c	Fri Apr 21 12:45:44 2000
+++ linux.19p18/arch/alpha/kernel/osf_sys.c	Thu Feb  8 11:53:29 2001
@@ -78,8 +78,10 @@
 	mm = current->mm;
 	mm->end_code = bss_start + bss_len;
 	mm->brk = bss_start + bss_len;
+#if 0
 	printk("set_program_attributes(%lx %lx %lx %lx)\n",
 		text_start, text_len, bss_start, bss_len);
+#endif
 	unlock_kernel();
 	return 0;
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/alpha/kernel/process.c linux.19p18/arch/alpha/kernel/process.c
--- linux.vanilla/arch/alpha/kernel/process.c	Fri Apr 21 12:45:44 2000
+++ linux.19p18/arch/alpha/kernel/process.c	Thu Feb 15 10:12:07 2001
@@ -249,8 +249,11 @@
 	alpha_mv.kill_arch(LINUX_REBOOT_CMD_POWER_OFF, NULL);
 }
 
-void show_regs(struct pt_regs * regs)
+void __show_regs(struct pt_regs * regs)
 {
+	extern void dik_show_trace(unsigned long *);
+
+	printk("\nCPU: %d", smp_processor_id());
 	printk("\nps: %04lx pc: [<%016lx>]\n", regs->ps, regs->pc);
 	printk("rp: [<%016lx>] sp: %p\n", regs->r26, regs+1);
 	printk(" r0: %016lx  r1: %016lx  r2: %016lx  r3: %016lx\n",
@@ -265,6 +268,15 @@
 	       regs->r23, regs->r24, regs->r25, regs->r26);
 	printk("r27: %016lx r28: %016lx r29: %016lx hae: %016lx\n",
 	       regs->r27, regs->r28, regs->gp, regs->hae);
+	dik_show_trace(regs+1);
+}
+
+void show_regs(struct pt_regs * regs)
+{
+	__show_regs(regs);
+#ifdef CONFIG_SMP
+	smp_show_regs();
+#endif
 }
 
 /*
@@ -463,3 +475,29 @@
 	unlock_kernel();
 	return error;
 }
+
+#ifdef __SMP__
+/*
+ * execve() system call for in kernel use.
+ *
+ * Two(user and kernel) execve() have quite different call path and
+ * following function puts lock_kernel() and unlock_kernel() in kernel
+ * execve().  You could put them in unistd.h but you will have to
+ * modify many files to clear compile error -
+ *
+ * soohoon.lee@api-networks.com.  */
+
+asmlinkage int ___kernel_execve(char *filename, char **argp, char **envp,
+	struct pt_regs *regs)
+{
+	int error;
+
+	lock_kernel();
+
+	error = do_execve(filename, argp, envp, regs);
+
+	unlock_kernel();
+
+	return error;
+}
+#endif /* __SMP__ */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/alpha/kernel/smp.c linux.19p18/arch/alpha/kernel/smp.c
--- linux.vanilla/arch/alpha/kernel/smp.c	Mon Dec 11 22:12:33 2000
+++ linux.19p18/arch/alpha/kernel/smp.c	Wed Jan  3 13:37:59 2001
@@ -95,8 +95,7 @@
 smp_store_cpu_info(int cpuid)
 {
 	cpu_data[cpuid].loops_per_jiffy = loops_per_jiffy;
-	cpu_data[cpuid].last_asn
-	  = (cpuid << WIDTH_HARDWARE_ASN) + ASN_FIRST_VERSION;
+	cpu_data[cpuid].last_asn = ASN_FIRST_VERSION;
 
         cpu_data[cpuid].irq_count = 0;
         cpu_data[cpuid].bh_count = 0;
@@ -739,7 +738,14 @@
 
 			/* At this point the structure may be gone unless
 			   wait is true.  */
-			(*func)(info);
+			{
+			static void ipi_show_regs(void *);
+
+			if (func != ipi_show_regs)
+				(*func)(info);
+			else
+				(*func)((void *) regs);
+			}
 
 			/* Notify the sending CPU that the task is done.  */
 			mb();
@@ -856,6 +862,21 @@
 }
 
 static void
+ipi_show_regs(void * param)
+{
+	struct pt_regs *regs = (struct pt_regs *) param;
+
+	__show_regs(regs);
+}
+
+void
+smp_show_regs(void)
+{
+	if (smp_call_function(ipi_show_regs, NULL, 1, 1))
+		printk(KERN_CRIT "smp_show_regs: timed out\n");
+}
+
+static void
 ipi_flush_tlb_all(void *ignored)
 {
 	tbia();
@@ -879,6 +900,8 @@
 	struct mm_struct *mm = (struct mm_struct *) x;
 	if (mm == current->mm)
 		flush_tlb_current(mm);
+	else
+		flush_tlb_other(mm);
 }
 
 void
@@ -886,10 +909,17 @@
 {
 	if (mm == current->mm) {
 		flush_tlb_current(mm);
-		if (atomic_read(&mm->count) == 1)
+		if (atomic_read(&mm->count) == 1) {
+			int i, cpu, this_cpu = smp_processor_id();
+			for (i = 0; i < smp_num_cpus; i++) {
+				cpu = cpu_logical_map(i);
+				if (cpu == this_cpu)
+					continue;
+				mm->context[cpu] = 0;
+			}
 			return;
-	} else
-		flush_tlb_other(mm);
+		}
+	}
 
 	if (smp_call_function(ipi_flush_tlb_mm, mm, 1, 1)) {
 		printk(KERN_CRIT "flush_tlb_mm: timed out\n");
@@ -906,8 +936,12 @@
 ipi_flush_tlb_page(void *x)
 {
 	struct flush_tlb_page_struct *data = (struct flush_tlb_page_struct *)x;
-	if (data->mm == current->mm)
-		flush_tlb_current_page(data->mm, data->vma, data->addr);
+	struct mm_struct * mm = data->mm;
+
+	if (mm == current->mm)
+		flush_tlb_current_page(mm, data->vma, data->addr);
+	else
+		flush_tlb_other(mm);
 }
 
 void
@@ -918,10 +952,17 @@
 
 	if (mm == current->mm) {
 		flush_tlb_current_page(mm, vma, addr);
-		if (atomic_read(&current->mm->count) == 1)
+		if (atomic_read(&current->mm->count) == 1) {
+			int i, cpu, this_cpu = smp_processor_id();
+			for (i = 0; i < smp_num_cpus; i++) {
+				cpu = cpu_logical_map(i);
+				if (cpu == this_cpu)
+					continue;
+				mm->context[cpu] = 0;
+			}
 			return;
-	} else
-		flush_tlb_other(mm);
+		}
+	}
        
 	data.vma = vma;
 	data.mm = mm;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/alpha/kernel/sys_nautilus.c linux.19p18/arch/alpha/kernel/sys_nautilus.c
--- linux.vanilla/arch/alpha/kernel/sys_nautilus.c	Sun Jun 11 21:44:09 2000
+++ linux.19p18/arch/alpha/kernel/sys_nautilus.c	Thu Feb  1 14:55:05 2001
@@ -111,7 +111,7 @@
 
 	switch(mode) {
         case LINUX_REBOOT_CMD_HALT:
-		printk("Press Reset bottun");
+		printk("Press Reset button");
 		break;
 	case LINUX_REBOOT_CMD_RESTART:
 		{
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/alpha/kernel/sys_ruffian.c linux.19p18/arch/alpha/kernel/sys_ruffian.c
--- linux.vanilla/arch/alpha/kernel/sys_ruffian.c	Fri Apr 21 12:45:44 2000
+++ linux.19p18/arch/alpha/kernel/sys_ruffian.c	Thu Feb  8 11:53:29 2001
@@ -163,16 +163,91 @@
 	enable_irq(2);		/* enable 2nd PIC cascade */
 }
 
+/*
+ *  Interrupt routing:
+ *
+ *		Primary bus
+ *	  IdSel		INTA	INTB	INTC	INTD
+ * 21052   13		  -	  -	  -	  -
+ * SIO	   14		 23	  -	  -	  -
+ * 21143   15		 44	  -	  -	  -
+ * Slot 0  17		 43	 42	 41	 40
+ *
+ *		Secondary bus
+ *	  IdSel		INTA	INTB	INTC	INTD
+ * Slot 0   8 (18)	 19	 18	 17	 16
+ * Slot 1   9 (19)	 31	 30	 29	 28
+ * Slot 2  10 (20)	 27	 26	 25	 24
+ * Slot 3  11 (21)	 39	 38	 37	 36
+ * Slot 4  12 (22)	 35	 34	 33	 32
+ * 53c875  13 (23)	 20	  -	  -	  -
+ *
+ */
+
+static int __init
+ruffian_map_irq(struct pci_dev *dev, int slot, int pin)
+{
+        static char irq_tab[11][5] __initdata = {
+	      /*INT  INTA INTB INTC INTD */
+		{-1,  -1,  -1,  -1,  -1},  /* IdSel 13,  21052	     */
+		{-1,  -1,  -1,  -1,  -1},  /* IdSel 14,  SIO	     */
+		{44,  44,  44,  44,  44},  /* IdSel 15,  21143	     */
+		{-1,  -1,  -1,  -1,  -1},  /* IdSel 16,  none	     */
+		{43,  43,  42,  41,  40},  /* IdSel 17,  64-bit slot */
+		/* the next 6 are actually on PCI bus 1, across the bridge */
+		{19,  19,  18,  17,  16},  /* IdSel  8,  slot 0	     */
+		{31,  31,  30,  29,  28},  /* IdSel  9,  slot 1	     */
+		{27,  27,  26,  25,  24},  /* IdSel 10,  slot 2	     */
+		{39,  39,  38,  37,  36},  /* IdSel 11,  slot 3	     */
+		{35,  35,  34,  33,  32},  /* IdSel 12,  slot 4	     */
+		{20,  20,  20,  20,  20},  /* IdSel 13,  53c875	     */
+        };
+	const long min_idsel = 13, max_idsel = 23, irqs_per_slot = 5;
+	return COMMON_TABLE_LOOKUP;
+}
+
+static int __init
+ruffian_swizzle(struct pci_dev *dev, int *pinp)
+{
+	int slot, pin = *pinp;
+
+	if (dev->bus->number == 0) {
+		slot = PCI_SLOT(dev->devfn);
+	}		
+	/* Check for the built-in bridge.  */
+	else if (PCI_SLOT(dev->bus->self->devfn) == 13) {
+		slot = PCI_SLOT(dev->devfn) + 10;
+	}
+	else 
+	{
+		/* Must be a card-based bridge.  */
+		do {
+			if (PCI_SLOT(dev->bus->self->devfn) == 13) {
+				slot = PCI_SLOT(dev->devfn) + 10;
+				break;
+			}
+			pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));
+
+			/* Move up the chain of bridges.  */
+			dev = dev->bus->self;
+			/* Slot of the next bridge.  */
+			slot = PCI_SLOT(dev->devfn);
+		} while (dev->bus->self);
+	}
+	*pinp = pin;
+	return slot;
+}
 
 /*
  * For RUFFIAN, we do not want to make any modifications to the PCI
- * setup.  But we may need to do some kind of init.
+ * setup, except IRQ assignment.  But we may need to do some kind of init.
  */
 
 static void __init
 ruffian_pci_fixup(void)
 {
 	/* layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE); */
+	common_pci_fixup(ruffian_map_irq, ruffian_swizzle);
 }
 
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/alpha/kernel/traps.c linux.19p18/arch/alpha/kernel/traps.c
--- linux.vanilla/arch/alpha/kernel/traps.c	Sun Jun 11 21:44:09 2000
+++ linux.19p18/arch/alpha/kernel/traps.c	Thu Feb  8 11:53:29 2001
@@ -269,7 +269,7 @@
 	}
 }
 
-static void
+void
 dik_show_trace(unsigned long *sp)
 {
 	int i = 1;
@@ -1086,7 +1086,9 @@
 {
 	/* We only get here for OSF system calls, minus #112;
 	   the rest go to sys_ni_syscall.  */
+#if 0
 	printk("<sc %ld(%lx,%lx,%lx)>", regs.r0, a0, a1, a2);
+#endif
 	return -ENOSYS;
 }
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/alpha/lib/strlen_user.S linux.19p18/arch/alpha/lib/strlen_user.S
--- linux.vanilla/arch/alpha/lib/strlen_user.S	Fri Apr 21 12:45:45 2000
+++ linux.19p18/arch/alpha/lib/strlen_user.S	Tue Feb 27 16:30:13 2001
@@ -28,17 +28,9 @@
 	.set noat
 	.text
 
-	.globl __strlen_user
-	.ent __strlen_user
-	.frame sp, 0, ra
-
-	.align 3
-__strlen_user:
-	ldah	a1, 32767(zero)	# do not use plain strlen_user() for strings
-				# that might be almost 2 GB long; you should
-				# be using strnlen_user() instead
-
 	.globl __strnlen_user
+	.ent __strnlen_user
+	.frame sp, 0, ra
 
 	.align 3
 __strnlen_user:
@@ -89,4 +81,4 @@
 	subq	a1, t2, v0
 	ret
 
-	.end __strlen_user
+	.end __strnlen_user
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/alpha/mm/extable.c linux.19p18/arch/alpha/mm/extable.c
--- linux.vanilla/arch/alpha/mm/extable.c	Sun Jun 11 21:44:09 2000
+++ linux.19p18/arch/alpha/mm/extable.c	Tue Jan  9 12:05:48 2001
@@ -88,7 +88,7 @@
 	 */
 	ret = search_exception_table_without_gp(addr);
 	if (ret) {
-		printk(KERN_ALERT, "%s: [%lx] EX_TABLE search fail with"
+		printk(KERN_ALERT "%s: [%lx] EX_TABLE search fail with"
 		       "exc frame GP, success with raw GP\n",
 		       current->comm, addr);
 		return ret;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/alpha/mm/fault.c linux.19p18/arch/alpha/mm/fault.c
--- linux.vanilla/arch/alpha/mm/fault.c	Sat Sep  9 18:42:32 2000
+++ linux.19p18/arch/alpha/mm/fault.c	Wed Jan  3 13:33:37 2001
@@ -41,7 +41,7 @@
 get_new_mmu_context(struct task_struct *p, struct mm_struct *mm)
 {
 	unsigned long new = __get_new_mmu_context();
-	mm->context = new;
+	mm->context[smp_processor_id()] = new;
 	p->tss.asn = new & HARDWARE_ASN_MASK;
 }
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/dec21285.c linux.19p18/arch/arm/kernel/dec21285.c
--- linux.vanilla/arch/arm/kernel/dec21285.c	Mon Dec 11 22:12:33 2000
+++ linux.19p18/arch/arm/kernel/dec21285.c	Wed Jan  3 00:57:43 2001
@@ -169,9 +169,14 @@
 __initfunc(void pcibios_init(void))
 {
 	unsigned int mem_size = (unsigned int)high_memory - PAGE_OFFSET;
+	unsigned int mem_mask;
 	unsigned long cntl;
 
-	*CSR_SDRAMBASEMASK    = (mem_size - 1) & 0x0ffc0000;
+	for (mem_mask = 0x00100000; mem_mask < 0x10000000; mem_mask <<= 1)
+		if (mem_mask >= mem_size)
+			break;		
+
+	*CSR_SDRAMBASEMASK    = (mem_mask - 1) & 0x0ffc0000;
 	*CSR_SDRAMBASEOFFSET  = 0;
 	*CSR_ROMBASEMASK      = 0x80000000;
 	*CSR_CSRBASEMASK      = 0;
@@ -224,7 +229,7 @@
 	*CSR_PCISDRAMBASE     = virt_to_bus((void *)PAGE_OFFSET);
 	*CSR_PCIROMBASE       = 0;
 	*CSR_PCICMD           = PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
-				PCI_COMMAND_MASTER | PCI_COMMAND_FAST_BACK |
+				PCI_COMMAND_MASTER |
 				PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY |
 				(1 << 31) | (1 << 29) | (1 << 28) | (1 << 24);
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/entry-armv.S linux.19p18/arch/arm/kernel/entry-armv.S
--- linux.vanilla/arch/arm/kernel/entry-armv.S	Mon Dec 11 22:12:33 2000
+++ linux.19p18/arch/arm/kernel/entry-armv.S	Wed Jan  3 00:57:43 2001
@@ -322,7 +322,8 @@
 
 		.macro	restore_user_regs
 		ldr	r0, [sp, #S_PSR]		@ Get calling cpsr
-		msr	cpsr_c, #I_BIT | MODE_SVC	@ disable IRQs
+		mov	r1, #I_BIT | MODE_SVC		@ disable IRQs
+		msr	cpsr_c, r1
 		msr	spsr, r0			@ save in spsr_svc
 		ldmia	sp, {r0 - lr}^			@ Get calling r0 - lr
 		mov	r0, r0
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/head-armv.S linux.19p18/arch/arm/kernel/head-armv.S
--- linux.vanilla/arch/arm/kernel/head-armv.S	Mon Dec 11 22:12:33 2000
+++ linux.19p18/arch/arm/kernel/head-armv.S	Wed Jan  3 00:57:43 2001
@@ -388,6 +388,7 @@
 __arch_types_end:
 
 #ifdef CONFIG_DEBUG_LL
+		.text
 /*
  * Some debugging routines (useful if you've got MM problems and
  * printk isn't working).  For DEBUGGING ONLY!!!  Do not leave
@@ -441,6 +442,10 @@
 		.endm
 
 #elif defined(CONFIG_HOST_FOOTBRIDGE) || defined(CONFIG_ADDIN_FOOTBRIDGE)
+
+#include <asm/dec21285.h>
+#include <asm/hardware.h>
+
 #ifndef CONFIG_DEBUG_DC21285_PORT
 	/* For NetWinder debugging */
 		.macro	addruart,rx
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/hw-footbridge.c linux.19p18/arch/arm/kernel/hw-footbridge.c
--- linux.vanilla/arch/arm/kernel/hw-footbridge.c	Mon Dec 11 22:12:33 2000
+++ linux.19p18/arch/arm/kernel/hw-footbridge.c	Wed Jan  3 00:57:43 2001
@@ -205,7 +205,8 @@
 
 		pci_read_config_word(dev, PCI_STATUS, &status);
 		if (status & 0xf900) {
-			printk(KERN_DEBUG "PCI: [%04X:%04X] status = %X\n",
+			printk(KERN_DEBUG "PCI: %02x:%02x.%d [%04X:%04X] status = 0x%04X\n",
+				dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
 				dev->vendor, dev->device, status);
 
 			pci_write_config_word(dev, PCI_STATUS, status & 0xf900);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/process.c linux.19p18/arch/arm/kernel/process.c
--- linux.vanilla/arch/arm/kernel/process.c	Mon Dec 11 22:12:33 2000
+++ linux.19p18/arch/arm/kernel/process.c	Wed Jan  3 00:57:43 2001
@@ -228,10 +228,8 @@
 
 void flush_thread(void)
 {
-	int i;
-
-	for (i = 0; i < NR_DEBUGS; i++)
-		current->tss.debug[i] = 0;
+	memset(&current->tss.debug, 0, sizeof(struct debug_info));
+	memset(&current->tss.fpstate, 0, sizeof(union fp_state));
 	current->used_math = 0;
 	current->flags &= ~PF_USEDFPU;
 }
@@ -263,12 +261,10 @@
  */
 int dump_fpu (struct pt_regs *regs, struct user_fp *fp)
 {
-	int fpvalid = 0;
-
 	if (current->used_math)
-		memcpy (fp, &current->tss.fpstate.soft, sizeof (fp));
+		memcpy (fp, &current->tss.fpstate.soft, sizeof (*fp));
 
-	return fpvalid;
+	return current->used_math;
 }
 
 /*
@@ -276,18 +272,20 @@
  */
 void dump_thread(struct pt_regs * regs, struct user * dump)
 {
-	int i;
-
+	struct task_struct *tsk = current;
 	dump->magic = CMAGIC;
-	dump->start_code = current->mm->start_code;
+	dump->start_code = tsk->mm->start_code;
 	dump->start_stack = regs->ARM_sp & ~(PAGE_SIZE - 1);
 
-	dump->u_tsize = (current->mm->end_code - current->mm->start_code) >> PAGE_SHIFT;
-	dump->u_dsize = (current->mm->brk - current->mm->start_data + PAGE_SIZE - 1) >> PAGE_SHIFT;
+	dump->u_tsize = (tsk->mm->end_code - tsk->mm->start_code) >> PAGE_SHIFT;
+	dump->u_dsize = (tsk->mm->brk - tsk->mm->start_data + PAGE_SIZE - 1) >> PAGE_SHIFT;
 	dump->u_ssize = 0;
 
-	for (i = 0; i < NR_DEBUGS; i++)
-		dump->u_debugreg[i] = current->tss.debug[i];  
+	dump->u_debugreg[0] = tsk->tss.debug.bp[0].address;
+	dump->u_debugreg[1] = tsk->tss.debug.bp[1].address;
+	dump->u_debugreg[2] = tsk->tss.debug.bp[0].insn;
+	dump->u_debugreg[3] = tsk->tss.debug.bp[1].insn;
+	dump->u_debugreg[4] = tsk->tss.debug.nsaved;
 
 	if (dump->start_stack < 0x04000000)
 		dump->u_ssize = (0x04000000 - dump->start_stack) >> PAGE_SHIFT;
@@ -310,14 +308,19 @@
 	pid_t __ret;
 
 	__asm__ __volatile__(
-	"mov	r0, %1		@ kernel_thread sys_clone\n"
+	"orr	r0, %1, %2	@ kernel_thread\n"
 "	mov	r1, #0\n"
 	__syscall(clone)"\n"
-"	mov	%0, r0"
+"	movs	%0, r0
+	bne	1f
+	mov	fp, r0
+	mov	r0, %4
+	mov	lr, pc
+	mov	pc, %3
+	b	sys_exit
+1:	"
         : "=r" (__ret)
-        : "Ir" (flags | CLONE_VM) : "r0", "r1");
-	if (__ret == 0)
-		sys_exit((fn)(arg));
+        : "Ir" (flags), "I" (CLONE_VM), "r" (fn), "r" (arg): "r0", "r1", "lr");
 	return __ret;
 }
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/ptrace.c linux.19p18/arch/arm/kernel/ptrace.c
--- linux.vanilla/arch/arm/kernel/ptrace.c	Mon Dec 11 22:12:33 2000
+++ linux.19p18/arch/arm/kernel/ptrace.c	Wed Feb  7 09:51:01 2001
@@ -16,6 +16,9 @@
 #include <asm/pgtable.h>
 #include <asm/system.h>
 
+
+#define REG_PC	15
+#define REG_PSR	16
 /*
  * does not yet catch signals sent when the child dies.
  * in exit.c or in signal.c.
@@ -25,11 +28,12 @@
  * Breakpoint SWI instruction: SWI &9F0001
  */
 #define BREAKINST	0xef9f0001
-#define PTRACE_GETREGS		12
-#define PTRACE_SETREGS		13
-#define PTRACE_GETFPREGS	14
-#define PTRACE_SETFPREGS	15
 
+/*
+ * Get the address of the live pt_regs for the specified task.
+ * These are saved onto the top kernel stack when the process
+ * is not running.
+ */
 static inline struct pt_regs *
 get_user_regs(struct task_struct *task)
 {
@@ -299,38 +303,42 @@
 	return 0;
 }
 
+#define write_tsk_long(chld, addr, val) write_long((chld), (addr), (val))
+#define read_tsk_long(chld, addr, val)  read_long((chld), (addr), (val))
+
 /*
  * Get value of register `rn' (in the instruction)
  */
-static unsigned long ptrace_getrn (struct task_struct *child, unsigned long insn)
+static unsigned long
+ptrace_getrn(struct task_struct *child, unsigned long insn)
 {
 	unsigned int reg = (insn >> 16) & 15;
 	unsigned long val;
 
+	val = get_stack_long(child, reg);
 	if (reg == 15)
-		val = pc_pointer (get_stack_long (child, reg));
-	else
-		val = get_stack_long (child, reg);
+		val = pc_pointer(val + 8);
+
 
-printk ("r%02d=%08lX ", reg, val);
 	return val;
 }
 
 /*
  * Get value of operand 2 (in an ALU instruction)
  */
-static unsigned long ptrace_getaluop2 (struct task_struct *child, unsigned long insn)
+static unsigned long
+ptrace_getaluop2(struct task_struct *child, unsigned long insn)
 {
 	unsigned long val;
 	int shift;
 	int type;
 
-printk ("op2=");
+
 	if (insn & 1 << 25) {
 		val = insn & 255;
 		shift = (insn >> 8) & 15;
 		type = 3;
-printk ("(imm)");
+
 	} else {
 		val = get_stack_long (child, insn & 15);
 
@@ -340,9 +348,9 @@
 			shift = (insn >> 7) & 31;
 
 		type = (insn >> 5) & 3;
-printk ("(r%02ld)", insn & 15);
+
 	}
-printk ("sh%dx%d", type, shift);
+
 	switch (type) {
 	case 0:	val <<= shift;	break;
 	case 1:	val >>= shift;	break;
@@ -350,27 +358,28 @@
 		val = (((signed long)val) >> shift);
 		break;
 	case 3:
-		__asm__ __volatile__("mov %0, %0, ror %1" : "=r" (val) : "0" (val), "r" (shift));
+		val = (val >> shift) | (val << (32 - shift));
 		break;
 	}
-printk ("=%08lX ", val);
+
 	return val;
 }
 
 /*
  * Get value of operand 2 (in a LDR instruction)
  */
-static unsigned long ptrace_getldrop2 (struct task_struct *child, unsigned long insn)
+static unsigned long
+ptrace_getldrop2(struct task_struct *child, unsigned long insn)
 {
 	unsigned long val;
 	int shift;
 	int type;
 
-	val = get_stack_long (child, insn & 15);
+	val = get_stack_long(child, insn & 15);
 	shift = (insn >> 7) & 31;
 	type = (insn >> 5) & 3;
 
-printk ("op2=r%02ldsh%dx%d", insn & 15, shift, type);
+
 	switch (type) {
 	case 0:	val <<= shift;	break;
 	case 1:	val >>= shift;	break;
@@ -378,115 +387,88 @@
 		val = (((signed long)val) >> shift);
 		break;
 	case 3:
-		__asm__ __volatile__("mov %0, %0, ror %1" : "=r" (val) : "0" (val), "r" (shift));
+		val = (val >> shift) | (val << (32 - shift));
 		break;
 	}
-printk ("=%08lX ", val);
+
 	return val;
 }
-#undef pc_pointer
-#define pc_pointer(x) ((x) & 0x03fffffc)
-int ptrace_set_bpt (struct task_struct *child)
-{
-	unsigned long insn, pc, alt;
-	int i, nsaved = 0, res;
-
-	pc = pc_pointer (get_stack_long (child, 15/*REG_PC*/));
-
-	res = read_long (child, pc, &insn);
-	if (res < 0)
-		return res;
-
-	child->tss.debug[nsaved++] = alt = pc + 4;
-printk ("ptrace_set_bpt: insn=%08lX pc=%08lX ", insn, pc);
-	switch (insn & 0x0e100000) {
+
+static unsigned long
+get_branch_address(struct task_struct *child, unsigned long pc, unsigned long insn)
+{
+	unsigned long alt = 0;
+
+	switch (insn & 0x0e000000) {
 	case 0x00000000:
-	case 0x00100000:
-	case 0x02000000:
-	case 0x02100000: /* data processing */
-		printk ("data ");
-		switch (insn & 0x01e0f000) {
-		case 0x0000f000:
-			alt = ptrace_getrn(child, insn) & ptrace_getaluop2(child, insn);
-			break;
-		case 0x0020f000:
-			alt = ptrace_getrn(child, insn) ^ ptrace_getaluop2(child, insn);
-			break;
-		case 0x0040f000:
-			alt = ptrace_getrn(child, insn) - ptrace_getaluop2(child, insn);
-			break;
-		case 0x0060f000:
-			alt = ptrace_getaluop2(child, insn) - ptrace_getrn(child, insn);
-			break;
-		case 0x0080f000:
-			alt = ptrace_getrn(child, insn) + ptrace_getaluop2(child, insn);
-			break;
-		case 0x00a0f000:
-			alt = ptrace_getrn(child, insn) + ptrace_getaluop2(child, insn) +
-				(get_stack_long (child, 16/*REG_PSR*/) & CC_C_BIT ? 1 : 0);
-			break;
-		case 0x00c0f000:
-			alt = ptrace_getrn(child, insn) - ptrace_getaluop2(child, insn) +
-				(get_stack_long (child, 16/*REG_PSR*/) & CC_C_BIT ? 1 : 0);
-			break;
-		case 0x00e0f000:
-			alt = ptrace_getaluop2(child, insn) - ptrace_getrn(child, insn) +
-				(get_stack_long (child, 16/*REG_PSR*/) & CC_C_BIT ? 1 : 0);
-			break;
-		case 0x0180f000:
-			alt = ptrace_getrn(child, insn) | ptrace_getaluop2(child, insn);
-			break;
-		case 0x01a0f000:
-			alt = ptrace_getaluop2(child, insn);
-			break;
-		case 0x01c0f000:
-			alt = ptrace_getrn(child, insn) & ~ptrace_getaluop2(child, insn);
-			break;
-		case 0x01e0f000:
-			alt = ~ptrace_getaluop2(child, insn);
+	case 0x02000000: {
+		/*
+		 * data processing
+		 */
+		long aluop1, aluop2, ccbit;
+
+		if ((insn & 0xf000) != 0xf000)
 			break;
+
+
+
+		aluop1 = ptrace_getrn(child, insn);
+		aluop2 = ptrace_getaluop2(child, insn);
+		ccbit  = get_stack_long(child, REG_PSR) & CC_C_BIT ? 1 : 0;
+
+		switch (insn & 0x01e00000) {
+		case 0x00000000: alt = aluop1 & aluop2;		break;
+		case 0x00200000: alt = aluop1 ^ aluop2;		break;
+		case 0x00400000: alt = aluop1 - aluop2;		break;
+		case 0x00600000: alt = aluop2 - aluop1;		break;
+		case 0x00800000: alt = aluop1 + aluop2;		break;
+		case 0x00a00000: alt = aluop1 + aluop2 + ccbit;	break;
+		case 0x00c00000: alt = aluop1 - aluop2 + ccbit;	break;
+		case 0x00e00000: alt = aluop2 - aluop1 + ccbit;	break;
+		case 0x01800000: alt = aluop1 | aluop2;		break;
+		case 0x01a00000: alt = aluop2;			break;
+		case 0x01c00000: alt = aluop1 & ~aluop2;	break;
+		case 0x01e00000: alt = ~aluop2;			break;
 		}
 		break;
+	}
+
+	case 0x04000000:
+	case 0x06000000:
+		/*
+		 * ldr
+		 */
+		if ((insn & 0x0010f000) == 0x0010f000) {
+			unsigned long base;
 
-	case 0x04100000: /* ldr */
-		if ((insn & 0xf000) == 0xf000) {
-printk ("ldr ");
-			alt = ptrace_getrn(child, insn);
+			base = ptrace_getrn(child, insn);
 			if (insn & 1 << 24) {
-				if (insn & 1 << 23)
-					alt += ptrace_getldrop2 (child, insn);
+				long aluop2;
+
+				if (insn & 0x02000000)
+					aluop2 = ptrace_getldrop2(child, insn);
 				else
-					alt -= ptrace_getldrop2 (child, insn);
-			}
-			if (read_long (child, alt, &alt) < 0)
-				alt = pc + 4; /* not valid */
-			else
-				alt = pc_pointer (alt);
-		}
-		break;
+					aluop2 = insn & 0xfff;
 
-	case 0x06100000: /* ldr imm */
-		if ((insn & 0xf000) == 0xf000) {
-printk ("ldrimm ");
-			alt = ptrace_getrn(child, insn);
-			if (insn & 1 << 24) {
 				if (insn & 1 << 23)
-					alt += insn & 0xfff;
+					base += aluop2;
 				else
-					alt -= insn & 0xfff;
+					base -= aluop2;
 			}
-			if (read_long (child, alt, &alt) < 0)
-				alt = pc + 4; /* not valid */
-			else
-				alt = pc_pointer (alt);
+
+			if (read_tsk_long(child, base, &alt) == 0)
+				alt = pc_pointer(alt);
 		}
 		break;
 
-	case 0x08100000: /* ldm */
-		if (insn & (1 << 15)) {
+	case 0x08000000:
+		/*
+		 * ldm
+		 */
+		if ((insn & 0x00108000) == 0x00108000) {
 			unsigned long base;
-			int nr_regs;
-printk ("ldm ");
+			unsigned int nr_regs;
+
 
 			if (insn & (1 << 23)) {
 				nr_regs = insn & 65535;
@@ -506,23 +488,23 @@
 					nr_regs = 0;
 			}
 
-			base = ptrace_getrn (child, insn);
+			base = ptrace_getrn(child, insn);
 
-			if (read_long (child, base + nr_regs, &alt) < 0)
-				alt = pc + 4; /* not valid */
-			else
-				alt = pc_pointer (alt);
+			if (read_tsk_long(child, base + nr_regs, &alt) == 0)
+				alt = pc_pointer(alt);
 			break;
 		}
 		break;
 
-	case 0x0a000000:
-	case 0x0a100000: { /* bl or b */
+	case 0x0a000000: {
+		/*
+		 * bl or b
+		 */
 		signed long displ;
-printk ("b/bl ");
+
 		/* It's a branch/branch link: instead of trying to
 		 * figure out whether the branch will be taken or not,
-		 * we'll put a breakpoint at either location.  This is
+		 * we'll put a breakpoint at both locations.  This is
 		 * simpler, more reliable, and probably not a whole lot
 		 * slower than the alternative approach of emulating the
 		 * branch.
@@ -534,196 +516,230 @@
 	    }
 	    break;
 	}
-printk ("=%08lX\n", alt);
-	if (alt != pc + 4)
-		child->tss.debug[nsaved++] = alt;
 
-	for (i = 0; i < nsaved; i++) {
-		res = read_long (child, child->tss.debug[i], &insn);
-		if (res >= 0) {
-			child->tss.debug[i + 2] = insn;
-			res = write_long (child, child->tss.debug[i], BREAKINST);
-		}
-		if (res < 0) {
-			child->tss.debug[4] = 0;
-			return res;
+	return alt;
+}
+
+static int
+add_breakpoint(struct task_struct *child, struct debug_info *dbg, unsigned long addr)
+{
+	int nr = dbg->nsaved;
+	int res = -EINVAL;
+
+	if (nr < 2) {
+		res = read_tsk_long(child, addr, &dbg->bp[nr].insn);
+		if (res == 0)
+			res = write_tsk_long(child, addr, BREAKINST);
+
+		if (res == 0) {
+			dbg->bp[nr].address = addr;
+			dbg->nsaved += 1;
 		}
+	} else
+		printk(KERN_DEBUG "add_breakpoint: too many breakpoints\n");
+
+	return res;
+}
+
+int ptrace_set_bpt(struct task_struct *child)
+{
+	unsigned long insn, pc;
+	int res;
+
+	pc = pc_pointer(get_stack_long(child, REG_PC));
+
+	res = read_long(child, pc, &insn);
+	if (!res) {
+		struct debug_info *dbg = &child->tss.debug;
+		unsigned long alt;
+
+		dbg->nsaved = 0;
+
+		alt = get_branch_address(child, pc, insn);
+
+		if (alt)
+			res = add_breakpoint(child, dbg, alt);
+
+		/*
+		 * Note that we ignore the result of setting the above
+		 * breakpoint since it may fail.  When it does, this is
+		 * not so much an error, but a forewarning that we will
+		 * be receiving a prefetch abort shortly.
+		 *
+		 * If we don't set this breakpoint here, then we can
+		 * loose control of the thread during single stepping.
+		 */
+		if (!alt || predicate(insn) != PREDICATE_ALWAYS)
+			res = add_breakpoint(child, dbg, pc + 4);
 	}
-	child->tss.debug[4] = nsaved;
-	return 0;
+
+	return res;
 }
 
-/* Ensure no single-step breakpoint is pending.  Returns non-zero
+/*
+ * Ensure no single-step breakpoint is pending.  Returns non-zero
  * value if child was being single-stepped.
  */
 int ptrace_cancel_bpt (struct task_struct *child)
 {
-	int i, nsaved = child->tss.debug[4];
+	struct debug_info *dbg = &child->tss.debug;
+	int i, nsaved = dbg->nsaved;
 
-	child->tss.debug[4] = 0;
+	dbg->nsaved = 0;
 
 	if (nsaved > 2) {
-		printk ("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved);
+		printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved);
 		nsaved = 2;
 	}
-	for (i = 0; i < nsaved; i++)
-		write_long (child, child->tss.debug[i], child->tss.debug[i + 2]);
+
+	for (i = 0; i < nsaved; i++) {
+		unsigned long tmp;
+
+		read_tsk_long(child, dbg->bp[i].address, &tmp);
+		if (tmp != BREAKINST)
+			printk(KERN_ERR "ptrace_cancel_bpt: weirdness\n");
+		write_tsk_long(child, dbg->bp[i].address, dbg->bp[i].insn);
+	}
 	return nsaved != 0;
 }
 
-asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
+static int do_ptrace(int request, struct task_struct *child, long addr, long data)
 {
-	struct task_struct *child;
+	unsigned long tmp;
 	int ret;
 
-	lock_kernel();
-	ret = -EPERM;
-	if (request == PTRACE_TRACEME) {
-		/* are we already being traced? */
-		if (current->flags & PF_PTRACED)
-			goto out;
-		/* set the ptrace bit in the process flags. */
-		current->flags |= PF_PTRACED;
-		ret = 0;
-		goto out;
-	}
-	if (pid == 1)		/* you may not mess with init */
-		goto out;
-	ret = -ESRCH;
-	if (!(child = find_task_by_pid(pid)))
-		goto out;
-	ret = -EPERM;
-	if (request == PTRACE_ATTACH) {
-		if (child == current)
-			goto out;
-		if ((!child->dumpable ||
-		    (current->uid != child->euid) ||
-		    (current->uid != child->suid) ||
-		    (current->uid != child->uid) ||
-	 	    (current->gid != child->egid) ||
-	 	    (current->gid != child->sgid) ||
-	 	    (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
-			goto out;
-		/* the same process cannot be attached many times */
-		if (child->flags & PF_PTRACED)
-			goto out;
-		child->flags |= PF_PTRACED;
-		if (child->p_pptr != current) {
-			REMOVE_LINKS(child);
-			child->p_pptr = current;
-			SET_LINKS(child);
-		}
-		send_sig(SIGSTOP, child, 1);
-		ret = 0;
-		goto out;
-	}
-	ret = -ESRCH;
-	if (!(child->flags & PF_PTRACED))
-		goto out;
-	if (child->state != TASK_STOPPED) {
-		if (request != PTRACE_KILL)
-			goto out;
-	}
-	if (child->p_pptr != current)
-		goto out;
-
 	switch (request) {
-		case PTRACE_PEEKTEXT:				/* read word at location addr. */
-		case PTRACE_PEEKDATA: {
-			unsigned long tmp;
-
-			ret = read_long(child, addr, &tmp);
-			if (ret >= 0)
-				ret = put_user(tmp, (unsigned long *)data);
-			goto out;
-		}
-
-		case PTRACE_PEEKUSR: {				/* read the word at location addr in the USER area. */
-			unsigned long tmp;
+		/*
+		 * read word at location "addr" in the child process.
+		 */
+		case PTRACE_PEEKTEXT:
+		case PTRACE_PEEKDATA:
+			ret = read_tsk_long(child, addr, &tmp);
+			if (!ret)
+				ret = put_user(tmp, (unsigned long *) data);
+			break;
 
+		/*
+		 * read the word at location "addr" in the user registers.
+		 */
+		case PTRACE_PEEKUSR:
 			ret = -EIO;
 			if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
-				goto out;
+				break;
 
 			tmp = 0;  /* Default return condition */
-			if (addr < sizeof (struct pt_regs))
+			if (addr < sizeof(struct pt_regs))
 				tmp = get_stack_long(child, (int)addr >> 2);
 			ret = put_user(tmp, (unsigned long *)data);
-			goto out;
-		}
+			break;
 
-		case PTRACE_POKETEXT:				/* write the word at location addr. */
+		/*
+		 * write the word at location addr.
+		 */
+		case PTRACE_POKETEXT:
 		case PTRACE_POKEDATA:
-			ret = write_long(child,addr,data);
-			goto out;
+			ret = write_tsk_long(child, addr, data);
+			break;
 
-		case PTRACE_POKEUSR:				/* write the word at location addr in the USER area */
+		/*
+		 * write the word at location addr in the user registers.
+		 */
+		case PTRACE_POKEUSR:
 			ret = -EIO;
 			if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
-				goto out;
+				break;
 
-			if (addr < sizeof (struct pt_regs))
+			if (addr < sizeof(struct pt_regs))
 				ret = put_stack_long(child, (int)addr >> 2, data);
-			goto out;
+			break;
 
-		case PTRACE_SYSCALL:				/* continue and stop at next (return from) syscall */
-		case PTRACE_CONT:				/* restart after signal. */
+		/*
+		 * continue/restart and stop at next (return from) syscall
+		 */
+		case PTRACE_SYSCALL:
+		case PTRACE_CONT:
 			ret = -EIO;
 			if ((unsigned long) data > _NSIG)
-				goto out;
+				break;
 			if (request == PTRACE_SYSCALL)
 				child->flags |= PF_TRACESYS;
 			else
 				child->flags &= ~PF_TRACESYS;
 			child->exit_code = data;
-			wake_up_process (child);
 			/* make sure single-step breakpoint is gone. */
-			ptrace_cancel_bpt (child);
+			ptrace_cancel_bpt(child);
+			wake_up_process(child);
 			ret = 0;
-			goto out;
+			break;
 
-		/* make the child exit.  Best I can do is send it a sigkill.
+		/*
+		 * make the child exit.  Best I can do is send it a sigkill.
 		 * perhaps it should be put in the status that it wants to
 		 * exit.
 		 */
 		case PTRACE_KILL:
-			if (child->state == TASK_ZOMBIE)	/* already dead */
-				return 0;
-			wake_up_process (child);
+			/* already dead */
+			ret = 0;
+			if (child->state == TASK_ZOMBIE)
+				break;
 			child->exit_code = SIGKILL;
 			/* make sure single-step breakpoint is gone. */
-			ptrace_cancel_bpt (child);
+			ptrace_cancel_bpt(child);
+			wake_up_process(child);
 			ret = 0;
-			goto out;
+			break;
 
-		case PTRACE_SINGLESTEP:				/* execute single instruction. */
+		/*
+		 * execute single instruction.
+		 */
+		case PTRACE_SINGLESTEP:
 			ret = -EIO;
 			if ((unsigned long) data > _NSIG)
-				goto out;
-			child->tss.debug[4] = -1;
+				break;
+			child->tss.debug.nsaved = -1;
 			child->flags &= ~PF_TRACESYS;
-			wake_up_process(child);
 			child->exit_code = data;
 			/* give it a chance to run. */
+			wake_up_process(child);
 			ret = 0;
-			goto out;
-			
-		case PTRACE_GETREGS:
-		{	/* Get all gp regs from the child. */
-			unsigned char *stack;
+			break;
 
+		/*
+		 * detach a process that was attached.
+		 */
+		case PTRACE_DETACH:
+			ret = -EIO;
+			if ((unsigned long) data > _NSIG)
+				break;
+			child->flags &= ~(PF_PTRACED|PF_TRACESYS);
+			child->exit_code = data;
+			REMOVE_LINKS(child);
+			child->p_pptr = child->p_opptr;
+			SET_LINKS(child);
+			/* make sure single-step breakpoint is gone. */
+			ptrace_cancel_bpt (child);
+			wake_up_process (child);
 			ret = 0;
-			stack = (unsigned char *)((unsigned long)child + 8192 - sizeof(struct pt_regs));
-			if (copy_to_user((void *)data, stack,
+			break;
+
+		/*
+		 * Get all gp regs from the child.
+		 */
+		case PTRACE_GETREGS: {
+			struct pt_regs *regs = get_user_regs(child);
+
+			ret = 0;
+			if (copy_to_user((void *)data, regs,
 					 sizeof(struct pt_regs)))
 				ret = -EFAULT;
 
-			goto out;
-		};
+			break;
+		}
 
-		/* Set all gp regs in the child. */
-		case PTRACE_SETREGS:
-		{
+		/*
+		 * Set all gp regs in the child.
+		 */
+		case PTRACE_SETREGS: {
 			struct pt_regs newregs;
 
 			ret = -EFAULT;
@@ -737,44 +753,103 @@
 					ret = 0;
 				}
 			}
-			goto out;
+			break;
 		}
 
+		/*
+		 * Get the child FPU state.
+		 */
 		case PTRACE_GETFPREGS: 
-			/* Get the child FPU state. */
-			ret = 0;
-			if (copy_to_user((void *)data, &child->tss.fpstate,
-					 sizeof(struct user_fp)))
-				ret = -EFAULT;
-			goto out;
-		
-		case PTRACE_SETFPREGS:
-			/* Set the child FPU state. */
-			ret = 0;
-			if (copy_from_user(&child->tss.fpstate, (void *)data,
-					   sizeof(struct user_fp)))
-				ret = -EFAULT;
-			goto out;
+			ret = -EIO;
+			if (!access_ok(VERIFY_WRITE, (void *)data, sizeof(struct user_fp)))
+				break;
+
+			/* we should check child->used_math here */
+			ret = __copy_to_user((void *)data, &child->tss.fpstate,
+					     sizeof(struct user_fp)) ? -EFAULT : 0;
+			break;
 
-		case PTRACE_DETACH:				/* detach a process that was attached. */
+		/*
+		 * Set the child FPU state.
+		 */
+		case PTRACE_SETFPREGS:
 			ret = -EIO;
-			if ((unsigned long) data > _NSIG)
-				goto out;
-			child->flags &= ~(PF_PTRACED|PF_TRACESYS);
-			wake_up_process (child);
-			child->exit_code = data;
-			REMOVE_LINKS(child);
-			child->p_pptr = child->p_opptr;
-			SET_LINKS(child);
-			/* make sure single-step breakpoint is gone. */
-			ptrace_cancel_bpt (child);
-			ret = 0;
-			goto out;
+			if (!access_ok(VERIFY_READ, (void *)data, sizeof(struct user_fp)))
+				break;
+
+			child->used_math = 1;
+			ret = __copy_from_user(&child->tss.fpstate, (void *)data,
+					   sizeof(struct user_fp)) ? -EFAULT : 0;
+			break;
 
 		default:
 			ret = -EIO;
+			break;
+	}
+
+	return ret;
+}
+
+asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
+{
+	struct task_struct *child;
+	int ret;
+
+	lock_kernel();
+	ret = -EPERM;
+	if (request == PTRACE_TRACEME) {
+		/* are we already being traced? */
+		if (current->flags & PF_PTRACED)
 			goto out;
+		/* set the ptrace bit in the process flags. */
+		current->flags |= PF_PTRACED;
+		ret = 0;
+		goto out;
 	}
+	ret = -ESRCH;
+	if (!(child = find_task_by_pid(pid)))
+		goto out;
+
+	ret = -EPERM;
+	if (pid == 1)		/* you may not mess with init */
+		goto out;
+
+	if (request == PTRACE_ATTACH) {
+		if (child == current)
+			goto out;
+		if ((!child->dumpable ||
+		    (current->uid != child->euid) ||
+		    (current->uid != child->suid) ||
+		    (current->uid != child->uid) ||
+	 	    (current->gid != child->egid) ||
+	 	    (current->gid != child->sgid) ||
+	 	    (current->gid != child->gid)) && !capable(CAP_SYS_PTRACE))
+			goto out;
+		/* the same process cannot be attached many times */
+		if (child->flags & PF_PTRACED)
+			goto out;
+		child->flags |= PF_PTRACED;
+
+		if (child->p_pptr != current) {
+			REMOVE_LINKS(child);
+			child->p_pptr = current;
+			SET_LINKS(child);
+		}
+
+		send_sig(SIGSTOP, child, 1);
+		ret = 0;
+		goto out;
+	}
+	ret = -ESRCH;
+	if (!(child->flags & PF_PTRACED))
+		goto out;
+	if (child->state != TASK_STOPPED && request != PTRACE_KILL)
+		goto out;
+	if (child->p_pptr != current)
+		goto out;
+
+	ret = do_ptrace(request, child, addr, data);
+
 out:
 	unlock_kernel();
 	return ret;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/kernel/signal.c linux.19p18/arch/arm/kernel/signal.c
--- linux.vanilla/arch/arm/kernel/signal.c	Mon Dec 11 22:12:33 2000
+++ linux.19p18/arch/arm/kernel/signal.c	Wed Jan  3 00:57:43 2001
@@ -539,6 +539,7 @@
 				if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
 					notify_parent(current, SIGCHLD);
 				schedule();
+				single_stepping |= ptrace_cancel_bpt(current);
 				continue;
 
 			case SIGQUIT: case SIGILL: case SIGTRAP:
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/lib/delay.S linux.19p18/arch/arm/lib/delay.S
--- linux.vanilla/arch/arm/lib/delay.S	Mon Dec 11 22:12:33 2000
+++ linux.19p18/arch/arm/lib/delay.S	Wed Jan  3 00:57:43 2001
@@ -9,17 +9,24 @@
 
 LC0:		.word	SYMBOL_NAME(loops_per_jiffy)
 
+/*
+ * 0 <= r0 <= 2000
+ */
 ENTRY(udelay)
-		mov	r2, #0x1000
-		orr	r2, r2, #0x00c6
+		mov	r2,     #0x00006800
+		orr	r2, r2, #0x000000db
 		mul	r1, r0, r2
 		ldr	r2, LC0
 		ldr	r2, [r2]
 		mov	r1, r1, lsr #11
 		mov	r2, r2, lsr #11
 		mul	r0, r1, r2
-		movs	r0, r0, lsr #10
+		movs	r0, r0, lsr #6
 		RETINSTR(moveq,pc,lr)
+
+/*
+ * loops = (r0 * 0x10c6 * 100 * loops_per_jiffie) / 2^32
+ */
 
 @ Delay routine
 ENTRY(__delay)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/lib/memset.S linux.19p18/arch/arm/lib/memset.S
--- linux.vanilla/arch/arm/lib/memset.S	Mon Dec 11 22:12:33 2000
+++ linux.19p18/arch/arm/lib/memset.S	Wed Jan  3 00:57:43 2001
@@ -1,88 +1,80 @@
 /*
- * linux/arch/arm/lib/memset.S
+ *  linux/arch/arm/lib/memset.S
  *
- * Copyright (C) 1995-1999 Russell King
+ *  Copyright (C) 1995-2000 Russell King
  *
- * ASM optimised string functions
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
  *
+ *  ASM optimised string functions
  */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
-#include "constants.h"
 
-		.text
-		.align	5
-ENTRY(memset)
-		mov	r3, r0
-		cmp	r2, #16
-		blt	6f
-		ands	ip, r3, #3
-		beq	1f
-		cmp	ip, #2
-		strltb	r1, [r3], #1			@ Align destination
-		strleb	r1, [r3], #1
-		strb	r1, [r3], #1
-		rsb	ip, ip, #4
-		sub	r2, r2, ip
-1:		orr	r1, r1, r1, lsl #8
-		orr	r1, r1, r1, lsl #16
-		cmp	r2, #256
-		blt	4f
-		stmfd	sp!, {r4, r5, lr}
-		mov	r4, r1
-		mov	r5, r1
-		mov	lr, r1
-		mov	ip, r2, lsr #6
-		sub	r2, r2, ip, lsl #6
-2:		stmia	r3!, {r1, r4, r5, lr}		@ 64 bytes at a time.
-		stmia	r3!, {r1, r4, r5, lr}
-		stmia	r3!, {r1, r4, r5, lr}
-		stmia	r3!, {r1, r4, r5, lr}
-		subs	ip, ip, #1
-		bne	2b
-		teq	r2, #0
-		LOADREGS(eqfd, sp!, {r4, r5, pc})	@ Now <64 bytes to go.
-		tst	r2, #32
-		stmneia	r3!, {r1, r4, r5, lr}
-		stmneia	r3!, {r1, r4, r5, lr}
-		tst	r2, #16
-		stmneia	r3!, {r1, r4, r5, lr}
-		ldmia	sp!, {r4, r5}
-3:		tst	r2, #8
-		stmneia	r3!, {r1, lr}
-		tst	r2, #4
-		strne	r1, [r3], #4
-		tst	r2, #2
-		strneb	r1, [r3], #1
-		strneb	r1, [r3], #1
-		tst	r2, #1
-		strneb	r1, [r3], #1
-		LOADREGS(fd, sp!, {pc})
+	.text
+	.align	5
+	.word	0
 
-4:		movs	ip, r2, lsr #3
-		beq	3b
-		sub	r2, r2, ip, lsl #3
-		stmfd	sp!, {lr}
-		mov	lr, r1
-		subs	ip, ip, #4
-5:		stmgeia	r3!, {r1, lr}
-		stmgeia	r3!, {r1, lr}
-		stmgeia	r3!, {r1, lr}
-		stmgeia	r3!, {r1, lr}
-		subges	ip, ip, #4
-		bge	5b
-		tst	ip, #2
-		stmneia	r3!, {r1, lr}
-		stmneia	r3!, {r1, lr}
-		tst	ip, #1
-		stmneia	r3!, {r1, lr}
-		teq	r2, #0
-		LOADREGS(eqfd, sp!, {pc})
-		b	3b
+1:	subs	r2, r2, #4		@ 1 do we have enough
+	blt	5f			@ 1 bytes to align with?
+	cmp	r3, #2			@ 1
+	strltb	r1, [r0], #1		@ 1
+	strleb	r1, [r0], #1		@ 1
+	strb	r1, [r0], #1		@ 1
+	add	r2, r2, r3		@ 1 (r2 = r2 - (4 - r3))
+/*
+ * The pointer is now aligned and the length is adjusted.  Try doing the
+ * memzero again.
+ */
 
-6:		subs	r2, r2, #1
-		strgeb	r1, [r3], #1
-		bgt	6b
-		RETINSTR(mov, pc, lr)
+ENTRY(memset)
+	ands	r3, r0, #3		@ 1 unaligned?
+	bne	1b			@ 1
+/*
+ * we know that the pointer in r0 is aligned to a word boundary.
+ */
+	orr	r1, r1, r1, lsl #8
+	orr	r1, r1, r1, lsl #16
+	mov	r3, r1
+	cmp	r2, #16
+	blt	4f
+/*
+ * We need an extra register for this loop - save the return address and
+ * use the LR
+ */
+	str	lr, [sp, #-4]!
+	mov	ip, r1
+	mov	lr, r1
 
+2:	subs	r2, r2, #64
+	stmgeia	r0!, {r1, r3, ip, lr}	@ 64 bytes at a time.
+	stmgeia	r0!, {r1, r3, ip, lr}
+	stmgeia	r0!, {r1, r3, ip, lr}
+	stmgeia	r0!, {r1, r3, ip, lr}
+	bgt	2b
+	LOADREGS(eqfd, sp!, {pc})	@ Now <64 bytes to go.
+/*
+ * No need to correct the count; we're only testing bits from now on
+ */
+	tst	r2, #32
+	stmneia	r0!, {r1, r3, ip, lr}
+	stmneia	r0!, {r1, r3, ip, lr}
+	tst	r2, #16
+	stmneia	r0!, {r1, r3, ip, lr}
+	ldr	lr, [sp], #4
 
+4:	tst	r2, #8
+	stmneia	r0!, {r1, r3}
+	tst	r2, #4
+	strne	r1, [r0], #4
+/*
+ * When we get here, we've got less than 4 bytes to zero.  We
+ * may have an unaligned pointer as well.
+ */
+5:	tst	r2, #2
+	strneb	r1, [r0], #1
+	strneb	r1, [r0], #1
+	tst	r2, #1
+	strneb	r1, [r0], #1
+	RETINSTR(mov,pc,lr)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/vmlinux-armo.lds linux.19p18/arch/arm/vmlinux-armo.lds
--- linux.vanilla/arch/arm/vmlinux-armo.lds	Mon Dec 11 22:12:33 2000
+++ linux.19p18/arch/arm/vmlinux-armo.lds	Thu Jan  1 01:00:00 1970
@@ -1,69 +0,0 @@
-/* ld script to make ARM Linux kernel
- * taken from the i386 version by Russell King
- * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
- */
-OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")
-OUTPUT_ARCH(arm)
-ENTRY(_start)
-SECTIONS
-{
-  _text = .;			/* Text and read-only data */
-  .text : {
-	*(.text)
-	*(.fixup)
-	*(.gnu.warning)
-	} = 0x9090
-  .text.lock : { *(.text.lock) }	/* out-of-line lock text */
-  .rodata : { *(.rodata) }
-  .kstrtab : { *(.kstrtab) }
-
-  . = ALIGN(16);		/* Exception table */
-  __start___ex_table = .;
-  __ex_table : { *(__ex_table) }
-  __stop___ex_table = .;
-
-  __start___ksymtab = .;	/* Kernel symbol table */
-  __ksymtab : { *(__ksymtab) }
-  __stop___ksymtab = .;
-
-  _etext = .;			/* End of text section */
-
-  . = ALIGN(8192);
-  .data : {			/* Data */
-	*(.init.task)
-	*(.data)
-	CONSTRUCTORS
-	}
-
-  _edata = .;			/* End of data section */
-
-  . = ALIGN(32768);		/* Init code and data */
-  __init_begin = .;
-  .text.init : { *(.text.init) }
-  .data.init : { *(.data.init) }
-  . = ALIGN(16);		/* __setup() commandline parameters */
-  __setup_start = .;
-  .setup.init : { *(.setup.init) }
-  __setup_end = .;
-  __initcall_start = .;		/* the init functions to be called */
-  .initcall.init : { *(.initcall.init) }
-  __initcall_end = .;
-  . = ALIGN(32768);
-  __init_end = .;
-
-
-  __bss_start = .;		/* BSS */
-  .bss : {
-	*(.bss)
-	}
-  _end = . ;
-
-  /* Stabs debugging sections.  */
-  .stab 0 : { *(.stab) }
-  .stabstr 0 : { *(.stabstr) }
-  .stab.excl 0 : { *(.stab.excl) }
-  .stab.exclstr 0 : { *(.stab.exclstr) }
-  .stab.index 0 : { *(.stab.index) }
-  .stab.indexstr 0 : { *(.stab.indexstr) }
-  .comment 0 : { *(.comment) }
-}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/arm/vmlinux-armv.lds linux.19p18/arch/arm/vmlinux-armv.lds
--- linux.vanilla/arch/arm/vmlinux-armv.lds	Mon Dec 11 22:12:33 2000
+++ linux.19p18/arch/arm/vmlinux-armv.lds	Thu Jan  1 01:00:00 1970
@@ -1,70 +0,0 @@
-/* ld script to make ARM Linux kernel
- * taken from the i386 version by Russell King
- * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
- */
-OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")
-OUTPUT_ARCH(arm)
-ENTRY(_start)
-SECTIONS
-{
-  _text = .;			/* Text and read-only data */
-  .text : {
-	*(.text)
-	*(.fixup)
-	*(.gnu.warning)
-	} = 0x9090
-  .text.lock : { *(.text.lock) }	/* out-of-line lock text */
-  .rodata : { *(.rodata) }
-  .kstrtab : { *(.kstrtab) }
-
-  . = ALIGN(16);		/* Exception table */
-  __start___ex_table = .;
-  __ex_table : { *(__ex_table) }
-  __stop___ex_table = .;
-
-  __start___ksymtab = .;	/* Kernel symbol table */
-  __ksymtab : { *(__ksymtab) }
-  __stop___ksymtab = .;
-
-  _etext = .;			/* End of text section */
-
-  . = ALIGN(8192);
-  .data : {			/* Data */
-	*(.init.task)
-	*(.data)
-	CONSTRUCTORS
-	}
-
-  _edata = .;			/* End of data section */
-
-  . = ALIGN(4096);		/* Init code and data */
-  __init_begin = .;
-  .text.init : { *(.text.init) }
-  .data.init : { *(.data.init) }
-  . = ALIGN(16);		/* __setup() commandline parameters */
-  __setup_start = .;
-  .setup.init : { *(.setup.init) }
-  __setup_end = .;
- 
-  __initcall_start = .;		/* the init functions to be called */
-  .initcall.init : { *(.initcall.init) }
-  __initcall_end = .;
-  . = ALIGN(4096);
-  __init_end = .;
-
-
-  __bss_start = .;		/* BSS */
-  .bss : {
-	*(.bss)
-	}
-  _end = . ;
-
-  /* Stabs debugging sections.  */
-  .stab 0 : { *(.stab) }
-  .stabstr 0 : { *(.stabstr) }
-  .stab.excl 0 : { *(.stab.excl) }
-  .stab.exclstr 0 : { *(.stab.exclstr) }
-  .stab.index 0 : { *(.stab.index) }
-  .stab.indexstr 0 : { *(.stab.indexstr) }
-  .comment 0 : { *(.comment) }
-}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/boot/setup.S linux.19p18/arch/i386/boot/setup.S
--- linux.vanilla/arch/i386/boot/setup.S	Mon Dec 11 22:12:33 2000
+++ linux.19p18/arch/i386/boot/setup.S	Thu Feb  1 15:07:58 2001
@@ -32,7 +32,7 @@
 !
 !
 ! A20 gating fiddled to work on AMD Elan AmSC4xx series by kira@linuxgrrls.org
-! july 1999
+! july 1999 - from a 2.0 patch by Christian Lademann <cal@zls.de>
 !
 
 #define __ASSEMBLY__
@@ -248,16 +248,46 @@
 
 loader_ok:
 ! Get memory size (extended mem, kB)
-
+	xor     eax, eax
+	mov     [0x1e0], eax
 #ifndef STANDARD_MEMORY_BIOS_CALL
-	push	ebx
+	mov     [0x1e8], al
+meme820:
+	xor     ebx, ebx
+	mov     di,#0x2d0
+
+jmpe820:
+	mov     eax,#0x0000e820
+	mov     edx,#0x534d4150		! Some biosen trash edx each call
+	mov     ecx,#20
+	push    ds
+	pop     es
+	int     0x15
+	jc      bail820
 
-        xor     ebx,ebx		! preload new memory slot with 0k
-        mov	[0x1e0], ebx
+	cmp     eax,#0x534d4150
+	jne     bail820
 
-        mov     ax,#0xe801
-	int     0x15
-	jc      oldstylemem
+	cmp     16(di),#1
+	jne     again820
+
+good820:
+	mov     al,[0x1e8]
+	cmp     al,#32
+	jnl     bail820
+
+	incb    [0x1e8]
+	mov     ax,di
+	add     ax,#20
+	mov     di,ax
+again820:
+	cmp     ebx,#0
+	jne     jmpe820
+bail820:
+meme801:
+	mov	ax,#0xe801
+	int	0x15
+	jc	mem88
 
 ! Memory size is in 1 k chunksizes, to avoid confusing loadlin.
 ! We store the 0xe801 memory size in a completely different place,
@@ -266,23 +296,19 @@
 ! alternative new memory detection scheme, and it's sensible
 ! to write everything into the same place.)
 
-	and     ebx, #0xffff    ! clear sign extend
-	shl     ebx, 6          ! and go from 64k to 1k chunks
-	mov     [0x1e0],ebx     ! store extended memory size
-
-	and     eax, #0xffff    ! clear sign extend
- 	add     [0x1e0],eax     ! and add lower memory into total size.
-  
-	! and fall into the old memory detection code to populate the
-	! compatibility slot.
+	and 	ebx, #0xffff	! clear sign extend
+	shl	ebx, 6		! and go from 64k to 1k chunks
+	mov	[0x1e0],ebx	! store extented memory size
+	
+	and	eax, #0xffff	! clear sign extend
+	add	[0x1e0],eax	! and add lower memory into total size. 
 
-oldstylemem:
-	pop	ebx
-#else
-	mov     dword ptr [0x1e0], #0
+	! and fall into the old memory detection to populate the
+	! compatibility slot.	
+mem88:
 #endif
-	mov	ah,#0x88
-	int	0x15
+        mov     ah,#0x88
+        int     0x15
 	mov	[2],ax
 
 ! Set the keyboard repeat rate to the max
@@ -552,46 +578,44 @@
 	lgdt	gdt_48		! load gdt with whatever appropriate
 
 ! that was painless, now we enable A20
-
-! if this is SC410 or a few other bits we need to do it with the 'fast' method
-
-        in      al,#0x92        ! read "System Control Port A"
-        or      al,#0x02        ! Set "Alternate Gate A20" - Bit
-        out     #0x92,al        ! write "System Control Port A"
+	call	empty_8042
 
 ! do it the normal way too, so as not to upset normal machines
-
-	call	empty_8042
 	mov	al,#0xD1		! command write
 	out	#0x64,al
 	call	empty_8042
+
 	mov	al,#0xDF		! A20 on
 	out	#0x60,al
 	call	empty_8042
 
+! if this is SC410 or a few other bits we need to do it with the 'fast' method
+!
+!	You must preserve the other bits here. Otherwise embarrasing things
+!	like laptops powering off on boot happen. Corrected version by Kira
+!	Brown from Linux 2.2
+
+        in      al,#0x92        ! read "System Control Port A"
+        or      al,#0x02        ! Set "Alternate Gate A20" - Bit
+        out     #0x92,al        ! write "System Control Port A"
+
 ! wait until a20 really *is* enabled; it can take a fair amount of
 ! time on certain systems; Toshiba Tecras are known to have this
-! problem.  The memory location used here is the int 0x1f vector,
-! which should be safe to use; any *unused* memory location < 0xfff0
-! should work here.  
+! problem.  The memory location used here (0x200) is the int 0x80
+! vector, which should be safe to use.
 
-#define	TEST_ADDR 0x7c
-
-	push	ds
 	xor	ax,ax			! segment 0x0000
-	mov	ds,ax
+	mov	fs,ax
 	dec	ax			! segment 0xffff (HMA)
 	mov	gs,ax
-	mov	bx,[TEST_ADDR]		! we want to restore the value later
 a20_wait:
-	inc	ax
-	mov	[TEST_ADDR],ax
+	inc	ax			! unused memory location <0xfff0
+	seg	fs
+	mov	[0x200],ax		! we use the "int 0x80" vector
 	seg	gs
-	cmp	ax,[TEST_ADDR+0x10]
+	cmp	ax,[0x210]		! and its corresponding HMA addr
 	je	a20_wait		! loop until no longer aliased
-	mov	[TEST_ADDR],bx		! restore original value
-	pop	ds
-		
+
 ! make sure any possible coprocessor is properly reset..
 
 	xor	ax,ax
@@ -771,10 +795,17 @@
 !
 ! Some machines have delusions that the keyboard buffer is always full
 ! with no keyboard attached...
+!
+! If there is no keyboard controller, we will usually get 0xff
+! to all the reads.  With each IO taking a microsecond and
+! a timeout of 100,000 iterations, this can take about half a
+! second ("delay" == outb to port 0x80). That should be ok,
+! and should also be plenty of time for a real keyboard controller
+! to empty.
 
 empty_8042:
        push    ecx
-       mov     ecx,#0xFFFFFF
+       mov     ecx,#100000
 
 empty_8042_loop:
        dec     ecx
@@ -814,7 +845,7 @@
 ! Delay is needed after doing I/O
 !
 delay:
-	.word	0x00eb			! jmp $+2
+	out	#0x80,al
 	ret
 
 !
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/config.in linux.19p18/arch/i386/config.in
--- linux.vanilla/arch/i386/config.in	Mon Dec 11 22:12:33 2000
+++ linux.19p18/arch/i386/config.in	Wed Dec 13 22:53:39 2000
@@ -12,11 +12,11 @@
 mainmenu_option next_comment
 comment 'Processor type and features'
 choice 'Processor family' \
-	"386			CONFIG_M386	\
-	 486/Cx486		CONFIG_M486	\
-	 586/K5/5x86/6x86	CONFIG_M586	\
-	 Pentium/K6/TSC		CONFIG_M586TSC	\
-	 PPro/6x86MX		CONFIG_M686" PPro
+	"386				CONFIG_M386	\
+	 486/Cx486			CONFIG_M486	\
+	 586/K5/5x86/6x86		CONFIG_M586	\
+	 Pentium/K6/TSC/CyrixIII	CONFIG_M586TSC	\
+	 PPro/6x86MX			CONFIG_M686" PPro
 #
 # Define implied options from the CPU selection here
 #
@@ -33,7 +33,7 @@
   define_bool CONFIG_X86_GOOD_APIC y
 fi
 
-tristate '/dev/cpu/microcode - Intel P6 CPU microcode support' CONFIG_MICROCODE
+tristate '/dev/cpu/microcode - Intel IA32 CPU microcode support' CONFIG_MICROCODE
 tristate '/dev/cpu/*/msr - Model-specific register support' CONFIG_X86_MSR
 tristate '/dev/cpu/*/cpuid - CPU information support' CONFIG_X86_CPUID
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/defconfig linux.19p18/arch/i386/defconfig
--- linux.vanilla/arch/i386/defconfig	Mon Dec 11 22:12:33 2000
+++ linux.19p18/arch/i386/defconfig	Thu Feb 15 16:20:36 2001
@@ -21,6 +21,9 @@
 CONFIG_X86_POPAD_OK=y
 CONFIG_X86_TSC=y
 CONFIG_X86_GOOD_APIC=y
+# CONFIG_MICROCODE is not set
+# CONFIG_X86_MSR is not set
+# CONFIG_X86_CPUID is not set
 CONFIG_1GB=y
 # CONFIG_2GB is not set
 # CONFIG_MATH_EMULATION is not set
@@ -58,6 +61,7 @@
 CONFIG_BINFMT_MISC=y
 # CONFIG_PARPORT is not set
 # CONFIG_APM is not set
+# CONFIG_TOSHIBA is not set
 
 #
 # Plug and Play support
@@ -100,6 +104,7 @@
 CONFIG_PARIDE_PARPORT=y
 # CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -133,6 +138,11 @@
 # CONFIG_ATALK is not set
 
 #
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
 # Telephony Support
 #
 # CONFIG_PHONE is not set
@@ -148,6 +158,7 @@
 #
 CONFIG_BLK_DEV_SD=y
 # CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
 # CONFIG_BLK_DEV_SR is not set
 # CONFIG_CHR_DEV_SG is not set
 
@@ -166,7 +177,6 @@
 # CONFIG_SCSI_AHA152X is not set
 # CONFIG_SCSI_AHA1542 is not set
 # CONFIG_SCSI_AHA1740 is not set
-# CONFIG_SCSI_AACRAID is not set
 # CONFIG_SCSI_AIC7XXX is not set
 # CONFIG_SCSI_IPS is not set
 # CONFIG_SCSI_ADVANSYS is not set
@@ -174,6 +184,7 @@
 # CONFIG_SCSI_AM53C974 is not set
 # CONFIG_SCSI_MEGARAID is not set
 # CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_CPQFCTS is not set
 # CONFIG_SCSI_DTC3280 is not set
 # CONFIG_SCSI_EATA is not set
 # CONFIG_SCSI_EATA_DMA is not set
@@ -192,7 +203,6 @@
 CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=4
 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
 CONFIG_SCSI_NCR53C8XX_SYNC=20
-# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
 # CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
 # CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
 # CONFIG_SCSI_PAS16 is not set
@@ -209,6 +219,14 @@
 # CONFIG_SCSI_ULTRASTOR is not set
 
 #
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_PCI is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_SCSI is not set
+
+#
 # Network device support
 #
 CONFIG_NETDEVICES=y
@@ -218,6 +236,7 @@
 #
 # CONFIG_ARCNET is not set
 CONFIG_DUMMY=m
+# CONFIG_BONDING is not set
 # CONFIG_EQUALIZER is not set
 # CONFIG_NET_SB1000 is not set
 
@@ -233,8 +252,8 @@
 CONFIG_NET_EISA=y
 # CONFIG_PCNET32 is not set
 # CONFIG_APRICOT is not set
+# CONFIG_LP486E is not set
 # CONFIG_CS89x0 is not set
-# CONFIG_DM9102 is not set
 # CONFIG_DE4X5 is not set
 # CONFIG_DEC_ELCP is not set
 # CONFIG_DEC_ELCP_OLD is not set
@@ -267,9 +286,12 @@
 # CONFIG_HOSTESS_SV11 is not set
 # CONFIG_COSA is not set
 # CONFIG_SEALEVEL_4021 is not set
+# CONFIG_SYNCLINK_SYNCPPP is not set
+# CONFIG_LANMEDIA is not set
 # CONFIG_COMX is not set
 # CONFIG_DLCI is not set
 # CONFIG_WAN_DRIVERS is not set
+# CONFIG_XPEED is not set
 # CONFIG_SBNI is not set
 
 #
@@ -323,6 +345,7 @@
 # CONFIG_WATCHDOG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
+# CONFIG_INTEL_RNG is not set
 
 #
 # Video For Linux
@@ -336,6 +359,11 @@
 # CONFIG_FTAPE is not set
 
 #
+# USB support
+#
+# CONFIG_USB is not set
+
+#
 # Filesystems
 #
 # CONFIG_QUOTA is not set
@@ -363,6 +391,8 @@
 #
 # CONFIG_CODA_FS is not set
 CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFSD is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 # CONFIG_SMB_FS is not set
@@ -373,6 +403,7 @@
 #
 # CONFIG_BSD_DISKLABEL is not set
 # CONFIG_MAC_PARTITION is not set
+# CONFIG_MINIX_SUBPARTITION is not set
 # CONFIG_SMD_DISKLABEL is not set
 # CONFIG_SOLARIS_X86_PARTITION is not set
 # CONFIG_NLS is not set
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/Makefile linux.19p18/arch/i386/kernel/Makefile
--- linux.vanilla/arch/i386/kernel/Makefile	Mon Dec 11 22:12:33 2000
+++ linux.19p18/arch/i386/kernel/Makefile	Thu Feb  1 15:00:52 2001
@@ -15,8 +15,8 @@
 O_TARGET := kernel.o
 O_OBJS   := process.o signal.o entry.o traps.o irq.o vm86.o \
             ptrace.o ioport.o ldt.o setup.o time.o sys_i386.o \
-	    bluesmoke.o dmi_scan.o
-OX_OBJS  := i386_ksyms.o
+	    bluesmoke.o
+OX_OBJS  := i386_ksyms.o dmi_scan.o
 MX_OBJS  :=
 
 ifdef CONFIG_PCI
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/apm.c linux.19p18/arch/i386/kernel/apm.c
--- linux.vanilla/arch/i386/kernel/apm.c	Mon Dec 11 22:12:33 2000
+++ linux.19p18/arch/i386/kernel/apm.c	Wed Feb  7 09:42:47 2001
@@ -36,6 +36,7 @@
  * Oct 1999, Version 1.10
  * Nov 1999, Version 1.11
  * Jan 2000, Version 1.12
+ * Feb 2000, Version 1.13
  *
  * History:
  *    0.6b: first version in official kernel, Linux 1.3.46
@@ -55,7 +56,7 @@
  *         The new replacment for it is, but Linux doesn't yet support this.
  *         Alan Cox Linux 2.1.55
  *    1.3: Set up a valid data descriptor 0x40 for buggy BIOS's
- *    1.4: Upgraded to support APM 1.2. Integrated ThinkPad suspend patch by 
+ *    1.4: Upgraded to support APM 1.2. Integrated ThinkPad suspend patch by
  *         Dean Gaudet <dgaudet@arctic.org>.
  *         C. Scott Ananian <cananian@alumni.princeton.edu> Linux 2.1.87
  *    1.5: Fix segment register reloading (in case of bad segments saved
@@ -127,7 +128,7 @@
  *         scripts that check for it before doing power off
  *         work (Jim Avera <jima@hal.com>).
  *   1.13: Fix the Thinkpad (again) :-( (CONFIG_APM_IGNORE_MULTIPLE_SUSPENDS
- *         is now the way life works). 
+ *         is now the way life works).
  *         Fix thinko in suspend() (wrong return).
  *   1.13ac: Added apm_battery_horked() for Compal boards (Dell 5000e etc)
  *
@@ -242,8 +243,8 @@
 
 /*
  * Define to re-initialize the interrupt 0 timer to 100 Hz after a suspend.
- * This patched by Chad Miller <cmiller@surfsouth.com>, orig code by David 
- * Chen <chen@ctpa04.mit.edu>
+ * This patched by Chad Miller <cmiller@surfsouth.com>, original code by
+ * David Chen <chen@ctpa04.mit.edu>
  */
 #undef INIT_TIMER_AFTER_SUSPEND
 
@@ -326,7 +327,6 @@
 #else
 static int			power_off_enabled = 1;
 #endif
-static int 			dell_crap = 0;	/*Set if we find a 5000e */
 
 static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
 static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
@@ -522,7 +522,7 @@
 			&dummy, &dummy))
 		return (eax >> 8) & 0xff;
 	*event = ebx;
-	if (apm_bios_info.version < 0x0102)
+	if (apm_info.connection_version < 0x0102)
 		*info = ~0; /* indicate info not valid */
 	else
 		*info = ecx;
@@ -554,7 +554,7 @@
 #ifdef ALWAYS_CALL_BUSY
 	clock_slowed = 1;
 #else
-	clock_slowed = (apm_bios_info.flags & APM_IDLE_SLOWS_CLOCK) != 0;
+	clock_slowed = (apm_info.bios.flags & APM_IDLE_SLOWS_CLOCK) != 0;
 #endif
 	return 1;
 }
@@ -620,7 +620,7 @@
 	 * This may be called on an SMP machine.
 	 */
 #ifdef CONFIG_SMP
-	/* Many bioses don't like being called from CPU != 0 */
+	/* Some bioses don't like being called from CPU != 0 */
 	while (cpu_number_map[smp_processor_id()] != 0) {
 		kernel_thread(apm_magic, NULL,
 			CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
@@ -638,15 +638,15 @@
 {
 	u32	eax;
 
-	if ((enable == 0) && (apm_bios_info.flags & APM_BIOS_DISENGAGED))
+	if ((enable == 0) && (apm_info.bios.flags & APM_BIOS_DISENGAGED))
 		return APM_NOT_ENGAGED;
 	if (apm_bios_call_simple(APM_FUNC_ENABLE_PM, APM_DEVICE_BALL,
 			enable, &eax))
 		return (eax >> 8) & 0xff;
 	if (enable)
-		apm_bios_info.flags &= ~APM_BIOS_DISABLED;
+		apm_info.bios.flags &= ~APM_BIOS_DISABLED;
 	else
-		apm_bios_info.flags |= APM_BIOS_DISABLED;
+		apm_info.bios.flags |= APM_BIOS_DISABLED;
 	return APM_SUCCESS;
 }
 
@@ -658,6 +658,8 @@
 	u32	edx;
 	u32	dummy;
 
+	if (apm_info.get_power_status_broken)
+		return APM_32_UNSUPPORTED;
 	if (apm_bios_call(APM_FUNC_GET_STATUS, APM_DEVICE_ALL, 0,
 			&eax, &ebx, &ecx, &edx, &dummy))
 		return (eax >> 8) & 0xff;
@@ -677,7 +679,7 @@
 	u32	edx;
 	u32	esi;
 
-	if (apm_bios_info.version < 0x0102) {
+	if (apm_info.connection_version < 0x0102) {
 		/* pretend we only have one battery. */
 		if (which != 1)
 			return APM_BAD_DEVICE;
@@ -701,15 +703,15 @@
 	u32	eax;
 
 	if ((enable == 0) && (device == APM_DEVICE_ALL)
-	    && (apm_bios_info.flags & APM_BIOS_DISABLED))
+	    && (apm_info.bios.flags & APM_BIOS_DISABLED))
 		return APM_DISABLED;
 	if (apm_bios_call_simple(APM_FUNC_ENGAGE_PM, device, enable, &eax))
 		return (eax >> 8) & 0xff;
 	if (device == APM_DEVICE_ALL) {
 		if (enable)
-			apm_bios_info.flags &= ~APM_BIOS_DISENGAGED;
+			apm_info.bios.flags &= ~APM_BIOS_DISENGAGED;
 		else
-			apm_bios_info.flags |= APM_BIOS_DISENGAGED;
+			apm_info.bios.flags |= APM_BIOS_DISENGAGED;
 	}
 	return APM_SUCCESS;
 }
@@ -931,7 +933,7 @@
 		if (call->callback(event) && undo) {
 			for (fix = callback_list; fix != call; fix = fix->next)
 				fix->callback(undo);
-			if (apm_bios_info.version > 0x100)
+			if (apm_info.connection_version > 0x100)
 				apm_set_power_state(APM_STATE_REJECT);
 			return 0;
 		}
@@ -974,7 +976,7 @@
 
 		case APM_USER_SUSPEND:
 #ifdef CONFIG_APM_IGNORE_USER_SUSPEND
-			if (apm_bios_info.version > 0x100)
+			if (apm_info.connection_version > 0x100)
 				apm_set_power_state(APM_STATE_REJECT);
 			break;
 #endif
@@ -1035,7 +1037,7 @@
 	int		err;
 
 	if ((standbys_pending > 0) || (suspends_pending > 0)) {
-		if ((apm_bios_info.version > 0x100) && (pending_count-- <= 0)) {
+		if ((apm_info.connection_version > 0x100) && (pending_count-- <= 0)) {
 			pending_count = 4;
 			if (debug)
 				printk(KERN_DEBUG "apm: setting state busy\n");
@@ -1244,18 +1246,6 @@
 	return 0;
 }
 
-/*
- *	This is called by the DMI code when it finds an Inspiron 5000e
- *	(aka compal reference board). We actually do the check by the BIOS
- *	vendor name, version and serial so we can extend it to try and catch
- *	non Dell stuff later.
- */
- 
-void apm_battery_horked(void)
-{
-	dell_crap = 1;
-}
-
 static int apm_get_info(char *buf, char **start, off_t fpos, int length, int dummy)
 {
 	char *		p;
@@ -1272,14 +1262,14 @@
 
 	p = buf;
 
-	if ((smp_num_cpus == 1) && (!dell_crap) && 
+	if ((smp_num_cpus == 1) &&
 	    !(error = apm_get_power_status(&bx, &cx, &dx))) {
 		ac_line_status = (bx >> 8) & 0xff;
 		battery_status = bx & 0xff;
 		if ((cx & 0xff) != 0xff)
 			percentage = cx & 0xff;
 
-		if (apm_bios_info.version > 0x100) {
+		if (apm_info.connection_version > 0x100) {
 			battery_flag = (cx >> 8) & 0xff;
 			if (dx != 0xffff) {
 				units = (dx & 0x8000) ? "min" : "sec";
@@ -1327,9 +1317,9 @@
 
 	p += sprintf(p, "%s %d.%d 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
 		     driver_version,
-		     (apm_bios_info.version >> 8) & 0xff,
-		     apm_bios_info.version & 0xff,
-		     apm_bios_info.flags,
+		     (apm_info.bios.version >> 8) & 0xff,
+		     apm_info.bios.version & 0xff,
+		     apm_info.bios.flags,
 		     ac_line_status,
 		     battery_status,
 		     battery_flag,
@@ -1349,22 +1339,28 @@
 	char *		power_stat;
 	char *		bat_stat;
 
-	if (apm_bios_info.version > 0x100) {
-		/*
-		 * We only support BIOSs up to version 1.2
-		 */
-		if (apm_bios_info.version > 0x0102)
-			apm_bios_info.version = 0x0102;
-		if (apm_driver_version(&apm_bios_info.version) != APM_SUCCESS) {
-			/* Fall back to an APM 1.0 connection. */
-			apm_bios_info.version = 0x100;
+	if (apm_info.connection_version == 0) {
+		apm_info.connection_version = apm_info.bios.version;
+		if (apm_info.connection_version > 0x100) {
+			/*
+			 * We only support BIOSs up to version 1.2
+			 */
+			if (apm_info.connection_version > 0x0102)
+				apm_info.connection_version = 0x0102;
+			error = apm_driver_version(&apm_info.connection_version);
+			if (error != APM_SUCCESS) {
+				apm_error("driver version", error);
+				/* Fall back to an APM 1.0 connection. */
+				apm_info.connection_version = 0x100;
+			}
 		}
 	}
-	if (debug && (smp_num_cpus == 1)) {
+	if (debug)
 		printk(KERN_INFO "apm: Connection version %d.%d\n",
-			(apm_bios_info.version >> 8) & 0xff,
-			apm_bios_info.version & 0xff);
+			(apm_info.connection_version >> 8) & 0xff,
+			apm_info.connection_version & 0xff);
 
+	if (debug && (smp_num_cpus == 1)) {
 		error = apm_get_power_status(&bx, &cx, &dx);
 		if (error)
 			printk(KERN_INFO "apm: power status not available\n");
@@ -1389,7 +1385,7 @@
 				printk("unknown\n");
 			else
 				printk("%d%%\n", cx & 0xff);
-			if (apm_bios_info.version > 0x100) {
+			if (apm_info.connection_version > 0x100) {
 				printk(KERN_INFO
 				       "apm: battery flag 0x%02x, battery life ",
 				       (cx >> 8) & 0xff);
@@ -1404,7 +1400,7 @@
 	}
 
 #ifdef CONFIG_APM_DO_ENABLE
-	if (apm_bios_info.flags & APM_BIOS_DISABLED) {
+	if (apm_info.bios.flags & APM_BIOS_DISABLED) {
 		/*
 		 * This call causes my NEC UltraLite Versa 33/C to hang if it
 		 * is booted with PM disabled but not in the docking station.
@@ -1417,8 +1413,8 @@
 		}
 	}
 #endif
-	if ((apm_bios_info.flags & APM_BIOS_DISENGAGED)
-	    && (apm_bios_info.version > 0x0100)) {
+	if ((apm_info.bios.flags & APM_BIOS_DISENGAGED)
+	    && (apm_info.connection_version > 0x0100)) {
 		error = apm_engage_power_management(APM_DEVICE_ALL, 1);
 		if (error) {
 			apm_error("engage power management", error);
@@ -1482,17 +1478,17 @@
 
 static int __init apm_init(void)
 {
-	if (apm_bios_info.version == 0) {
+	if (apm_info.bios.version == 0) {
 		printk(KERN_INFO "apm: BIOS not found.\n");
 		return -ENODEV;
 	}
 	printk(KERN_INFO
 		"apm: BIOS version %d.%d Flags 0x%02x (Driver version %s)\n",
-		((apm_bios_info.version >> 8) & 0xff),
-		(apm_bios_info.version & 0xff),
-		apm_bios_info.flags,
+		((apm_info.bios.version >> 8) & 0xff),
+		(apm_info.bios.version & 0xff),
+		apm_info.bios.flags,
 		driver_version);
-	if ((apm_bios_info.flags & APM_32_BIT_SUPPORT) == 0) {
+	if ((apm_info.bios.flags & APM_32_BIT_SUPPORT) == 0) {
 		printk(KERN_INFO "apm: no 32 bit BIOS support\n");
 		return -ENODEV;
 	}
@@ -1501,23 +1497,23 @@
 	 * Fix for the Compaq Contura 3/25c which reports BIOS version 0.1
 	 * but is reportedly a 1.0 BIOS.
 	 */
-	if (apm_bios_info.version == 0x001)
-		apm_bios_info.version = 0x100;
+	if (apm_info.bios.version == 0x001)
+		apm_info.bios.version = 0x100;
 
 	/* BIOS < 1.2 doesn't set cseg_16_len */
-	if (apm_bios_info.version < 0x102)
-		apm_bios_info.cseg_16_len = 0; /* 64k */
+	if (apm_info.bios.version < 0x102)
+		apm_info.bios.cseg_16_len = 0; /* 64k */
 
 	if (debug) {
 		printk(KERN_INFO "apm: entry %x:%lx cseg16 %x dseg %x",
-			apm_bios_info.cseg, apm_bios_info.offset,
-			apm_bios_info.cseg_16, apm_bios_info.dseg);
-		if (apm_bios_info.version > 0x100)
+			apm_info.bios.cseg, apm_info.bios.offset,
+			apm_info.bios.cseg_16, apm_info.bios.dseg);
+		if (apm_info.bios.version > 0x100)
 			printk(" cseg len %x, dseg len %x",
-				apm_bios_info.cseg_len,
-				apm_bios_info.dseg_len);
-		if (apm_bios_info.version > 0x101)
-			printk(" cseg16 len %x", apm_bios_info.cseg_16_len);
+				apm_info.bios.cseg_len,
+				apm_info.bios.dseg_len);
+		if (apm_info.bios.version > 0x101)
+			printk(" cseg16 len %x", apm_info.bios.cseg_16_len);
 		printk("\n");
 	}
 
@@ -1540,16 +1536,16 @@
 		 __va((unsigned long)0x40 << 4));
 	_set_limit((char *)&gdt[APM_40 >> 3], 4095 - (0x40 << 4));
 
-	apm_bios_entry.offset = apm_bios_info.offset;
+	apm_bios_entry.offset = apm_info.bios.offset;
 	apm_bios_entry.segment = APM_CS;
 	set_base(gdt[APM_CS >> 3],
-		 __va((unsigned long)apm_bios_info.cseg << 4));
+		 __va((unsigned long)apm_info.bios.cseg << 4));
 	set_base(gdt[APM_CS_16 >> 3],
-		 __va((unsigned long)apm_bios_info.cseg_16 << 4));
+		 __va((unsigned long)apm_info.bios.cseg_16 << 4));
 	set_base(gdt[APM_DS >> 3],
-		 __va((unsigned long)apm_bios_info.dseg << 4));
+		 __va((unsigned long)apm_info.bios.dseg << 4));
 #ifndef APM_RELAX_SEGMENTS
-	if (apm_bios_info.version == 0x100) {
+	if (apm_info.bios.version == 0x100) {
 #endif
 		/* For ASUS motherboard, Award BIOS rev 110 (and others?) */
 		_set_limit((char *)&gdt[APM_CS >> 3], 64 * 1024 - 1);
@@ -1560,11 +1556,11 @@
 #ifndef APM_RELAX_SEGMENTS
 	} else {
 		_set_limit((char *)&gdt[APM_CS >> 3],
-			(apm_bios_info.cseg_len - 1) & 0xffff);
+			(apm_info.bios.cseg_len - 1) & 0xffff);
 		_set_limit((char *)&gdt[APM_CS_16 >> 3],
-			(apm_bios_info.cseg_16_len - 1) & 0xffff);
+			(apm_info.bios.cseg_16_len - 1) & 0xffff);
 		_set_limit((char *)&gdt[APM_DS >> 3],
-			(apm_bios_info.dseg_len - 1) & 0xffff);
+			(apm_info.bios.dseg_len - 1) & 0xffff);
 	}
 #endif
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/cpuid.c linux.19p18/arch/i386/kernel/cpuid.c
--- linux.vanilla/arch/i386/kernel/cpuid.c	Mon Dec 11 22:12:33 2000
+++ linux.19p18/arch/i386/kernel/cpuid.c	Thu Dec 21 23:02:19 2000
@@ -152,6 +152,7 @@
 
 static void cpuid_exit(void)
 {
+  unregister_chrdev(CPUID_MAJOR, "cpu/cpuid");
 }
 
 module_init(cpuid_init);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/dmi_scan.c linux.19p18/arch/i386/kernel/dmi_scan.c
--- linux.vanilla/arch/i386/kernel/dmi_scan.c	Mon Dec 11 22:12:33 2000
+++ linux.19p18/arch/i386/kernel/dmi_scan.c	Wed Feb  7 09:42:47 2001
@@ -1,8 +1,8 @@
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/init.h>
+#include <linux/apm_bios.h>
 #include <asm/io.h>
 
 struct dmi_header
@@ -125,17 +125,19 @@
 			 *	< Does it Boot Win98 >-N--
 			 *               |Y
 			 *           [Ship It]
+			 *
+			 *	Phoenix A04  08/24/2000 is known bad (Dell Inspiron 5000e)
+			 *	Phoenix A07  09/29/2000 is known good (Dell Inspiron 5000)
 			 */
 			 
-			if(strcmp(dmi_string(dm, data[4]), "Phoenix Technologies LTD")==0 &&
-			   strcmp(dmi_string(dm, data[5]), "A04")==0 &&
-			   strcmp(dmi_string(dm, data[8]), "08/24/2000")==0)
+			if(strcmp(dmi_string(dm, data[4]), "Phoenix Technologies LTD")==0)
 			{
-#ifdef CONFIG_APM
-				extern void apm_battery_horked(void);
-			   	apm_battery_horked();			   	
-			   	printk(KERN_WARNING "BIOS strings suggest APM bugs, disabling battery reporting.\n");
-#endif			   	
+				if(strcmp(dmi_string(dm, data[5]), "A04")==0 
+					&& strcmp(dmi_string(dm, data[8]), "08/24/2000")==0)
+				{
+				   	apm_info.get_power_status_broken = 1;
+					printk(KERN_WARNING "BIOS strings suggest APM bugs, disabling power status reporting.\n");
+				}
 			}
 			break;
 #ifdef DUMP_DMI
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/entry.S linux.19p18/arch/i386/kernel/entry.S
--- linux.vanilla/arch/i386/kernel/entry.S	Sat Sep  9 18:42:32 2000
+++ linux.19p18/arch/i386/kernel/entry.S	Tue Dec 19 02:14:13 2000
@@ -267,16 +267,18 @@
 	pushl %ebx
 	cld
 	movl %es,%cx
-	xchgl %eax, ORIG_EAX(%esp)	# orig_eax (get the error code. )
+	movl ORIG_EAX(%esp), %esi	# get the error code
+	movl ES(%esp), %edi		# get the function address
+	movl %eax, ORIG_EAX(%esp)
+	movl %ecx, ES(%esp)
 	movl %esp,%edx
-	xchgl %ecx, ES(%esp)		# get the address and save es.
-	pushl %eax			# push the error code
-	pushl %edx
+	pushl %esi			# push the error code
+	pushl %edx			# push the pt_regs pointer
 	movl $(__KERNEL_DS),%edx
 	movl %dx,%ds
 	movl %dx,%es
 	GET_CURRENT(%ebx)
-	call *%ecx
+	call *%edi
 	addl $8,%esp
 	jmp ret_from_exception
 
@@ -331,11 +333,6 @@
 ENTRY(coprocessor_segment_overrun)
 	pushl $0
 	pushl $ SYMBOL_NAME(do_coprocessor_segment_overrun)
-	jmp error_code
-
-ENTRY(reserved)
-	pushl $0
-	pushl $ SYMBOL_NAME(do_reserved)
 	jmp error_code
 
 ENTRY(double_fault)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/microcode.c linux.19p18/arch/i386/kernel/microcode.c
--- linux.vanilla/arch/i386/kernel/microcode.c	Mon Dec 11 22:12:34 2000
+++ linux.19p18/arch/i386/kernel/microcode.c	Sat Dec 30 19:42:45 2000
@@ -4,12 +4,13 @@
  *	Copyright (C) 2000 Tigran Aivazian
  *
  *	This driver allows to upgrade microcode on Intel processors
- *	belonging to P6 family - PentiumPro, Pentium II, Pentium III etc.
+ *	belonging to IA32 family - PentiumPro, Pentium II, Pentium III,
+ *	Pentium II Xeon, Pentium III Xeon, Pentium 4 etc.
  *
- *	Reference: Section 8.10 of Volume III, Intel Pentium III Manual, 
- *	Order Number 243192 or download from:
+ *	Reference: Section 8.10 of Volume III, Intel Pentium 4 Manual, 
+ *	Order Number 245472 or free download from:
  *		
- *	http://developer.intel.com/design/pentiumii/manuals/243192.htm
+ *	http://developer.intel.com/design/pentium4/manuals/245472.htm
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -30,6 +31,12 @@
  *		Added MICROCODE_IOCFREE ioctl to clear memory.
  *	1.05	09 June 2000, Simon Trimmer <simon@veritas.com>
  *		Messages for error cases (non intel & no suitable microcode).
+ *	1.06	07 Dec 2000, Tigran Aivazian <tigran@veritas.com>
+ *		Pentium 4 support + backported fixes from 2.4
+ *	1.07	13 Dec 2000, Tigran Aivazian <tigran@veritas.com>
+ *		More bugfixes backported from 2.4
+ *	1.08	27 Dec 2000, Tigran Aivazian <tigran@veritas.com>
+ *		Fix: X86_FEATURE_30 was used incorrectly (in a 2.4 manner)
  */
 
 #include <linux/init.h>
@@ -37,7 +44,6 @@
 #include <linux/sched.h>
 #include <linux/module.h>
 #include <linux/vmalloc.h>
-#include <linux/smp_lock.h>
 #include <linux/miscdevice.h>
 #include <linux/smp.h>
 
@@ -45,45 +51,25 @@
 #include <asm/uaccess.h>
 #include <asm/processor.h>
 
-#define MICROCODE_MINOR 184
-#define MICROCODE_IOCFREE _IO('6',0)
-struct microcode {
-	unsigned int hdrver;
-	unsigned int rev;
-	unsigned int date;
-	unsigned int sig;
-	unsigned int cksum;
-	unsigned int ldrver;
-	unsigned int pf;
-	unsigned int reserved[5];
-	unsigned int bits[500];
-};
-
-#define MICROCODE_VERSION 	"1.05"
+#define MICROCODE_VERSION 	"1.08"
 
-MODULE_DESCRIPTION("Intel CPU (P6) microcode update driver");
+MODULE_DESCRIPTION("Intel CPU (IA-32) microcode update driver");
 MODULE_AUTHOR("Tigran Aivazian <tigran@veritas.com>");
 EXPORT_NO_SYMBOLS;
 
 /* VFS interface */
 static int microcode_open(struct inode *, struct file *);
-static int microcode_release(struct inode *, struct file *);
 static ssize_t microcode_read(struct file *, char *, size_t, loff_t *);
 static ssize_t microcode_write(struct file *, const char *, size_t, loff_t *);
 static int microcode_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
 
+/* read()/write()/ioctl() are serialized on this */
+static struct semaphore microcode_sem = MUTEX;
 
 /* internal helpers to do the work */
 static int do_microcode_update(void);
 static void do_update_one(void *);
 
-/*
- *  Bits in microcode_status. (31 bits of room for future expansion)
- */
-#define MICROCODE_IS_OPEN	0	/* set if device is in use */
-
-static unsigned long microcode_status;
-
 /* the actual array of microcode blocks, each 2048 bytes */
 static struct microcode *microcode;
 static unsigned int microcode_num;
@@ -95,7 +81,6 @@
 	write:		microcode_write,
 	ioctl:		microcode_ioctl,
 	open:		microcode_open,
-	release:	microcode_release,
 };
 
 static struct miscdevice microcode_dev = {
@@ -106,26 +91,23 @@
 
 int __init microcode_init(void)
 {
-	int error = 0;
-
 	if (misc_register(&microcode_dev) < 0) {
-		printk(KERN_WARNING 
-			"microcode: can't misc_register on minor=%d\n",
+		printk(KERN_ERR "microcode: can't misc_register on minor=%d\n",
 			MICROCODE_MINOR);
-		error = 1;
+		return -EINVAL;
 	}
-	printk(KERN_INFO "P6 Microcode Update Driver v%s registered\n", 
+	printk(KERN_INFO "IA-32 Microcode Update Driver: v%s <tigran@veritas.com>\n", 
 			MICROCODE_VERSION);
 	return 0;
 }
 
 #ifdef MODULE
-static void microcode_exit(void)
+void cleanup_module(void)
 {
 	misc_deregister(&microcode_dev);
 	if (mc_applied)
 		kfree(mc_applied);
-	printk(KERN_INFO "P6 Microcode Update Driver v%s unregistered\n", 
+	printk(KERN_INFO "IA-32 Microcode Update Driver v%s unregistered\n", 
 			MICROCODE_VERSION);
 }
 
@@ -133,34 +115,14 @@
 {
 	return microcode_init();
 }
-void cleanup_module(void)
-{
-	microcode_exit();
-}
 #endif
 
-/*
- * We enforce only one user at a time here with open/close.
- */
 static int microcode_open(struct inode *inode, struct file *file)
 {
-	if (!capable(CAP_SYS_RAWIO))
-		return -EPERM;
-
-	/* one at a time, please */
-	if (test_and_set_bit(MICROCODE_IS_OPEN, &microcode_status))
-		return -EBUSY;
-
-	return 0;
-}
-
-static int microcode_release(struct inode *inode, struct file *file)
-{
-	clear_bit(MICROCODE_IS_OPEN, &microcode_status);
-	return 0;
+	return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
 }
 
-/* a pointer to 'struct update_req' is passed to the IPI handler = do_update_one()
+/*
  * update_req[cpu].err is set to 1 if update failed on 'cpu', 0 otherwise
  * if err==0, microcode[update_req[cpu].slot] points to applied block of microcode
  */
@@ -174,10 +136,10 @@
 	int i, error = 0, err;
 	struct microcode *m;
 
-	if (smp_call_function(do_update_one, (void *)update_req, 1, 1) != 0)
+	if (smp_call_function(do_update_one, NULL, 1, 1) != 0)
 		panic("do_microcode_update(): timed out waiting for other CPUs\n");
 
-	do_update_one((void *)update_req);
+	do_update_one(NULL);
 
 	for (i=0; i<smp_num_cpus; i++) {
 		err = update_req[i].err;
@@ -194,22 +156,23 @@
 {
 	int cpu_num = smp_processor_id();
 	struct cpuinfo_x86 *c = cpu_data + cpu_num;
-	struct update_req *req = (struct update_req *)arg + cpu_num;
+	struct update_req *req = update_req + cpu_num;
 	unsigned int pf = 0, val[2], rev, sig;
 	int i,found=0;
 
 	req->err = 1; /* be pessimistic */
 
-	if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6){
-		printk(KERN_ERR "microcode: CPU%d not an Intel P6\n", cpu_num );
+	if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 ||
+		(c->x86_capability & X86_FEATURE_30) ) { /* IA64 */
+		printk(KERN_ERR "microcode: CPU%d not a capable Intel processor\n", cpu_num);
 		return;
 	}
 
 	sig = c->x86_mask + (c->x86_model<<4) + (c->x86<<8);
 
-	if (c->x86_model >= 5) {
-		/* get processor flags from BBL_CR_OVRD MSR (0x17) */
-		rdmsr(0x17, val[0], val[1]);
+	if ((c->x86_model >= 5) || (c->x86 > 6)) {
+		/* get processor flags from MSR 0x17 */
+		rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
 		pf = 1 << ((val[1] >> 18) & 7);
 	}
 
@@ -219,7 +182,12 @@
 
 			found=1;
 
-			rdmsr(0x8B, val[0], rev);
+			/* trick, to work even if there was no prior update by the BIOS */
+			wrmsr(MSR_IA32_UCODE_REV, 0, 0);
+			__asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
+
+			/* get current (on-cpu) revision into rev (ignore val[0]) */
+			rdmsr(MSR_IA32_UCODE_REV, val[0], rev);
 			if (microcode[i].rev < rev) {
 				printk(KERN_ERR 
 					"microcode: CPU%d not 'upgrading' to earlier revision"
@@ -241,10 +209,16 @@
 					break;
 				}
 
-				wrmsr(0x79, (unsigned int)(m->bits), 0);
+				/* write microcode via MSR 0x79 */
+				wrmsr(MSR_IA32_UCODE_WRITE, (unsigned int)(m->bits), 0);
+
+				/* serialize */
 				__asm__ __volatile__ ("cpuid" : : : "ax", "bx", "cx", "dx");
-				rdmsr(0x8B, val[0], val[1]);
 
+				/* get the current revision from MSR 0x8B */
+				rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
+
+				/* notify the caller of success on this cpu */
 				req->err = 0;
 				req->slot = i;
 				printk(KERN_ERR "microcode: CPU%d updated from revision "
@@ -255,19 +229,27 @@
 		}
 
 	if(!found)
-		printk(KERN_ERR "microcode: found no data for CPU%d (sig=%x, pflags=%d)\n", cpu_num, sig, pf);
+		printk(KERN_ERR "microcode: CPU%d no microcode found! (sig=%x, pflags=%d)\n",
+				cpu_num, sig, pf);
 }
 
 static ssize_t microcode_read(struct file *file, char *buf, size_t len, loff_t *ppos)
 {
+	ssize_t err = 0;
+
+	down(&microcode_sem);
 	if (*ppos >= mc_fsize)
-		return 0;
+		goto out;
 	if (*ppos + len > mc_fsize)
 		len = mc_fsize - *ppos;
+	err = -EFAULT;
 	if (copy_to_user(buf, mc_applied + *ppos, len))
-		return -EFAULT;
+		goto out;
 	*ppos += len;
-	return len;
+	err = len;
+out:
+	up(&microcode_sem);
+	return err;
 }
 
 static ssize_t microcode_write(struct file *file, const char *buf, size_t len, loff_t *ppos)
@@ -279,17 +261,18 @@
 			sizeof(struct microcode));
 		return -EINVAL;
 	}
+	down(&microcode_sem);
 	if (!mc_applied) {
 		mc_applied = kmalloc(smp_num_cpus*sizeof(struct microcode),
 				GFP_KERNEL);
 		if (!mc_applied) {
+			up(&microcode_sem);
 			printk(KERN_ERR "microcode: out of memory for saved microcode\n");
 			return -ENOMEM;
 		}
 		memset(mc_applied, 0, mc_fsize);
 	}
 	
-	lock_kernel();
 	microcode_num = len/sizeof(struct microcode);
 	microcode = vmalloc(len);
 	if (!microcode) {
@@ -310,7 +293,7 @@
 out_fsize:
 	vfree(microcode);
 out_unlock:
-	unlock_kernel();
+	up(&microcode_sem);
 	return ret;
 }
 
@@ -319,15 +302,19 @@
 {
 	switch(cmd) {
 		case MICROCODE_IOCFREE:
+			down(&microcode_sem);
 			if (mc_applied) {
+				int bytes = smp_num_cpus * sizeof(struct microcode);
+
 				memset(mc_applied, 0, mc_fsize);
 				kfree(mc_applied);
 				mc_applied = NULL;
-				printk(KERN_WARNING 
-					"microcode: freed %d bytes\n", mc_fsize);
 				mc_fsize = 0;
+				printk(KERN_WARNING "microcode: freed %d bytes\n", bytes);
+				up(&microcode_sem);
 				return 0;
 			}
+			up(&microcode_sem);
 			return -ENODATA;
 
 		default:
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/msr.c linux.19p18/arch/i386/kernel/msr.c
--- linux.vanilla/arch/i386/kernel/msr.c	Mon Dec 11 22:12:34 2000
+++ linux.19p18/arch/i386/kernel/msr.c	Thu Dec 21 23:02:03 2000
@@ -260,6 +260,7 @@
 
 static void msr_exit(void)
 {
+  unregister_chrdev(MSR_MAJOR, "cpu/msr");
 }
 
 module_init(msr_init);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/setup.c linux.19p18/arch/i386/kernel/setup.c
--- linux.vanilla/arch/i386/kernel/setup.c	Mon Dec 11 22:12:34 2000
+++ linux.19p18/arch/i386/kernel/setup.c	Wed Feb  7 09:42:47 2001
@@ -73,6 +73,7 @@
 #include <asm/cobalt.h>
 #include <asm/msr.h>
 #include <asm/dma.h>
+#include <asm/e820.h>
 
 /*
  * Machine setup..
@@ -98,11 +99,12 @@
  */
 struct drive_info_struct { char dummy[32]; } drive_info;
 struct screen_info screen_info;
-struct apm_bios_info apm_bios_info;
+struct apm_info apm_info;
 struct sys_desc_table_struct {
 	unsigned short length;
 	unsigned char table[0];
 };
+struct e820map e820 __initdata = { 0, };
 
 unsigned char aux_device_present;
 
@@ -123,6 +125,8 @@
 #define SCREEN_INFO (*(struct screen_info *) (PARAM+0))
 #define EXT_MEM_K (*(unsigned short *) (PARAM+2))
 #define ALT_MEM_K (*(unsigned long *) (PARAM+0x1e0))
+#define E820_MAP_NR (*(char*) (PARAM+E820NR))
+#define E820_MAP  ((struct e820entry *) (PARAM+E820MAP))
 #define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+0x40))
 #define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80))
 #define SYS_DESC_TABLE (*(struct sys_desc_table_struct*)(PARAM+0xa0))
@@ -269,18 +273,128 @@
 	}
 #endif
 
+static void __init add_memory_region(unsigned long long start,
+				     unsigned long long size, int type)
+{
+       int x = e820.nr_map;
+
+       if (x == E820MAX) {
+           printk("Ooops! Too many entries in the memory map!\n");
+           return;
+       }
+
+       e820.map[x].addr = start;
+       e820.map[x].size = size;
+       e820.map[x].type = type;
+       e820.nr_map++;
+} /* add_memory_region */
+
+unsigned long i386_endbase __initdata =  0;
+
+static int __init copy_e820_map(struct e820entry * biosmap, int nr_map)
+{
+       /* Only one memory region (or negative)? Ignore it */
+       if (nr_map < 2)
+               return -1;
+
+       do {
+               unsigned long long start = biosmap->addr;
+               unsigned long long size = biosmap->size;
+               unsigned long long end = start + size;
+               unsigned long type = biosmap->type;
+
+               /* Overflow in 64 bits? Ignore the memory map. */
+               if (start > end)
+                       return -1;
+
+               /*
+                * Some BIOSes claim RAM in the 640k - 1M region.
+                * Not right. Fix it up.
+                */
+               if (type == E820_RAM) {
+                       if (start < 0x100000ULL && end > i386_endbase) {
+                               if (start < i386_endbase)
+                                       add_memory_region(start, i386_endbase-start, type);
+                               if (end <= 0x100000ULL)
+                                       continue;
+                               start = 0x100000ULL;
+                               size = end - start;
+                       }
+               }
+               add_memory_region(start, size, type);
+       } while (biosmap++,--nr_map);
+       return 0;
+}
+
+static void __init print_memory_map(char *who)
+{
+	int i;
+
+	for (i = 0; i < e820.nr_map; i++) {
+		printk(" %s: %08lx @ %08lx ", who,
+		       (unsigned long) e820.map[i].size,
+		       (unsigned long) e820.map[i].addr);
+		switch (e820.map[i].type) {
+		case E820_RAM:	printk("(usable)\n");
+				break;
+		case E820_RESERVED:
+				printk("(reserved)\n");
+				break;
+		case E820_ACPI:
+				printk("(ACPI data)\n");
+				break;
+		case E820_NVS:
+				printk("(ACPI NVS)\n");
+				break;
+		default:	printk("type %lu\n", e820.map[i].type);
+				break;
+		}
+	}
+}
+
+static void __init setup_memory_region(void)
+{
+       char *who = "BIOS-e820";
+
+       /*
+        * Try to copy the BIOS-supplied E820-map.
+        *
+        * Otherwise fake a memory map; one section from 0k->640k,
+        * the next section from 1mb->appropriate_mem_k
+        */
+       if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) {
+               unsigned long mem_size;
+
+               /* compare results from other methods and take the greater */
+               if (ALT_MEM_K < EXT_MEM_K) {
+                       mem_size = EXT_MEM_K;
+                       who = "BIOS-88";
+               } else {
+                       mem_size = ALT_MEM_K;
+                       who = "BIOS-e801";
+               }
+
+               e820.nr_map = 0;
+               add_memory_region(0, i386_endbase, E820_RAM);
+               add_memory_region(HIGH_MEMORY, (mem_size << 10), E820_RAM);
+       }
+       printk("BIOS-provided physical RAM map:\n");
+       print_memory_map(who);
+} /* setup_memory_region */
+
 
 static char command_line[COMMAND_LINE_SIZE] = { 0, };
        char saved_command_line[COMMAND_LINE_SIZE];
-unsigned long i386_endbase __initdata =  0;
 
 __initfunc(void setup_arch(char **cmdline_p,
 	unsigned long * memory_start_p, unsigned long * memory_end_p))
 {
-	unsigned long memory_start, memory_end;
+	unsigned long memory_start, memory_end = 0;
 	char c = ' ', *to = command_line, *from = COMMAND_LINE;
 	int len = 0;
 	int read_endbase_from_BIOS = 1;
+	int i;
+	unsigned long user_mem = 0;
 
 #ifdef CONFIG_VISWS
 	visws_get_board_type_and_rev();
@@ -289,7 +403,7 @@
  	ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV);
  	drive_info = DRIVE_INFO;
  	screen_info = SCREEN_INFO;
-	apm_bios_info = APM_BIOS_INFO;
+	apm_info.bios = APM_BIOS_INFO;
 	if( SYS_DESC_TABLE.length != 0 ) {
 		MCA_bus = SYS_DESC_TABLE.table[3] &0x2;
 		machine_id = SYS_DESC_TABLE.table[0];
@@ -297,17 +411,7 @@
 		BIOS_revision = SYS_DESC_TABLE.table[2];
 	}
 	aux_device_present = AUX_DEVICE_INFO;
-	memory_end = (1<<20) + (EXT_MEM_K<<10);
-#ifndef STANDARD_MEMORY_BIOS_CALL
-	{
-		unsigned long memory_alt_end = (1<<20) + (ALT_MEM_K<<10);
-		/* printk(KERN_DEBUG "Memory sizing: %08x %08x\n", memory_end, memory_alt_end); */
-		if (memory_alt_end > memory_end)
-			memory_end = memory_alt_end;
-	}
-#endif
 
-	memory_end &= PAGE_MASK;
 #ifdef CONFIG_BLK_DEV_RAM
 	rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
 	rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
@@ -337,12 +441,12 @@
 				from += 9+4;
 				boot_cpu_data.x86_capability &= ~X86_FEATURE_PSE;
 			} else {
-				memory_end = simple_strtoul(from+4, &from, 0);
+				user_mem = simple_strtoul(from+4, &from, 0);
 				if ( *from == 'K' || *from == 'k' ) {
-					memory_end = memory_end << 10;
+					user_mem = user_mem << 10;
 					from++;
 				} else if ( *from == 'M' || *from == 'm' ) {
-					memory_end = memory_end << 20;
+					user_mem = user_mem << 20;
 					from++;
 				}
 			}
@@ -351,7 +455,6 @@
 		{
 			if (to != command_line) to--;
 			i386_endbase = simple_strtoul(from+8, &from, 0);
-			i386_endbase += PAGE_OFFSET;
 			read_endbase_from_BIOS = 0;
 		}
 		c = *(from++);
@@ -387,7 +490,35 @@
 			}
 			i386_endbase = BIOS_ENDBASE;
 		}
-		i386_endbase += PAGE_OFFSET;
+	}
+
+	if (!user_mem)
+		setup_memory_region();
+	else {
+		e820.nr_map = 0;
+		add_memory_region(0, i386_endbase, E820_RAM);
+		add_memory_region(HIGH_MEMORY, user_mem-HIGH_MEMORY, E820_RAM);
+		printk("USER-provided physical RAM map:\n");
+		print_memory_map("USER");
+	}
+
+#define PFN_UP(x)      (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
+#define PFN_DOWN(x)    ((x) >> PAGE_SHIFT)
+	for (i = 0; i < e820.nr_map; i++) {
+		unsigned long long start, end;
+		/* RAM? */
+		if (e820.map[i].type != E820_RAM)
+			continue;
+		start = e820.map[i].addr;
+		if (start >= 0xffffffff)
+			continue;
+		end = e820.map[i].addr + e820.map[i].size;
+		if (start >= end)
+			continue;
+		if (end > 0xffffffff)
+			end = 0xffffffff;
+		if (end > memory_end)
+			memory_end = end;
 	}
 
 #define VMALLOC_RESERVE	(64 << 20)	/* 64MB for vmalloc */
@@ -1147,7 +1278,9 @@
 		wrmsr(0x1107, lv, hv);
 		/* Cyrix III */
 		c->x86_capability |= X86_FEATURE_CX8;
-		rdmsr(0x80000001, lv, hv);
+		
+		/* Check for 3dnow */
+		cpuid(0x80000001, &lv, &lv, &lv, &hv);
 		if(hv&(1<<31))
 			c->x86_capability |= X86_FEATURE_AMD3D;
 	}	
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/smp.c linux.19p18/arch/i386/kernel/smp.c
--- linux.vanilla/arch/i386/kernel/smp.c	Mon Dec 11 22:12:34 2000
+++ linux.19p18/arch/i386/kernel/smp.c	Thu Dec 21 22:49:00 2000
@@ -680,7 +680,7 @@
  */
 unsigned long __init smp_alloc_memory(unsigned long mem_base)
 {
-	if (mem_base + PAGE_SIZE > i386_endbase)
+	if (mem_base + PAGE_SIZE > i386_endbase + PAGE_OFFSET)
 		panic("smp_alloc_memory: Insufficient low memory for kernel trampoline 0x%lx.", mem_base);
 	trampoline_base = (void *)mem_base;
 	return mem_base + PAGE_SIZE;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/time.c linux.19p18/arch/i386/kernel/time.c
--- linux.vanilla/arch/i386/kernel/time.c	Mon Dec 11 22:12:34 2000
+++ linux.19p18/arch/i386/kernel/time.c	Wed Dec 13 22:38:07 2000
@@ -176,6 +176,14 @@
 
 	count |= inb_p(0x40) << 8;
 
+	/* VIA686a test code... reset the latch if count > max */
+ 	if (count > LATCH-1) {
+		outb_p(0x34, 0x43);
+		outb_p(LATCH & 0xff, 0x40);
+		outb(LATCH >> 8, 0x40);
+		count = LATCH - 1;
+	}	
+	
 	/*
 	 * avoiding timer inconsistencies (they are rare, but they happen)...
 	 * there are two kinds of problems that must be avoided here:
@@ -468,6 +476,22 @@
 
 		count = inb_p(0x40);    /* read the latched count */
 		count |= inb(0x40) << 8;
+
+		/* VIA686a test code... reset the latch if count > max */
+		if (count > LATCH-1) {
+			static int last_whine;
+			outb_p(0x34, 0x43);
+			outb_p(LATCH & 0xff, 0x40);
+			outb(LATCH >> 8, 0x40);
+			count = LATCH - 1;
+			if(time_after(jiffies, last_whine))
+			{
+				printk(KERN_WARNING "probable hardware bug: clock timer configuration lost - probably a VIA686a.\n");
+				printk(KERN_WARNING "probable hardware bug: restoring chip configuration.\n");
+				last_whine = jiffies + HZ;
+			}			
+		}	
+
 #if 0
 		spin_unlock(&i8253_lock);
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/kernel/traps.c linux.19p18/arch/i386/kernel/traps.c
--- linux.vanilla/arch/i386/kernel/traps.c	Mon Dec 11 22:12:34 2000
+++ linux.19p18/arch/i386/kernel/traps.c	Wed Jan  3 13:40:32 2001
@@ -106,7 +106,6 @@
 asmlinkage void general_protection(void);
 asmlinkage void page_fault(void);
 asmlinkage void coprocessor_error(void);
-asmlinkage void reserved(void);
 asmlinkage void alignment_check(void);
 asmlinkage void spurious_interrupt_bug(void);
 asmlinkage void machine_check(void);
@@ -156,7 +155,7 @@
 		printk("\nStack: ");
 		stack = (unsigned long *) esp;
 		for(i=0; i < kstack_depth_to_print; i++) {
-			if (((long) stack & 4095) == 0)
+			if (((long) stack & 8191) == 0)
 				break;
 			if (i && ((i % 8) == 0))
 				printk("\n       ");
@@ -171,7 +170,7 @@
 			module_start = PAGE_OFFSET + (max_mapnr << PAGE_SHIFT);
 			module_start = ((module_start + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1));
 			module_end = module_start + MODULE_RANGE;
-			while (((long) stack & 4095) != 0) {
+			while (((long) stack & 8191) != 0) {
 				addr = *stack++;
 				/*
 				 * If the address is either in the text segment of the
@@ -246,7 +245,6 @@
 DO_ERROR(11, SIGBUS,  "segment not present", segment_not_present, current)
 DO_ERROR(12, SIGBUS,  "stack segment", stack_segment, current)
 DO_ERROR(17, SIGSEGV, "alignment check", alignment_check, current)
-DO_ERROR(18, SIGSEGV, "reserved", reserved, current)
 /* I don't have documents for this but it does seem to cover the cache
    flush from user space exception some people get. */
 DO_ERROR(19, SIGSEGV, "cache flush denied", cache_flush_denied, current)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/i386/mm/init.c linux.19p18/arch/i386/mm/init.c
--- linux.vanilla/arch/i386/mm/init.c	Mon Dec 11 22:12:34 2000
+++ linux.19p18/arch/i386/mm/init.c	Thu Dec 21 22:49:00 2000
@@ -27,6 +27,7 @@
 #include <asm/pgtable.h>
 #include <asm/dma.h>
 #include <asm/fixmap.h>
+#include <asm/e820.h>
 
 extern void show_net_buffers(void);
 extern unsigned long init_smp_mappings(unsigned long);
@@ -384,8 +385,6 @@
 		printk(".\n");
 }
 
-extern unsigned long i386_endbase;
-
 __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
 {
 	unsigned long start_low_mem = PAGE_SIZE;
@@ -417,15 +416,36 @@
 #endif
 	start_mem = PAGE_ALIGN(start_mem);
 
-	while (start_low_mem < i386_endbase) {
-		clear_bit(PG_reserved, &mem_map[MAP_NR(start_low_mem)].flags);
-		start_low_mem += PAGE_SIZE;
-	}
+	for (tmp = __pa(start_low_mem); tmp < __pa(end_mem);
+	     tmp += PAGE_SIZE) {
+		struct page * page = mem_map + (tmp >> PAGE_SHIFT);
+		int i;
+		extern struct e820map e820;
 
-	while (start_mem < end_mem) {
-		clear_bit(PG_reserved, &mem_map[MAP_NR(start_mem)].flags);
-		start_mem += PAGE_SIZE;
+		/* don't include kernel memory and bootmem allocations */
+		if (tmp >= 0x100000 && tmp < __pa(start_mem))
+			continue;
+
+		for (i = 0; i < e820.nr_map; i++) {
+			unsigned long long start, end;
+			/* RAM? */
+			if (e820.map[i].type != E820_RAM)
+				continue;
+			start = e820.map[i].addr;
+			if (start >= 0xffffffff)
+				continue;
+			end = e820.map[i].addr + e820.map[i].size;
+			if (start >= end)
+				continue;
+			if (end > 0xffffffff)
+				end = 0xffffffff;
+
+			/* start and end are valid here */
+			if (start <= tmp && tmp+PAGE_SIZE <= end)
+				clear_bit(PG_reserved, &page->flags);
+		}
 	}
+
 	for (tmp = PAGE_OFFSET ; tmp < end_mem ; tmp += PAGE_SIZE) {
 		if (tmp >= MAX_DMA_ADDRESS)
 			clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/config.in linux.19p18/arch/ppc/config.in
--- linux.vanilla/arch/ppc/config.in	Mon Dec 11 22:12:35 2000
+++ linux.19p18/arch/ppc/config.in	Thu Feb 15 16:19:20 2001
@@ -151,9 +151,11 @@
 mainmenu_option next_comment
 comment 'ISDN subsystem'
 
-tristate 'ISDN support' CONFIG_ISDN
-if [ "$CONFIG_ISDN" != "n" ]; then
-  source drivers/isdn/Config.in
+if [ "$CONFIG_NET" != "n" ]; then
+   tristate 'ISDN support' CONFIG_ISDN
+   if [ "$CONFIG_ISDN" != "n" ]; then
+      source drivers/isdn/Config.in
+   fi
 fi
 endmenu
 
@@ -176,22 +178,25 @@
 
 mainmenu_option next_comment
 comment 'Mac device drivers'
+
 if [ "$CONFIG_INPUT_KEYBDEV" = "y" -o "$CONFIG_INPUT_MOUSEDEV" = "y" ]; then
-   bool 'Use input layer for ADB keyboard and mouse' CONFIG_INPUT_ADBHID
+  bool 'Use input layer for ADB keyboard and mouse' CONFIG_INPUT_ADBHID
 fi
 if [ "$CONFIG_INPUT_ADBHID" = "y" ]; then
-   define_bool CONFIG_MAC_HID y
-   bool '  Support for ADB raw keycodes' CONFIG_MAC_ADBKEYCODES
-   bool '  Support for mouse button 2+3 emulation' CONFIG_MAC_EMUMOUSEBTN
+  define_bool CONFIG_INPUT_KEYBDEV $CONFIG_VT
+  define_bool CONFIG_INPUT_MOUSEDEV y
+  define_bool CONFIG_MAC_HID y
+  bool '  Support for ADB raw keycodes' CONFIG_MAC_ADBKEYCODES
+  bool '  Support for mouse button 2+3 emulation' CONFIG_MAC_EMUMOUSEBTN
 else
-   bool 'Support for ADB keyboard (old driver)' CONFIG_MAC_KEYBOARD
-   bool 'Support for ADB mouse (old driver)' CONFIG_ADBMOUSE
+  bool 'Support for ADB keyboard (old driver)' CONFIG_MAC_KEYBOARD
+  bool 'Support for ADB mouse (old driver)' CONFIG_ADBMOUSE
 fi
 tristate 'Support for /dev/rtc' CONFIG_PPC_RTC
 bool 'Support for PowerMac floppy' CONFIG_MAC_FLOPPY
 tristate 'Support for PowerMac serial ports' CONFIG_MAC_SERIAL
 if [ "$CONFIG_MAC_SERIAL" = "y" ]; then
-   bool '   Support for console on serial port' CONFIG_SERIAL_CONSOLE
+  bool '   Support for console on serial port' CONFIG_SERIAL_CONSOLE
 fi
 endmenu
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/feature.c linux.19p18/arch/ppc/kernel/feature.c
--- linux.vanilla/arch/ppc/kernel/feature.c	Mon Dec 11 22:12:35 2000
+++ linux.19p18/arch/ppc/kernel/feature.c	Thu Feb 15 16:12:00 2001
@@ -2,7 +2,7 @@
  *  arch/ppc/kernel/feature.c
  *
  *  Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
- *                     Ben. Herrenschmidt (bh40@calva.net)
+ *                     Ben. Herrenschmidt (benh@kernel.crashing.org)
  *
  *  This program is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU General Public License
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/misc.S linux.19p18/arch/ppc/kernel/misc.S
--- linux.vanilla/arch/ppc/kernel/misc.S	Mon Dec 11 22:12:35 2000
+++ linux.19p18/arch/ppc/kernel/misc.S	Wed Feb 14 14:21:31 2001
@@ -563,6 +563,14 @@
 	isync /* Handle erratas in some cases */
 	blr
 
+_GLOBAL(_get_ICTC)
+       mfspr   r3,ICTC
+       blr
+
+_GLOBAL(_set_ICTC)
+       mtspr   ICTC,r3
+       blr
+
 /*
 	L2CR functions
 	Copyright İ 1997-1998 by PowerLogix R & D, Inc.
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/openpic.c linux.19p18/arch/ppc/kernel/openpic.c
--- linux.vanilla/arch/ppc/kernel/openpic.c	Mon Dec 11 22:12:35 2000
+++ linux.19p18/arch/ppc/kernel/openpic.c	Thu Feb 15 16:12:00 2001
@@ -8,8 +8,7 @@
  *
  *  Added initialisation code for Apple Core99 machines, tweaked a few things
  *  to avoid bogus interrupts and to make sure the disable function exits with
- *  the interrupt actually masked.
- *    Benjamin Herrenschmidt <bh40@calva.net>
+ *  the interrupt actually masked. --BenH
  *  Todo: map interrupts to all available CPUs after the ack round
  * 
  *  This file is subject to the terms and conditions of the GNU General Public
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/pmac_setup.c linux.19p18/arch/ppc/kernel/pmac_setup.c
--- linux.vanilla/arch/ppc/kernel/pmac_setup.c	Mon Dec 11 22:12:35 2000
+++ linux.19p18/arch/ppc/kernel/pmac_setup.c	Thu Feb 15 16:12:00 2001
@@ -449,6 +449,16 @@
 
 #ifdef CONFIG_BLK_DEV_IDE_PMAC
 
+void
+ide_pmac_init(void)
+{
+	if (_machine == _MACH_Pmac)
+		pmu_suspend();
+	ide_init();	
+	if (_machine == _MACH_Pmac)
+		pmu_resume();
+}
+
 extern kdev_t pmac_find_ide_boot(char *bootdevice, int n);
 
 __initfunc(kdev_t find_ide_boot(void))
@@ -657,6 +667,10 @@
 	ppc_md.set_rtc_time   = pmac_set_rtc_time;
 	ppc_md.get_rtc_time   = pmac_get_rtc_time;
 	ppc_md.calibrate_decr = pmac_calibrate_decr;
+
+	ppc_md.pci_dev_root_bridge	= pmac_pci_dev_root_bridge;
+	ppc_md.pci_dev_mem_base		= pmac_pci_dev_mem_base;
+	ppc_md.pci_dev_io_base		= pmac_pci_dev_io_base;
 
 #ifdef CONFIG_VT
 #ifdef CONFIG_MAC_KEYBOARD
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/ppc_ksyms.c linux.19p18/arch/ppc/kernel/ppc_ksyms.c
--- linux.vanilla/arch/ppc/kernel/ppc_ksyms.c	Mon Dec 11 22:12:35 2000
+++ linux.19p18/arch/ppc/kernel/ppc_ksyms.c	Thu Feb  1 15:11:19 2001
@@ -5,30 +5,24 @@
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/interrupt.h>
+#include <linux/smp_lock.h>
 #include <linux/vt_kern.h>
 #include <linux/nvram.h>
 
-#include <asm/page.h>
 #include <asm/semaphore.h>
 #include <asm/processor.h>
 #include <asm/uaccess.h>
-#include <asm/io.h>
 #include <asm/ide.h>
-#include <asm/atomic.h>
-#include <asm/bitops.h>
 #include <asm/checksum.h>
 #include <asm/pgtable.h>
 #include <asm/adb.h>
 #include <asm/cuda.h>
 #include <asm/pmu.h>
 #include <asm/prom.h>
-#include <asm/system.h>
 #include <asm/pci-bridge.h>
 #include <asm/irq.h>
 #include <asm/feature.h>
-#include <asm/spinlock.h>
 #include <asm/dma.h>
-#include <asm/machdep.h>
 #include <asm/nvram.h>
 #include <asm/time.h>
 
@@ -179,10 +173,10 @@
 #endif
 
 #ifdef __SMP__
-EXPORT_SYMBOL(__global_cli);
-EXPORT_SYMBOL(__global_sti);
-EXPORT_SYMBOL(__global_save_flags);
-EXPORT_SYMBOL(__global_restore_flags);
+EXPORT_SYMBOL(cpu_data);
+EXPORT_SYMBOL(kernel_flag);
+EXPORT_SYMBOL(cpu_number_map);
+EXPORT_SYMBOL(smp_num_cpus);
 EXPORT_SYMBOL(_spin_lock);
 EXPORT_SYMBOL(_spin_unlock);
 EXPORT_SYMBOL(spin_trylock);
@@ -190,6 +184,17 @@
 EXPORT_SYMBOL(_read_unlock);
 EXPORT_SYMBOL(_write_lock);
 EXPORT_SYMBOL(_write_unlock);
+
+/* Global SMP irq stuff */
+EXPORT_SYMBOL(synchronize_irq);
+EXPORT_SYMBOL(synchronize_bh);
+EXPORT_SYMBOL(global_bh_count);
+EXPORT_SYMBOL(global_bh_lock);
+EXPORT_SYMBOL(global_irq_holder);
+EXPORT_SYMBOL(__global_cli);
+EXPORT_SYMBOL(__global_sti);
+EXPORT_SYMBOL(__global_save_flags);
+EXPORT_SYMBOL(__global_restore_flags);
 #endif /* __SMP__ */
 
 EXPORT_SYMBOL(_machine);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/prom.c linux.19p18/arch/ppc/kernel/prom.c
--- linux.vanilla/arch/ppc/kernel/prom.c	Mon Dec 11 22:12:36 2000
+++ linux.19p18/arch/ppc/kernel/prom.c	Thu Feb 15 16:14:50 2001
@@ -668,8 +668,8 @@
 	}
 	
 #endif	
-	/* If OpenFirmware version >= 3, then use quiesce call */
-	if (RELOC(prom_version) >= 3) {
+	/* If PowerMac, then use quiesce call */
+	if (!chrp) {
 	    prom_print(RELOC("Calling quiesce ...\n"));
 	    call_prom(RELOC("quiesce"), 0, 0);
 	    offset = reloc_offset();
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/ppc/kernel/sleep.S linux.19p18/arch/ppc/kernel/sleep.S
--- linux.vanilla/arch/ppc/kernel/sleep.S	Mon Dec 11 22:12:36 2000
+++ linux.19p18/arch/ppc/kernel/sleep.S	Thu Feb 15 16:12:00 2001
@@ -1,6 +1,6 @@
 /*
  * This file contains sleep low-level functions for PowerBook G3.
- *    Copyright (C) 1999 Benjamin Herrenschmidt (bh40@calva.net)
+ *    Copyright (C) 1999 Benjamin Herrenschmidt (benh@kernel.crashing.org)
  *    and Paul Mackerras (paulus@cs.anu.edu.au).
  *
  * This program is free software; you can redistribute it and/or
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/config.in linux.19p18/arch/s390/config.in
--- linux.vanilla/arch/s390/config.in	Mon Dec 11 22:12:36 2000
+++ linux.19p18/arch/s390/config.in	Thu Dec 21 22:50:29 2000
@@ -44,11 +44,14 @@
 endmenu
 
 source drivers/s390/Config.in
+
+mainmenu_option next_comment
 comment 'Character devices'
 bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
 if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
   int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
 fi
+endmenu
 
 if [ "$CONFIG_NET" = "y" ]; then
   source net/Config.in
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/Makefile linux.19p18/arch/s390/kernel/Makefile
--- linux.vanilla/arch/s390/kernel/Makefile	Sun Jun 11 21:44:09 2000
+++ linux.19p18/arch/s390/kernel/Makefile	Mon Feb 19 18:33:37 2001
@@ -18,16 +18,15 @@
 all: kernel.o head.o init_task.o
 
 O_TARGET := kernel.o
-O_OBJS   := lowcore.o entry.o bitmap.o traps.o time.o process.o irq.o \
-            setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
-            s390fpu.o s390io.o reipl.o debug.o s390_ext.o s390dyn.o \
-            s390mach.o 
+O_OBJS   := lowcore.o entry.o bitmap.o traps.o time.o \
+            setup.o sys_s390.o ptrace.o signal.o cpcmd.o \
+            s390fpu.o reipl.o s390mach.o 
 
-OX_OBJS  := s390_ksyms.o
+OX_OBJS  := debug.o ebcdic.o irq.o process.o s390_ext.o s390_ksyms.o s390dyn.o s390io.o
 MX_OBJS  :=
 
 ifdef CONFIG_SMP
-O_OBJS += smp.o
+OX_OBJS += smp.o
 endif
 
 ifeq ($(CONFIG_IEEEFPU_EMULATION),y)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/cpcmd.c linux.19p18/arch/s390/kernel/cpcmd.c
--- linux.vanilla/arch/s390/kernel/cpcmd.c	Mon Dec 11 22:12:36 2000
+++ linux.19p18/arch/s390/kernel/cpcmd.c	Mon Feb 19 18:37:49 2001
@@ -22,10 +22,10 @@
         ASCEBC(obuffer,olen);
 
         if (response != NULL && rlen > 0) {
-                asm volatile ("LRA   2,0(0,%0)\n\t"
+                asm volatile ("LRA   2,0(%0)\n\t"
                               "LR    4,%1\n\t"
                               "O     4,%4\n\t"
-                              "LRA   3,0(0,%2)\n\t"
+                              "LRA   3,0(%2)\n\t"
                               "LR    5,%3\n\t"
                               ".long 0x83240008 # Diagnose 83\n\t"
                               : /* no output */
@@ -34,7 +34,7 @@
                               : "2", "3", "4", "5" );
                 EBCASC(response, rlen);
         } else {
-                asm volatile ("LRA   2,0(0,%0)\n\t"
+                asm volatile ("LRA   2,0(%0)\n\t"
                               "LR    3,%1\n\t"
                               ".long 0x83230008 # Diagnose 83\n\t"
                               : /* no output */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/debug.c linux.19p18/arch/s390/kernel/debug.c
--- linux.vanilla/arch/s390/kernel/debug.c	Mon Dec 11 22:12:36 2000
+++ linux.19p18/arch/s390/kernel/debug.c	Mon Feb 19 18:33:37 2001
@@ -10,48 +10,58 @@
  *    Bugreports to: <Linux390@de.ibm.com>
  */
 
+#include <linux/config.h>
 #include <linux/stddef.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/malloc.h>
-#include <linux/vmalloc.h>
 #include <linux/ctype.h>
 #include <linux/version.h>
-#include <asm/ebcdic.h>
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
 
-#ifdef MODULE
 #include <linux/module.h>
-#endif
 
 #include <asm/debug.h>
 
 #define MIN(a,b) (((a)<(b))?(a):(b))
-
-#if defined(CONFIG_ARCH_S390)
-#define DEBUG_PROC_HEADER_SIZE 38
-#endif
-
-#define ADD_BUFFER 1000
+#define DEBUG_PROLOG_ENTRY -1
 
 /* typedefs */
 
 typedef struct file_private_info {
-	loff_t len;			/* length of output in byte */
-	int size;			/* size of buffer for output */
-	char *data;			/* buffer for output */
-	debug_info_t *debug_info;	/* the debug information struct */
+	loff_t offset;			/* offset of last read in file */
+	int    act_area;                /* number of last formated area */
+	int    act_entry;               /* last formated entry (offset */
+                                        /* relative to beginning of last */
+                                        /* formated area) */ 
+	size_t act_entry_offset;        /* up to this offset we copied */
+					/* in last read the last formated */
+					/* entry to userland */
+	char   temp_buf[2048];		/* buffer for output */
+	debug_info_t *debug_info_org;   /* original debug information */
+	debug_info_t *debug_info_snap;	/* snapshot of debug information */
 	struct debug_view *view;	/* used view of debug info */
 } file_private_info_t;
 
+typedef struct
+{
+	char *string;
+	/* 
+	 * This assumes that all args are converted into longs 
+	 * on L/390 this is the case for all types of parameter 
+	 * except of floats, and long long (32 bit) 
+         *
+         */
+	long args[0];
+} debug_sprintf_entry;
+
+
 extern void tod_to_timeval(uint64_t todval, struct timeval *xtime);
 
 /* internal function prototyes */
 
 static int debug_init(void);
-static int debug_format_output(debug_info_t * debug_area, char *buf,
-			       int size, struct debug_view *view);
 static ssize_t debug_output(struct file *file, char *user_buf,
 			    size_t user_len, loff_t * offset);
 static ssize_t debug_input(struct file *file, const char *user_buf,
@@ -65,6 +75,7 @@
 			     struct file_operations *fops);
 static void debug_delete_proc_dir_entry(struct proc_dir_entry *root,
 					struct proc_dir_entry *entry);
+static debug_info_t*  debug_info_create(char *name, int page_order, int nr_areas, int buf_size);
 static void debug_info_get(debug_info_t *);
 static void debug_info_put(debug_info_t *);
 static int debug_prolog_level_fn(debug_info_t * id,
@@ -72,38 +83,34 @@
 static int debug_input_level_fn(debug_info_t * id, struct debug_view *view,
 				struct file *file, const char *user_buf,
 				size_t user_buf_size, loff_t * offset);
-static int debug_hex_format_fn(debug_info_t * id, struct debug_view *view,
-			       char *out_buf, const char *in_buf);
-static int debug_ascii_format_fn(debug_info_t * id,
+static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view,
+                                char *out_buf, const char *in_buf);
+static int debug_raw_format_fn(debug_info_t * id,
 				 struct debug_view *view, char *out_buf,
 				 const char *in_buf);
-static int debug_ebcdic_format_fn(debug_info_t * id,
-				  struct debug_view *view, char *out_buf,
-				  const char *in_buf);
+static int debug_raw_header_fn(debug_info_t * id, struct debug_view *view,
+                         int area, debug_entry_t * entry, char *out_buf);
+
+static int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view,
+				   char *out_buf, debug_sprintf_entry *curr_event);
 
 /* globals */
 
-struct debug_view debug_ascii_view = {
-	"ascii",
+struct debug_view debug_raw_view = {
+	"raw",
 	NULL,
-	&debug_dflt_header_fn,
-	&debug_ascii_format_fn,
-	NULL
-};
-
-struct debug_view debug_ebcdic_view = {
-	"ebcdic",
+	&debug_raw_header_fn,
+	&debug_raw_format_fn,
 	NULL,
-	&debug_dflt_header_fn,
-	&debug_ebcdic_format_fn,
 	NULL
 };
 
-struct debug_view debug_hex_view = {
-	"hex",
+struct debug_view debug_hex_ascii_view = {
+	"hex_ascii",
 	NULL,
 	&debug_dflt_header_fn,
-	&debug_hex_format_fn,
+	&debug_hex_ascii_format_fn,
+	NULL,
 	NULL
 };
 
@@ -112,13 +119,26 @@
 	&debug_prolog_level_fn,
 	NULL,
 	NULL,
-	&debug_input_level_fn
+	&debug_input_level_fn,
+	NULL
+};
+
+struct debug_view debug_sprintf_view = {
+	"sprintf",
+	NULL,
+	&debug_dflt_header_fn,
+	(debug_format_proc_t*)&debug_sprintf_format_fn,
+	NULL,
+	NULL
 };
 
+
+unsigned int debug_feature_version = __DEBUG_FEATURE_VERSION;
+
 /* static globals */
 
-static debug_info_t debug_areas[DEBUG_MAX_AREAS];
-static debug_info_t *free_area = 0;
+static debug_info_t *debug_area_first = NULL;
+static debug_info_t *debug_area_last = NULL;
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
 static struct semaphore debug_lock = MUTEX;
 #else
@@ -143,10 +163,155 @@
 
 static struct proc_dir_entry *debug_proc_root_entry;
 
-
 /* functions */
 
 /*
+ * debug_info_alloc
+ * - alloc new debug-info
+ */
+
+static debug_info_t*  debug_info_alloc(char *name, int page_order,
+                                        int nr_areas, int buf_size)
+{
+	debug_info_t* rc;
+	int i;
+
+	/* alloc everything */
+
+	rc = (debug_info_t*) kmalloc(sizeof(debug_info_t), GFP_ATOMIC);
+	if(!rc)
+		goto fail_malloc_rc;
+	rc->active_entry = (int*)kmalloc(nr_areas * sizeof(int), GFP_ATOMIC);
+	if(!rc->active_entry)
+		goto fail_malloc_active_entry;
+	memset(rc->active_entry, 0, nr_areas * sizeof(int));
+	rc->areas = (debug_entry_t **) kmalloc(nr_areas *
+						sizeof(debug_entry_t *),
+						GFP_ATOMIC);
+	if (!rc->areas)
+		goto fail_malloc_areas;
+	for (i = 0; i < nr_areas; i++) {
+		rc->areas[i] = (debug_entry_t *) __get_free_pages(GFP_ATOMIC,
+								page_order);
+		if (!rc->areas[i]) {
+			for (i--; i >= 0; i--) {
+				free_pages((unsigned long) rc->areas[i],
+						page_order);
+			}
+			goto fail_malloc_areas2;
+		} else {
+			memset(rc->areas[i], 0, PAGE_SIZE << page_order);
+		}
+	}
+
+	/* initialize members */
+
+	spin_lock_init(&rc->lock);
+	rc->page_order  = page_order;
+	rc->nr_areas    = nr_areas;
+	rc->active_area = 0;
+	rc->level       = DEBUG_DEFAULT_LEVEL;
+	rc->buf_size    = buf_size;
+	rc->entry_size  = sizeof(debug_entry_t) + buf_size;
+	strncpy(rc->name, name, MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1)));
+	rc->name[MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1))] = 0;
+	memset(rc->views, 0, DEBUG_MAX_VIEWS * sizeof(struct debug_view *));
+	memset(rc->proc_entries, 0 ,DEBUG_MAX_VIEWS *
+		sizeof(struct proc_dir_entry*));
+	atomic_set(&(rc->ref_count), 0);
+
+	return rc;
+
+fail_malloc_areas2:
+	kfree(rc->areas);
+fail_malloc_areas:
+	kfree(rc->active_entry);
+fail_malloc_active_entry:
+	kfree(rc);
+fail_malloc_rc:
+	return NULL;
+}
+
+/*
+ * debug_info_free
+ * - free memory debug-info
+ */
+
+static void debug_info_free(debug_info_t* db_info){
+	int i;
+	for (i = 0; i < db_info->nr_areas; i++) {
+		free_pages((unsigned long) db_info->areas[i],
+		db_info->page_order);
+	}
+	kfree(db_info->areas);
+	kfree(db_info->active_entry);
+	kfree(db_info);
+}
+
+/*
+ * debug_info_create
+ * - create new debug-info
+ */
+
+static debug_info_t*  debug_info_create(char *name, int page_order, 
+                                        int nr_areas, int buf_size)
+{
+	debug_info_t* rc;
+
+        rc = debug_info_alloc(name, page_order, nr_areas, buf_size);
+        if(!rc) 
+		goto out;
+
+
+	/* create proc rood directory */
+
+        rc->proc_root_entry =
+            debug_create_proc_dir_entry(debug_proc_root_entry, rc->name,
+                                        S_IFDIR | S_IRUGO | S_IXUGO |
+                                        S_IWUSR | S_IWGRP, NULL, NULL);
+
+	/* append new element to linked list */
+
+        if(debug_area_first == NULL){
+                /* first element in list */
+                debug_area_first = rc;
+                rc->prev = NULL;
+        }
+        else{
+                /* append element to end of list */
+                debug_area_last->next = rc;
+                rc->prev = debug_area_last;
+        }
+        debug_area_last = rc;
+        rc->next = NULL;
+
+	debug_info_get(rc);
+out:
+	return rc;
+}
+
+/*
+ * debug_info_copy
+ * - copy debug-info
+ */
+
+static debug_info_t* debug_info_copy(debug_info_t* in)
+{
+        int i;
+        debug_info_t* rc;
+        rc = debug_info_alloc(in->name, in->page_order, 
+                                in->nr_areas, in->buf_size);
+        if(!rc)
+                goto out;
+
+        for(i = 0; i < in->nr_areas; i++){
+                memcpy(rc->areas[i],in->areas[i], PAGE_SIZE << in->page_order);
+        }
+out:
+        return rc;
+}
+
+/*
  * debug_info_get
  * - increments reference count for debug-info
  */
@@ -179,44 +344,120 @@
 		}
 		debug_delete_proc_dir_entry(debug_proc_root_entry,
 					    db_info->proc_root_entry);
-		for (i = 0; i < db_info->nr_areas; i++) {
-			free_pages((unsigned long) db_info->areas[i],
-				   db_info->page_order);
-		}
-		kfree(db_info->areas);
-		db_info->areas = NULL;
-		*((debug_info_t **) db_info) = free_area;
-		free_area = db_info;
+		if(db_info == debug_area_first)
+			debug_area_first = db_info->next;
+		if(db_info == debug_area_last)
+			debug_area_last = db_info->prev;
+		if(db_info->prev) db_info->prev->next = db_info->next;
+		if(db_info->next) db_info->next->prev = db_info->prev;
+		debug_info_free(db_info);
 	}
 }
 
+/*
+ * debug_format_entry:
+ * - format one debug entry and return size of formated data
+ */
+
+static int debug_format_entry(file_private_info_t *p_info)
+{
+	debug_info_t *id_org    = p_info->debug_info_org;
+	debug_info_t *id_snap   = p_info->debug_info_snap;
+	struct debug_view *view = p_info->view;
+	debug_entry_t *act_entry;
+	size_t len = 0;
+	if(p_info->act_entry == DEBUG_PROLOG_ENTRY){
+		/* print prolog */
+        	if (view->prolog_proc)
+                	len += view->prolog_proc(id_org, view,p_info->temp_buf);
+		goto out;
+	}
+
+	act_entry = (debug_entry_t *) ((char*)id_snap->areas[p_info->act_area] +
+					p_info->act_entry);
+                        
+	if (act_entry->id.stck == 0LL)
+			goto out;  /* empty entry */
+	if (view->header_proc)
+		len += view->header_proc(id_org, view, p_info->act_area, 
+					act_entry, p_info->temp_buf + len);
+	if (view->format_proc)
+		len += view->format_proc(id_org, view, p_info->temp_buf + len,
+						DEBUG_DATA(act_entry));
+      out:
+        return len;
+}
+
+/*
+ * debug_next_entry:
+ * - goto next entry in p_info
+ */
+
+extern inline int debug_next_entry(file_private_info_t *p_info)
+{
+	debug_info_t *id = p_info->debug_info_snap;
+	if(p_info->act_entry == DEBUG_PROLOG_ENTRY){
+		p_info->act_entry = 0;
+		goto out;
+	}
+	if ((p_info->act_entry += id->entry_size)
+		> ((PAGE_SIZE << (id->page_order)) 
+		- id->entry_size)){
+
+		/* next area */
+		p_info->act_entry = 0;
+        	p_info->act_area++;
+        	if(p_info->act_area >= id->nr_areas)
+			return 1;
+	}
+out:
+	return 0;	
+}
 
 /*
  * debug_output:
  * - called for user read()
- * - copies formated output form private_data of the file
- *   handle to the user buffer
+ * - copies formated debug entries to the user buffer
  */
 
 static ssize_t debug_output(struct file *file,	/* file descriptor */
 			    char *user_buf,	/* user buffer */
-			    size_t user_len,	/* length of buffer */
+			    size_t  len,	/* length of buffer */
 			    loff_t *offset	/* offset in the file */ )
 {
-	loff_t len;
+	size_t count = 0;
+	size_t entry_offset, size = 0;
 	int rc;
 	file_private_info_t *p_info;
 
 	p_info = ((file_private_info_t *) file->private_data);
-	if (*offset >= p_info->len) {
-		return 0;	/* EOF */
-	} else {
-		len = MIN(user_len, (p_info->len - *offset));
-		if ((rc = copy_to_user(user_buf, &(p_info->data[*offset]),len)))
-			return rc;;
-		(*offset) += len;
-		return len;	/* number of bytes "read" */
+	if (*offset != p_info->offset) 
+		return -EPIPE;
+	if(p_info->act_area >= p_info->debug_info_snap->nr_areas)
+		return 0;
+
+	entry_offset = p_info->act_entry_offset;
+
+	while(count < len){
+		size = debug_format_entry(p_info);
+		size = MIN((len - count), (size - entry_offset));
+
+		if(size){
+			if ((rc = copy_to_user(user_buf + count, 
+					p_info->temp_buf + entry_offset, size)))
+			return rc;
+		}
+		count += size;
+		entry_offset = 0;
+		if(count != len)
+			if(debug_next_entry(p_info)) 
+				goto out;
 	}
+out:
+	p_info->offset           = *offset + count;
+	p_info->act_entry_offset = size;	
+	*offset = p_info->offset;
+	return count;
 }
 
 /*
@@ -235,69 +476,16 @@
 	down(&debug_lock);
 	p_info = ((file_private_info_t *) file->private_data);
 	if (p_info->view->input_proc)
-		rc = p_info->view->input_proc(p_info->debug_info,
+		rc = p_info->view->input_proc(p_info->debug_info_org,
 					      p_info->view, file, user_buf,
 					      length, offset);
+	else
+		rc = -EPERM;
 	up(&debug_lock);
 	return rc;		/* number of input characters */
 }
 
 /*
- * debug_format_output:
- * - calls prolog, header and format functions of view to format output
- */
-
-static int debug_format_output(debug_info_t * debug_area, char *buf,
-			       int size, struct debug_view *view)
-{
-	int len = 0;
-	int i, j;
-	int nr_of_entries;
-	debug_entry_t *act_entry;
-
-	/* print prolog */
-	if (view->prolog_proc)
-		len += view->prolog_proc(debug_area, view, buf);
-	/* print debug records */
-	if (!(view->format_proc) && !(view->header_proc))
-		goto out;
-	nr_of_entries = PAGE_SIZE / debug_area->entry_size
-			<< debug_area->page_order;
-	for (i = 0; i < debug_area->nr_areas; i++) {
-		act_entry = debug_area->areas[i];
-		for (j = 0; j < nr_of_entries; j++) {
-			if (act_entry->id.fields.used == 0)
-				break;	/* empty entry */
-			if (view->header_proc)
-				len += view->header_proc(debug_area, view, i,
-						         act_entry, buf + len);
-			if (view->format_proc)
-				len += view->format_proc(debug_area, view,
-						         buf + len,
-						         act_entry->data);
-			len += sprintf(buf + len, "\n");
-			if (len > size) {
-				printk(KERN_ERR
-				"debug: error -- memory exceeded for (%s/%s)\n",
-				debug_area->name, view->name);
-				printk(KERN_ERR "debug: fix view %s!!\n",
-				       view->name);
-				printk(KERN_ERR
-				"debug: area: %i (0 - %i) entry: %i (0 - %i)\n",
-				i, debug_area->nr_areas - 1, j,
-				nr_of_entries - 1);
-				goto out;
-			}
-			act_entry = (debug_entry_t *) (((char *) act_entry) +
-					       debug_area->entry_size);
-		}
-	}
-      out:
-	return len;
-}
-
-
-/*
  * debug_open:
  * - called for user open()
  * - copies formated output to private_data area of the file
@@ -306,119 +494,68 @@
 
 static int debug_open(struct inode *inode, struct file *file)
 {
-	int i, j = 0, size = 0, rc = 0, f_entry_size = 0;
+	int i = 0, rc = 0;
 	file_private_info_t *p_info;
+	debug_info_t *debug_info, *debug_info_snapshot;
 
 #ifdef DEBUG
 	printk("debug_open\n");
 #endif
-
-#ifdef MODULE
 	MOD_INC_USE_COUNT;
-#endif
 	down(&debug_lock);
 
 	/* find debug log and view */
 
-	for (i = 0; i < DEBUG_MAX_AREAS; i++) {
-		if (debug_areas[i].areas == NULL)
-			continue;	/* not in use */
-		for (j = 0; j < DEBUG_MAX_VIEWS; j++) {
-			if (debug_areas[i].views[j] == NULL)
+	debug_info = debug_area_first;
+	while(debug_info != NULL){
+		for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
+			if (debug_info->views[i] == NULL)
 				continue;
-			else if (debug_areas[i].proc_entries[j]->low_ino ==
+			else if (debug_info->proc_entries[i]->low_ino ==
 				 file->f_dentry->d_inode->i_ino) {
 				goto found;	/* found view ! */
 			}
 		}
+		debug_info = debug_info->next;
 	}
 	/* no entry found */
 	rc = -EINVAL;
 	goto out;
+
       found:
-	if ((file->private_data =
-	     kmalloc(sizeof(file_private_info_t), GFP_ATOMIC)) == 0) {
-		printk(KERN_ERR "debug_open: kmalloc failed\n");
-		rc = -ENOMEM;
-		goto out;
-	}
-	p_info = (file_private_info_t *) file->private_data;
 
-	/*
-	 * the size for the formated output is calculated
-	 * with the following formula:
-	 *
-	 *   prolog-size
-	 *   +
-	 *   (record header size + record data field size)
-	 *   * number of entries per page
-	 *   * number of pages per area
-	 *   * number of areas
-	 */
-
-	if (debug_areas[i].views[j]->prolog_proc)
-		size +=
-		    debug_areas[i].views[j]->prolog_proc(&debug_areas[i],
-							 debug_areas[i].
-							 views[j], NULL);
-
-	if (debug_areas[i].views[j]->header_proc)
-		f_entry_size =
-		    debug_areas[i].views[j]->header_proc(&debug_areas[i],
-							 debug_areas[i].
-							 views[j], 0, NULL,
-							 NULL);
-	if (debug_areas[i].views[j]->format_proc)
-		f_entry_size +=
-		    debug_areas[i].views[j]->format_proc(&debug_areas[i],
-							 debug_areas[i].
-							 views[j], NULL,
-							 NULL);
-	if (f_entry_size)
-		f_entry_size += 1;	/* \n in each line */
-
-
-	size += f_entry_size 
-		* (PAGE_SIZE / debug_areas[i].entry_size
-		<< debug_areas[i].page_order)
-		* debug_areas[i].nr_areas + 1;	/* terminating \0 */
-#ifdef DEBUG
-	printk("debug_open: size: %i\n", size);
-#endif
+	/* make snapshot of current debug areas to get it consistent */
+
+	debug_info_snapshot = debug_info_copy(debug_info);
 
-	/* alloc some bytes more to be safe against bad views */
-	if ((p_info->data = vmalloc(size + ADD_BUFFER)) == 0) {
-		printk(KERN_ERR "debug_open: vmalloc failed\n");
-		vfree(file->private_data);
+	if(!debug_info_snapshot){
+		printk(KERN_ERR "debug_open: debug_info_copy failed (out of mem)\n");
 		rc = -ENOMEM;
 		goto out;
 	}
 
-	p_info->size = size;
-	p_info->debug_info = &debug_areas[i];
-	p_info->view = debug_areas[i].views[j];
-
-	spin_lock_irq(&debug_areas[i].lock);
-
-	p_info->len =
-	    debug_format_output(&debug_areas[i], p_info->data, size,
-				debug_areas[i].views[j]);
-#ifdef DEBUG
-	{
-		int ilen = p_info->len;
-		printk("debug_open: len: %i\n", ilen);
+	if ((file->private_data =
+	     kmalloc(sizeof(file_private_info_t), GFP_ATOMIC)) == 0) {
+		printk(KERN_ERR "debug_open: kmalloc failed\n");
+		debug_info_free(debug_info_snapshot);	
+		rc = -ENOMEM;
+		goto out;
 	}
-#endif
+	p_info = (file_private_info_t *) file->private_data;
+	p_info->offset = 0;
+	p_info->debug_info_snap = debug_info_snapshot;
+	p_info->debug_info_org  = debug_info;
+	p_info->view = debug_info->views[i];
+	p_info->act_area = 0;
+	p_info->act_entry = DEBUG_PROLOG_ENTRY;
+	p_info->act_entry_offset = 0;
 
-	spin_unlock_irq(&debug_areas[i].lock);
-	debug_info_get(&debug_areas[i]);
+	debug_info_get(debug_info);
 
       out:
 	up(&debug_lock);
-#ifdef MODULE
 	if (rc != 0)
 		MOD_DEC_USE_COUNT;
-#endif
 	return rc;
 }
 
@@ -434,18 +571,11 @@
 #ifdef DEBUG
 	printk("debug_close\n");
 #endif
-	down(&debug_lock);
 	p_info = (file_private_info_t *) file->private_data;
-	debug_info_put(p_info->debug_info);
-	if (p_info->data) {
-		vfree(p_info->data);
-		kfree(file->private_data);
-	}
-	up(&debug_lock);
-
-#ifdef MODULE
+	debug_info_free(p_info->debug_info_snap);
+	debug_info_put(p_info->debug_info_org);
+	kfree(file->private_data);
 	MOD_DEC_USE_COUNT;
-#endif
 	return 0;		/* success */
 }
 
@@ -522,74 +652,25 @@
     (char *name, int page_order, int nr_areas, int buf_size) 
 {
 	debug_info_t *rc = NULL;
-	int i;
 
-#ifdef MODULE
 	MOD_INC_USE_COUNT;
-#endif
 	if (!initialized)
 		debug_init();
 	down(&debug_lock);
-	if (!free_area) {
-		printk(KERN_WARNING "debug: no free debug area for %s\n",
-		       name);
-		goto out;
-	}
-	rc = free_area;
-	free_area = *((debug_info_t **) rc);
-	rc->areas = (debug_entry_t **) kmalloc(nr_areas *
-					       sizeof(debug_entry_t *),
-					       GFP_ATOMIC);
-	if (!rc->areas) {
-		free_area = rc;
-		rc = NULL;
-		goto out;
-	}
-	for (i = 0; i < nr_areas; i++) {
-		rc->areas[i] =
-		    (debug_entry_t *) __get_free_pages(GFP_ATOMIC,
-						       page_order);
-		if (!rc->areas[i]) {
-			for (i--; i >= 0; i--) {
-				free_pages((unsigned long) rc->areas[i],
-					   page_order);
-			}
-			free_area = rc;
-			rc = NULL;
-			goto out;
-		} else {
-			memset(rc->areas[i], 0, PAGE_SIZE << page_order);
-		}
-	}
 
-	rc->page_order  = page_order;
-	rc->nr_areas    = nr_areas;
-	rc->active_area = 0;
-	rc->level       = DEBUG_DEFAULT_LEVEL;
-	rc->buf_size    = buf_size;
-	rc->entry_size  = sizeof(debug_entry_t) 
-                          + buf_size - 4;  /* must subtract data[4] */
-	strncpy(rc->name, name,
-		MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1)));
-	rc->name[MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1))] = 0;
-	memset(rc->active_entry, 0, nr_areas * sizeof(int));
-	memset(rc->views, 0, DEBUG_MAX_VIEWS * sizeof(struct debug_view *));
-	atomic_set(&(rc->ref_count), 0);
-	rc->proc_root_entry =
-	    debug_create_proc_dir_entry(debug_proc_root_entry, rc->name,
-					S_IFDIR | S_IRUGO | S_IXUGO |
-					S_IWUSR | S_IWGRP, NULL, NULL);
+        /* create new debug_info */
+
+	rc = debug_info_create(name, page_order, nr_areas, buf_size);
+	if(!rc) 
+		goto out;
 	debug_register_view(rc, &debug_level_view);
-	debug_info_get(rc);
 	printk(KERN_INFO
 	       "debug: reserved %d areas of %d pages for debugging %s\n",
 	       nr_areas, 1 << page_order, rc->name);
       out:
         if (rc == NULL){
 		printk(KERN_ERR "debug: debug_register failed for %s\n",name);
-#ifdef MODULE
 		MOD_DEC_USE_COUNT;
-#endif
         }
 	up(&debug_lock);
 	return rc;
@@ -609,20 +690,44 @@
 	debug_info_put(id);
 	up(&debug_lock);
 
-#ifdef MODULE
 	MOD_DEC_USE_COUNT;
-#endif
       out:
 	return;
 }
 
+/*
+ * debug_set_level:
+ * - set actual debug level
+ */
+
+void debug_set_level(debug_info_t* id, int new_level)
+{
+	unsigned long flags;
+	if(!id)
+		return;	
+	spin_lock_irqsave(&id->lock,flags);
+        if(new_level == DEBUG_OFF_LEVEL){
+                id->level = DEBUG_OFF_LEVEL;
+                printk(KERN_INFO "debug: %s: switched off\n",id->name);
+        } else if ((new_level > DEBUG_MAX_LEVEL) || (new_level < 0)) {
+                printk(KERN_INFO
+                        "debug: %s: level %i is out of range (%i - %i)\n",
+                        id->name, new_level, 0, DEBUG_MAX_LEVEL);
+        } else {
+                id->level = new_level;
+                printk(KERN_INFO 
+			"debug: %s: new level %i\n",id->name,id->level);
+        }
+	spin_unlock_irqrestore(&id->lock,flags);
+}
+
 
 /*
  * proceed_active_entry:
  * - set active entry to next in the ring buffer
  */
 
-static inline void proceed_active_entry(debug_info_t * id)
+extern inline void proceed_active_entry(debug_info_t * id)
 {
 	if ((id->active_entry[id->active_area] += id->entry_size)
 	    > ((PAGE_SIZE << (id->page_order)) - id->entry_size))
@@ -634,7 +739,7 @@
  * - set active area to next in the ring buffer
  */
 
-static inline void proceed_active_area(debug_info_t * id)
+extern inline void proceed_active_area(debug_info_t * id)
 {
 	id->active_area++;
 	id->active_area = id->active_area % id->nr_areas;
@@ -644,7 +749,7 @@
  * get_active_entry:
  */
 
-static inline debug_entry_t *get_active_entry(debug_info_t * id)
+extern inline debug_entry_t *get_active_entry(debug_info_t * id)
 {
 	return (debug_entry_t *) ((char *) id->areas[id->active_area] +
 				  id->active_entry[id->active_area]);
@@ -655,162 +760,126 @@
  * - set timestamp, caller address, cpu number etc.
  */
 
-static inline debug_entry_t *debug_common(debug_info_t * id)
+extern inline debug_entry_t *debug_common(debug_info_t * id, int level, 
+                                    const void *buf, int len, int exception)
 {
+	unsigned long flags;
 	debug_entry_t *active;
 
+	spin_lock_irqsave(&id->lock, flags);
 	active = get_active_entry(id);
 	STCK(active->id.stck);
 	active->id.fields.cpuid = smp_processor_id();
-	active->id.fields.used = 1;
 	active->caller = __builtin_return_address(0);
-	return active;
-}
-
-/*
- * debug_event:
- */
-
-debug_entry_t *debug_event(debug_info_t * id, int level, void *buf,
-			   int len)
-{
-	long flags;
-	debug_entry_t *active = NULL;
-
-	if ((!id) || (level < id->level))
-		goto out;
-	spin_lock_irqsave(&id->lock, flags);
-	active = debug_common(id);
-	active->id.fields.exception = 0;
-	memset(active->data, 0, id->buf_size);
-	memcpy(active->data, buf, MIN(len, id->buf_size));
+	active->id.fields.exception = exception;
+	active->id.fields.level     = level;
+	memset(DEBUG_DATA(active), 0, id->buf_size);
+	memcpy(DEBUG_DATA(active), buf, MIN(len, id->buf_size));
 	proceed_active_entry(id);
+	if(exception)
+		proceed_active_area(id);
 	spin_unlock_irqrestore(&id->lock, flags);
-      out:
+
 	return active;
 }
 
 /*
- * debug_int_event:
+ * debug_event_common:
+ * - write debug entry with given size
  */
 
-debug_entry_t *debug_int_event(debug_info_t * id, int level,
-			       unsigned int tag)
+debug_entry_t *debug_event_common(debug_info_t * id, int level, const void *buf,
+			          int len)
 {
-	long flags;
-	debug_entry_t *active = NULL;
-
-	if ((!id) || (level < id->level))
-		goto out;
-	spin_lock_irqsave(&id->lock, flags);
-	active = debug_common(id);
-	active->id.fields.exception = 0;
-	memset(active->data, 0, id->buf_size);
-	memcpy(active->data, &tag, MIN(sizeof(unsigned int), id->buf_size));
-	proceed_active_entry(id);
-	spin_unlock_irqrestore(&id->lock, flags);
-      out:
-	return active;
+	return debug_common(id, level, buf, len, 0);
 }
 
 /*
- * debug_text_event:
+ * debug_exception_common:
+ * - write debug entry with given size and switch to next debug area
  */
 
-debug_entry_t *debug_text_event(debug_info_t * id, int level,
-				const char *txt)
+debug_entry_t *debug_exception_common(debug_info_t * id, int level, 
+                                      const void *buf, int len)
 {
-	long flags;
-	debug_entry_t *active = NULL;
-
-	if ((!id) || (level < id->level))
-		goto out;
-	spin_lock_irqsave(&id->lock, flags);
-	active = debug_common(id);
-	memset(active->data, 0, id->buf_size);
-	strncpy(active->data, txt, MIN(strlen(txt), id->buf_size));
-	ASCEBC(active->data, MIN(strlen(txt), id->buf_size));
-	active->id.fields.exception = 0;
-	proceed_active_entry(id);
-	spin_unlock_irqrestore(&id->lock, flags);
-      out:
-	return active;
-
+	return debug_common(id, level, buf, len, 1);
 }
 
 /*
- * debug_exception:
+ * counts arguments in format string for sprintf view
  */
 
-debug_entry_t *debug_exception(debug_info_t * id, int level, void *buf,
-			       int len)
+extern inline int debug_count_numargs(char *string)
 {
-	long flags;
-	debug_entry_t *active = NULL;
+	int numargs=0;
 
-	if ((!id) || (level < id->level))
-		goto out;
-	spin_lock_irqsave(&id->lock, flags);
-	active = debug_common(id);
-	active->id.fields.exception = 1;
-	memset(active->data, 0, id->buf_size);
-	memcpy(active->data, buf, MIN(len, id->buf_size));
-	proceed_active_entry(id);
-	proceed_active_area(id);
-	spin_unlock_irqrestore(&id->lock, flags);
-      out:
-	return active;
+	while(*string) {
+		if(*string++=='%')
+			numargs++;
+	}
+	return(numargs);
 }
 
 /*
- * debug_int_exception:
+ * debug_sprintf_event:
  */
 
-debug_entry_t *debug_int_exception(debug_info_t * id, int level,
-				   unsigned int tag)
+debug_entry_t *debug_sprintf_event(debug_info_t* id,
+                                   int level,char *string,...)
 {
-	long flags;
-	debug_entry_t *active = NULL;
+	va_list   ap;
+	int numargs,alloc_size,idx;
+	debug_sprintf_entry *curr_event;
+	debug_entry_t *retval = NULL;
 
-	if ((!id) || (level < id->level))
-		goto out;
-	spin_lock_irqsave(&id->lock, flags);
-	active = debug_common(id);
-	active->id.fields.exception = 1;
-	memset(active->data, 0, id->buf_size);
-	memcpy(active->data, &tag,
-	       MIN(sizeof(unsigned int), id->buf_size));
-	proceed_active_entry(id);
-	proceed_active_area(id);
-	spin_unlock_irqrestore(&id->lock, flags);
-      out:
-	return active;
+	if((!id) || (level > id->level))
+		return NULL;
+	else {
+		numargs=debug_count_numargs(string);
+		alloc_size=offsetof(debug_sprintf_entry,args[numargs]);
+		curr_event=alloca(alloc_size);
+
+		if(curr_event){
+			va_start(ap,string);
+			curr_event->string=string;
+			for(idx=0;idx<numargs;idx++)
+				curr_event->args[idx]=va_arg(ap,long);
+			retval=debug_common(id,level, curr_event,alloc_size,0);
+			va_end(ap);
+		}
+		return retval;
+	}
 }
 
 /*
- * debug_text_exception:
+ * debug_sprintf_exception:
  */
 
-debug_entry_t *debug_text_exception(debug_info_t * id, int level,
-				    const char *txt)
+debug_entry_t *debug_sprintf_exception(debug_info_t* id,
+                                       int level,char *string,...)
 {
-	long flags;
-	debug_entry_t *active = NULL;
-
-	if ((!id) || (level < id->level))
-		goto out;
-	spin_lock_irqsave(&id->lock, flags);
-	active = debug_common(id);
-	memset(active->data, 0, id->buf_size);
-	strncpy(active->data, txt, MIN(strlen(txt), id->buf_size));
-	ASCEBC(active->data, MIN(strlen(txt), id->buf_size));
-	active->id.fields.exception = 1;
-	proceed_active_entry(id);
-	proceed_active_area(id);
-	spin_unlock_irqrestore(&id->lock, flags);
-      out:
-	return active;
+	va_list   ap;
+	int numargs,alloc_size,idx;
+	debug_sprintf_entry *curr_event;
+	debug_entry_t *retval = NULL;
 
+	if((!id) || (level > id->level))
+		return NULL;
+	else {
+		numargs=debug_count_numargs(string);
+		alloc_size=offsetof(debug_sprintf_entry,args[numargs]);
+		curr_event=alloca(alloc_size);
+
+		if(curr_event){
+			va_start(ap,string);
+			curr_event->string=string;
+			for(idx=0;idx<numargs;idx++)
+				curr_event->args[idx]=va_arg(ap,long);
+			retval=debug_common(id,level, curr_event,alloc_size,1);
+			va_end(ap);
+		}
+		return retval;
+	}
 }
 
 /*
@@ -821,7 +890,6 @@
 int debug_init(void)
 {
 	int rc = 0;
-	int i;
 
 	down(&debug_lock);
 	if (!initialized) {
@@ -830,15 +898,7 @@
 						S_IFDIR | S_IRUGO | S_IXUGO
 						| S_IWUSR | S_IWGRP, NULL,
 						NULL);
-		for (i = 0; i < DEBUG_MAX_AREAS - 1; i++) {
-			*(debug_info_t **) (&debug_areas[i]) =
-			    (debug_info_t *) (&debug_areas[i + 1]);
-		}
-		*(debug_info_t **) (&debug_areas[i]) = (debug_info_t *) NULL;
-		free_area = &(debug_areas[0]);
-		printk(KERN_INFO
-		       "debug: %d areas reserved for debugging information\n",
-		       DEBUG_MAX_AREAS);
+		printk(KERN_INFO "debug: Initialization complete\n");
 		initialized = 1;
 	}
 	up(&debug_lock);
@@ -854,7 +914,7 @@
 {
 	int rc = 0;
 	int i;
-	long flags;
+	unsigned long flags;
 	mode_t mode = S_IFREG;
 
 	if (!id)
@@ -897,7 +957,7 @@
 {
 	int rc = 0;
 	int i;
-	long flags;
+	unsigned long flags;
 
 	if (!id)
 		goto out;
@@ -933,12 +993,8 @@
 {
 	int rc = 0;
 
-	if (out_buf == NULL) {
-		rc = 2;
-		goto out;
-	}
-	rc = sprintf(out_buf, "%i\n", id->level);
-      out:
+	if(id->level == -1) rc = sprintf(out_buf,"-\n");
+	else rc = sprintf(out_buf, "%i\n", id->level);
 	return rc;
 }
 
@@ -955,20 +1011,15 @@
 
 	if (*offset != 0)
 		goto out;
-	if ((rc = copy_from_user(input_buf, user_buf, 1)))
+	if (copy_from_user(input_buf, user_buf, 1)){
+		rc = -EFAULT;
 		goto out;
+	}
 	if (isdigit(input_buf[0])) {
 		int new_level = ((int) input_buf[0] - (int) '0');
-		if ((new_level > DEBUG_MAX_LEVEL) || (new_level < 0)) {
-			printk(KERN_INFO
-			       "debug: level %i is out of range (%i - %i)\n",
-			       new_level, 0, DEBUG_MAX_LEVEL);
-		} else {
-			id->level = new_level;
-			printk(KERN_INFO
-			       "debug: set new level %i for %s\n",
-			       id->level, id->name);
-		}
+		debug_set_level(id, new_level);
+	} else if(input_buf[0] == '-') {
+		debug_set_level(id, DEBUG_OFF_LEVEL);
 	} else {
 		printk(KERN_INFO "debug: level `%c` is not valid\n",
 		       input_buf[0]);
@@ -979,72 +1030,55 @@
 }
 
 /*
- * prints debug data in hex format
+ * prints debug header in raw format
  */
 
-static int debug_hex_format_fn(debug_info_t * id, struct debug_view *view,
-			       char *out_buf, const char *in_buf)
+int debug_raw_header_fn(debug_info_t * id, struct debug_view *view,
+                         int area, debug_entry_t * entry, char *out_buf)
 {
-	int i, rc = 0;
+        int rc;
 
-	if (out_buf == NULL || in_buf == NULL) {
-		rc = id->buf_size * 3;
-		goto out;
-	}
-	for (i = 0; i < id->buf_size; i++) {
-		rc += sprintf(out_buf + rc, "%02x ",
-			      ((unsigned char *) in_buf)[i]);
-	}
-      out:
-	return rc;
+	rc = sizeof(debug_entry_t);
+	memcpy(out_buf,entry,sizeof(debug_entry_t));
+        return rc;
 }
 
 /*
- * prints debug data in ascii format
+ * prints debug data in raw format
  */
 
-static int debug_ascii_format_fn(debug_info_t * id, struct debug_view *view, 
-				 char *out_buf, const char *in_buf)
+static int debug_raw_format_fn(debug_info_t * id, struct debug_view *view,
+			       char *out_buf, const char *in_buf)
 {
-	int i, rc = 0;
+	int rc;
 
-	if (out_buf == NULL || in_buf == NULL) {
-		rc = id->buf_size;
-		goto out;
-	}
-	for (i = 0; i < id->buf_size; i++) {
-		unsigned char c = in_buf[i];
-		if (!isprint(c))
-			rc += sprintf(out_buf + rc, ".");
-		else
-			rc += sprintf(out_buf + rc, "%c", c);
-	}
-      out:
+	rc = id->buf_size;
+	memcpy(out_buf, in_buf, id->buf_size);
 	return rc;
 }
 
 /*
- * prints debug data in ebcdic format
+ * prints debug data in hex/ascii format
  */
 
-static int debug_ebcdic_format_fn(debug_info_t * id, struct debug_view *view, 
-				  char *out_buf, const char *in_buf)
+static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view,
+		    		  char *out_buf, const char *in_buf)
 {
 	int i, rc = 0;
 
-	if (out_buf == NULL || in_buf == NULL) {
-		rc = id->buf_size;
-		goto out;
-	}
+	for (i = 0; i < id->buf_size; i++) {
+                rc += sprintf(out_buf + rc, "%02x ",
+                              ((unsigned char *) in_buf)[i]);
+        }
+	rc += sprintf(out_buf + rc, "| ");
 	for (i = 0; i < id->buf_size; i++) {
 		unsigned char c = in_buf[i];
-		EBCASC(&c, 1);
 		if (!isprint(c))
 			rc += sprintf(out_buf + rc, ".");
 		else
 			rc += sprintf(out_buf + rc, "%c", c);
 	}
-      out:
+	rc += sprintf(out_buf + rc, "\n");
 	return rc;
 }
 
@@ -1060,12 +1094,9 @@
 	char *except_str;
 	unsigned long caller;
 	int rc = 0;
+	unsigned int level;
 
-	if (out_buf == NULL) {
-		rc = DEBUG_PROC_HEADER_SIZE;
-		goto out;
-	}
-
+	level = entry->id.fields.level;
 	time = entry->id.stck;
 	/* adjust todclock to 1970 */
 	time -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096);
@@ -1076,14 +1107,61 @@
 	else
 		except_str = "-";
 	caller = (unsigned long) entry->caller;
-#if defined(CONFIG_ARCH_S390)
+#if defined(CONFIG_ARCH_S390X)
+	rc += sprintf(out_buf, "%02i %011lu:%06lu %1u %1s %02i %016lx  ",
+		      area, time_val.tv_sec, time_val.tv_usec, level,
+		      except_str, entry->id.fields.cpuid, caller);
+#else
 	caller &= 0x7fffffff;
-	rc += sprintf(out_buf, "%02i %011lu:%06lu %1s %02i %08lx  ",
-		      area, time_val.tv_sec,
-		      time_val.tv_usec, except_str,
-		      entry->id.fields.cpuid, caller);
+	rc += sprintf(out_buf, "%02i %011lu:%06lu %1u %1s %02i %08lx  ",
+		      area, time_val.tv_sec, time_val.tv_usec, level,
+		      except_str, entry->id.fields.cpuid, caller);
 #endif
-      out:
+	return rc;
+}
+
+/*
+ * prints debug data sprintf-formated:
+ * debug_sprinf_event/exception calls must be used together with this view
+ */
+
+#define DEBUG_SPRINTF_MAX_ARGS 10
+
+int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view,
+                            char *out_buf, debug_sprintf_entry *curr_event)
+{
+	int num_longs, num_used_args = 0,i, rc = 0;
+	int index[DEBUG_SPRINTF_MAX_ARGS];
+
+	/* count of longs fit into one entry */
+	num_longs = id->buf_size /  sizeof(long); 
+
+	if(num_longs < 1)
+		goto out; /* bufsize of entry too small */
+	if(num_longs == 1) {
+		/* no args, we use only the string */
+		strcpy(out_buf, curr_event->string);
+		rc = strlen(curr_event->string);
+		goto out;
+	}
+
+	/* number of arguments used for sprintf (without the format string) */
+	num_used_args   = MIN(DEBUG_SPRINTF_MAX_ARGS, (num_longs - 1));
+
+	memset(index,0, DEBUG_SPRINTF_MAX_ARGS * sizeof(int));
+
+	for(i = 0; i < num_used_args; i++)
+		index[i] = i;
+
+	rc =  sprintf(out_buf, curr_event->string, curr_event->args[index[0]],
+		curr_event->args[index[1]], curr_event->args[index[2]],
+		curr_event->args[index[3]], curr_event->args[index[4]],
+		curr_event->args[index[5]], curr_event->args[index[6]],
+		curr_event->args[index[7]], curr_event->args[index[8]],
+		curr_event->args[index[9]]);
+
+out:
+
 	return rc;
 }
 
@@ -1118,3 +1196,17 @@
 }
 
 #endif			/* MODULE */
+
+EXPORT_SYMBOL(debug_register);
+EXPORT_SYMBOL(debug_unregister); 
+EXPORT_SYMBOL(debug_set_level);
+EXPORT_SYMBOL(debug_register_view);
+EXPORT_SYMBOL(debug_unregister_view);
+EXPORT_SYMBOL(debug_event_common);
+EXPORT_SYMBOL(debug_exception_common);
+EXPORT_SYMBOL(debug_hex_ascii_view);
+EXPORT_SYMBOL(debug_raw_view);
+EXPORT_SYMBOL(debug_dflt_header_fn);
+EXPORT_SYMBOL(debug_sprintf_view);
+EXPORT_SYMBOL(debug_sprintf_exception);
+EXPORT_SYMBOL(debug_sprintf_event);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/ebcdic.c linux.19p18/arch/s390/kernel/ebcdic.c
--- linux.vanilla/arch/s390/kernel/ebcdic.c	Sun Jun 11 21:44:09 2000
+++ linux.19p18/arch/s390/kernel/ebcdic.c	Mon Feb 19 18:33:37 2001
@@ -9,6 +9,7 @@
  *               Martin Peschke <peschke@fh-brandenburg.de>
  */
 
+#include <linux/module.h>
 #include <asm/types.h>
 
 /*
@@ -389,3 +390,11 @@
 	0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
 	0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
 };
+
+EXPORT_SYMBOL_NOVERS(_ascebc_500);
+EXPORT_SYMBOL_NOVERS(_ebcasc_500);
+EXPORT_SYMBOL_NOVERS(_ascebc);
+EXPORT_SYMBOL_NOVERS(_ebcasc);
+EXPORT_SYMBOL_NOVERS(_ebc_tolower);
+EXPORT_SYMBOL_NOVERS(_ebc_toupper);
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/entry.S linux.19p18/arch/s390/kernel/entry.S
--- linux.vanilla/arch/s390/kernel/entry.S	Mon Dec 11 22:12:36 2000
+++ linux.19p18/arch/s390/kernel/entry.S	Mon Feb 19 18:37:49 2001
@@ -148,11 +148,11 @@
         xc      0(4,%r15),0(%r15)     ; /* clear back chain */
 
 #define RESTORE_ALL \
-        mvc     __LC_RETURN_PSW(8,0),SP_PSW(%r15) ; /* move user PSW to lowcore */ \
+        mvc     __LC_RETURN_PSW(8),SP_PSW(%r15) ; /* move user PSW to lowcore */ \
         lam     %a0,%a15,SP_AREGS(%r15) ; /* load the access registers */ \
-        lm      %r0,%r15,SP_R0(%r15)      ; /* load gprs 0-15 of user */ \
-        ni      __LC_RETURN_PSW+1(0),0xfd ; /* clear wait state bit */ \
-        lpsw    __LC_RETURN_PSW             /* back to caller */
+        lm      %r0,%r15,SP_R0(%r15)    ; /* load gprs 0-15 of user */ \
+        ni      __LC_RETURN_PSW+1,0xfd  ; /* clear wait state bit */ \
+        lpsw    __LC_RETURN_PSW           /* back to caller */
 
 #define GET_CURRENT /* load pointer to task_struct to R9 */ \
 	lr      %r9,%r15 ;  \
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/head.S linux.19p18/arch/s390/kernel/head.S
--- linux.vanilla/arch/s390/kernel/head.S	Mon Dec 11 22:12:36 2000
+++ linux.19p18/arch/s390/kernel/head.S	Mon Feb 19 18:37:49 2001
@@ -5,7 +5,7 @@
  *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
  *    Author(s): Hartmut Penner (hp@de.ibm.com),
  *               Martin Schwidefsky (schwidefsky@de.ibm.com),
- *               Rob van der Heij
+ *               Rob van der Heij (rvdhei@iae.nl)
  *
  * There are 5 different IPL methods
  *  1) load the image directly into ram at address 0 and do an PSW restart
@@ -13,11 +13,18 @@
  *     and start the code thru LPSW 0x0008000080010000 (VM only, deprecated)
  *  3) generate the tape ipl header, store the generated image on a tape
  *     and ipl from it
+ *     In case of SL tape you need to IPL 5 times to get past VOL1 etc
  *  4) generate the vm reader ipl header, move the generated image to the
  *     VM reader (use option NOH!) and do a ipl from reader (VM only)
  *  5) direct call of start by the SALIPL loader
  *  We use the cpuid to distinguish between VM and native ipl
  *  params for kernel are pushed to 0x10400 (see setup.h)
+
+    Changes: 
+    Okt 25 2000 <rvdheij@iae.nl>
+	added code to skip HDR and EOF to allow SL tape IPL (5 retries)
+	changed first CCW from rewind to backspace block
+
  */
 
 #include <linux/config.h>
@@ -32,7 +39,7 @@
 #define IPL_BS 1024
         .org   0
         .long  0x00080000,0x80000000+iplstart  # The first 24 bytes are loaded
-        .long  0x07000000,0x60000001           # by ipl to addresses 0-23.
+        .long  0x27000000,0x60000001           # by ipl to addresses 0-23.
         .long  0x02000000,0x20000000+IPL_BS    # (a PSW and two CCWs).
         .long  0x00000000,0x00000000           # external old psw
         .long  0x00000000,0x00000000           # svc old psw
@@ -140,7 +147,7 @@
 .Lcrash:.long  0x000a0000,0x00000000
 .Lldret:.long  0
 .Lsnsret: .long 0
-#endif  /* CONFIG_IPL_NONE */
+#endif  /* CONFIG_IPL_TAPE */
 
 #ifdef CONFIG_IPL_VM
 #define IPL_BS 0x730
@@ -260,6 +267,7 @@
 #
 # load parameter file from ipl device
 #
+.Lagain1:
  	l     %r2,INITRD_START-PARMAREA(%r12)  # use ramdisk location as temp
         bas   %r14,.Lloader                    # load parameter file
         ltr   %r2,%r2                          # got anything ?
@@ -269,6 +277,10 @@
 	la    %r2,895
 .Lnotrunc:
 	l     %r4,INITRD_START-PARMAREA(%r12)
+	clc   0(3,%r4),.L_hdr		       # if it is HDRx
+	bz    .Lagain1			       # skip dataset header
+	clc   0(3,%r4),.L_eof		       # if it is EOFx
+	bz    .Lagain1			       # skip dateset trailer
         la    %r5,0(%r4,%r2)
         lr    %r3,%r2
 .Lidebc:
@@ -306,6 +318,7 @@
 #
 # load ramdisk from ipl device
 #	
+.Lagain2:
  	l     %r2,INITRD_START-PARMAREA(%r12)  # load adr. of ramdisk
         bas   %r14,.Lloader                    # load ramdisk
  	st    %r2,INITRD_SIZE-PARMAREA(%r12)   # store size of ramdisk
@@ -313,6 +326,12 @@
         bnz   .Lrdcont
         st    %r2,INITRD_START-PARMAREA(%r12)  # no ramdisk found, null it
 .Lrdcont:
+	l     %r2,INITRD_START-PARMAREA(%r12)
+
+	clc   0(3,%r2),.L_hdr		       # skip HDRx and EOFx 
+	bz    .Lagain2
+	clc   0(3,%r2),.L_eof
+	bz    .Lagain2
 
 #ifdef CONFIG_IPL_VM
 #
@@ -340,7 +359,8 @@
 .Lreset:.byte  0xc3,0xc8,0xc1,0xd5,0xc7,0xc5,0x40,0xd9,0xc4,0xd9,0x40
         .byte  0xc1,0xd3,0xd3,0x40,0xd2,0xc5,0xc5,0xd7,0x40,0xd5,0xd6
         .byte  0xc8,0xd6,0xd3,0xc4             # "change rdr all keep nohold"
-
+.L_eof:	.long  0xc5d6c600	/* C'EOF' */
+.L_hdr:	.long  0xc8c4d900	/* C'HDR' */
 #endif  /* CONFIG_IPL */
 
 #
@@ -375,7 +395,7 @@
 	.long 0x83300060		# diag 3,0,x'0060' - storage size
 	b     .done
 .test:
-	mvc   0x68(8,0),.pgmnw		# set up pgm check handler
+	mvc   0x68(8),.pgmnw		# set up pgm check handler
 	l     %r2,.fourmeg
 	lr    %r3,%r2
 	bctr  %r3,%r0			# 4M-1
@@ -443,7 +463,7 @@
 #
 # find out memory size.
 #
-	mvc   104(8,0),.Lpcmem-.LPG1(%r13) # setup program check handler
+	mvc   104(8),.Lpcmem-.LPG1(%r13) # setup program check handler
         slr   %r1,%r1
         lhi   %r2,1
         sll   %r2,20
@@ -507,7 +527,7 @@
 #
 # find out if we have an IEEE fpu
 #
-        mvc    104(8,0),.Lpcfpu-.LPG1(%r13) # setup program check handler
+        mvc    104(8),.Lpcfpu-.LPG1(%r13) # setup program check handler
         ld     %f0,.Lflt0-.LPG1(%r13)   # load (float) 0.0
         ldr    %f2,%f0
         adbr   %f0,%f2                  # test IEEE add instruction
@@ -517,7 +537,7 @@
 #
 # find out if we have the CSP instruction
 #
-       mvc    104(8,0),.Lpccsp-.LPG1(%r13) # setup program check handler
+       mvc    104(8),.Lpccsp-.LPG1(%r13) # setup program check handler
        la     %r0,0
        lr     %r1,%r0
        la     %r2,.Lflt0-.LPG1(%r13)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/irq.c linux.19p18/arch/s390/kernel/irq.c
--- linux.vanilla/arch/s390/kernel/irq.c	Mon Dec 11 22:12:36 2000
+++ linux.19p18/arch/s390/kernel/irq.c	Mon Feb 19 18:33:37 2001
@@ -11,6 +11,7 @@
  *  S/390 I/O interrupt processing and I/O request processing is
  *   implemented in arch/s390/kernel/s390io.c
  */
+#include <linux/module.h>
 #include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/kernel_stat.h>
@@ -426,3 +427,12 @@
 
 }
 
+#ifdef CONFIG_SMP
+EXPORT_SYMBOL(s390_bh_lock);
+EXPORT_SYMBOL(__global_cli);
+EXPORT_SYMBOL(__global_sti);
+EXPORT_SYMBOL(__global_save_flags);
+EXPORT_SYMBOL(__global_restore_flags);
+EXPORT_SYMBOL(global_bh_lock);
+EXPORT_SYMBOL(synchronize_bh);
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/reipl.S linux.19p18/arch/s390/kernel/reipl.S
--- linux.vanilla/arch/s390/kernel/reipl.S	Sun Jun 11 21:44:09 2000
+++ linux.19p18/arch/s390/kernel/reipl.S	Mon Feb 19 18:37:49 2001
@@ -16,7 +16,7 @@
                 ni      .Lctlsave-.Lpg0(%r13),0xef
                 lctl    %c0,%c0,.Lctlsave-.Lpg0(%r13)
                 lr      %r1,%r2
-        	mvc     __LC_PGM_NEW_PSW(8,0),.Lpcnew-.Lpg0(%r13)
+        	mvc     __LC_PGM_NEW_PSW(8),.Lpcnew-.Lpg0(%r13)
                 stsch   .Lschib-.Lpg0(%r13)                                    
 	        oi      .Lschib+5-.Lpg0(%r13),0x84 
 .Lecs:  	xi      .Lschib+27-.Lpg0(%r13),0x01 
@@ -24,9 +24,9 @@
 		ssch	.Liplorb-.Lpg0(%r13)           
 		jz	.L001   
 		bas	%r14,.Ldisab-.Lpg0(%r13)
-.L001:		mvc	__LC_IO_NEW_PSW(8,0),.Lionew-.Lpg0(%r13)	
+.L001:		mvc	__LC_IO_NEW_PSW(8),.Lionew-.Lpg0(%r13)	
 .Ltpi:		lpsw	.Lwaitpsw-.Lpg0(%r13)          
-.Lcont:		c	%r1,__LC_SUBCHANNEL_ID(%r0)
+.Lcont:		c	%r1,__LC_SUBCHANNEL_ID
 		jnz	.Ltpi
 		clc	__LC_IO_INT_PARM(4),.Liplorb-.Lpg0(%r13)
 		jnz	.Ltpi
@@ -38,7 +38,7 @@
                 jz      .L003
                 bas     %r14,.Ldisab-.Lpg0(%r13)	
 .L003:		spx	.Lnull-.Lpg0(%r13)
-		st 	%r1,__LC_SUBCHANNEL_ID(%r0)	
+		st 	%r1,__LC_SUBCHANNEL_ID
                 lpsw 	0
 		sigp    0,0,0(6)               
 .Ldisab:	st      %r14,.Ldispsw+4-.Lpg0(%r13)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/s390_ext.c linux.19p18/arch/s390/kernel/s390_ext.c
--- linux.vanilla/arch/s390/kernel/s390_ext.c	Mon Dec 11 22:12:36 2000
+++ linux.19p18/arch/s390/kernel/s390_ext.c	Mon Feb 19 18:33:37 2001
@@ -9,6 +9,7 @@
 
 #include <linux/kernel.h>
 #include <linux/malloc.h>
+#include <linux/module.h>
 #include <asm/lowcore.h>
 #include <asm/s390_ext.h>
 
@@ -74,4 +75,6 @@
         return 0;
 }
 
+EXPORT_SYMBOL(register_external_interrupt);
+EXPORT_SYMBOL(unregister_external_interrupt);
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/s390_ksyms.c linux.19p18/arch/s390/kernel/s390_ksyms.c
--- linux.vanilla/arch/s390/kernel/s390_ksyms.c	Mon Dec 11 22:12:36 2000
+++ linux.19p18/arch/s390/kernel/s390_ksyms.c	Mon Feb 19 18:33:37 2001
@@ -3,71 +3,15 @@
  *
  *  S390 version
  */
-#include <linux/config.h>
 #include <linux/module.h>
-#include <linux/interrupt.h>
-#include <asm/debug.h>
 #include <linux/genhd.h>
-#include <asm/ccwcache.h>
-#include <asm/irq.h>
-#include <asm/string.h>
 #include <asm/checksum.h>
-#include <asm/s390_ext.h>
-#include <asm/s390dyn.h>
-#include <asm/ebcdic.h>
-#include <asm/timex.h>
 #include <asm/delay.h>
 #if CONFIG_IP_MULTICAST
 #include <net/arp.h>
 #endif
 
 /*
- * I/O subsystem
- */
-EXPORT_SYMBOL(halt_IO);
-EXPORT_SYMBOL(clear_IO);
-EXPORT_SYMBOL(do_IO);
-EXPORT_SYMBOL(resume_IO);
-EXPORT_SYMBOL(ioinfo);
-EXPORT_SYMBOL(get_dev_info_by_irq);
-EXPORT_SYMBOL(get_dev_info_by_devno);
-EXPORT_SYMBOL(get_irq_by_devno);
-EXPORT_SYMBOL(get_devno_by_irq);
-EXPORT_SYMBOL(get_irq_first);
-EXPORT_SYMBOL(get_irq_next);
-EXPORT_SYMBOL(read_conf_data);
-EXPORT_SYMBOL(read_dev_chars);
-EXPORT_SYMBOL(s390_request_irq_special);
-EXPORT_SYMBOL(s390_device_register);
-EXPORT_SYMBOL(s390_device_unregister);
-
-EXPORT_SYMBOL(s390_bh_lock);
-
-EXPORT_SYMBOL(ccw_alloc_request);
-EXPORT_SYMBOL(ccw_free_request);
-
-EXPORT_SYMBOL(register_external_interrupt);
-EXPORT_SYMBOL(unregister_external_interrupt);
-
-/* 
- * debug feature
- */
-EXPORT_SYMBOL(debug_register);
-EXPORT_SYMBOL(debug_unregister); 
-EXPORT_SYMBOL(debug_register_view);
-EXPORT_SYMBOL(debug_unregister_view);
-EXPORT_SYMBOL(debug_event);
-EXPORT_SYMBOL(debug_int_event);
-EXPORT_SYMBOL(debug_text_event);
-EXPORT_SYMBOL(debug_exception);
-EXPORT_SYMBOL(debug_int_exception);
-EXPORT_SYMBOL(debug_text_exception);
-EXPORT_SYMBOL(debug_hex_view);
-EXPORT_SYMBOL(debug_ascii_view);
-EXPORT_SYMBOL(debug_ebcdic_view);
-EXPORT_SYMBOL(debug_dflt_header_fn);
-
-/*
  * memory management
  */
 EXPORT_SYMBOL(init_mm);
@@ -92,32 +36,12 @@
 EXPORT_SYMBOL_NOVERS(strpbrk);
 EXPORT_SYMBOL_NOVERS(strstr);
 
-EXPORT_SYMBOL_NOVERS(_ascebc_500);
-EXPORT_SYMBOL_NOVERS(_ebcasc_500);
-EXPORT_SYMBOL_NOVERS(_ascebc);
-EXPORT_SYMBOL_NOVERS(_ebcasc);
-EXPORT_SYMBOL_NOVERS(_ebc_tolower);
-EXPORT_SYMBOL_NOVERS(_ebc_toupper);
-
 /*
  * misc.
  */
 EXPORT_SYMBOL(__copy_from_user_fixup);
 EXPORT_SYMBOL(__copy_to_user_fixup);
 EXPORT_SYMBOL(__udelay);
-#ifdef CONFIG_SMP
-#include <asm/smplock.h>
-EXPORT_SYMBOL(__global_cli);
-EXPORT_SYMBOL(__global_sti);
-EXPORT_SYMBOL(__global_save_flags);
-EXPORT_SYMBOL(__global_restore_flags);
-EXPORT_SYMBOL(global_bh_lock);
-EXPORT_SYMBOL(synchronize_bh);
-EXPORT_SYMBOL(kernel_flag);
-EXPORT_SYMBOL(smp_ctl_set_bit);
-EXPORT_SYMBOL(smp_ctl_clear_bit);
-EXPORT_SYMBOL(smp_do_callback_all);
-#endif
 EXPORT_SYMBOL(kernel_thread);
 EXPORT_SYMBOL(csum_fold);
 EXPORT_SYMBOL(genhd_dasd_name);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/s390dyn.c linux.19p18/arch/s390/kernel/s390dyn.c
--- linux.vanilla/arch/s390/kernel/s390dyn.c	Mon Dec 11 22:12:36 2000
+++ linux.19p18/arch/s390/kernel/s390dyn.c	Mon Feb 19 18:33:37 2001
@@ -7,6 +7,7 @@
  *    Author(s): Ingo Adlung (adlung@de.ibm.com)
  */
 
+#include <linux/module.h>
 #include <linux/init.h>
 #include <linux/smp_lock.h>
 
@@ -204,3 +205,5 @@
 	return( pdevreg);
 }
 
+EXPORT_SYMBOL(s390_device_register);
+EXPORT_SYMBOL(s390_device_unregister);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/s390io.c linux.19p18/arch/s390/kernel/s390io.c
--- linux.vanilla/arch/s390/kernel/s390io.c	Mon Dec 11 22:12:36 2000
+++ linux.19p18/arch/s390/kernel/s390io.c	Sun Feb 25 23:10:55 2001
@@ -8,6 +8,7 @@
  *    Author(s): Ingo Adlung (adlung@de.ibm.com)
  */
 
+#include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/kernel_stat.h>
 #include <linux/signal.h>
@@ -126,7 +127,7 @@
                               not_oper_handler_func_t  not_oper_handler,
                               unsigned long            irqflags,
                               const char              *devname,
-                              void                    *dev_id)
+                              devstat_t               *dev_id)
 {
 	int               retval;
 	struct s390_irqaction *action;
@@ -204,7 +205,7 @@
                                    NULL,
                                    irqflags,
                                    devname,
-                                   dev_id);
+                                   (devstat_t *)dev_id);
 
 	if ( ret == 0 )
 	{
@@ -2041,6 +2042,7 @@
 	int               ending_status   = 0;
 	int               allow4handler   = 1;
 	int               chnchk          = 0;
+	devstat_t        *dp;
 #if 0
 	int               cpu             = smp_processor_id();
 
@@ -2058,7 +2060,8 @@
 		action = ioinfo[irq]->irq_desc.action;
 	
   	} /* endif */
-
+	dp  = &ioinfo[irq]->devstat;
+	
 #ifdef CONFIG_DEBUG_IO
 	/*
 	 * It might be possible that a device was not-oper. at the time
@@ -2176,8 +2179,26 @@
 		chnchk = 1;
 
 	} /* endif */
+	if( dp->ii.irb.scsw.ectl==0)
+	{
+		issense=0;
+	}
+	else if (    (dp->ii.irb.scsw.stctl == SCSW_STCTL_STATUS_PEND)
+	     &&	(dp->ii.irb.scsw.eswf  == 0                     ))
+	{
+		issense = 0;
+	}
+	else if (    (dp->ii.irb.scsw.stctl ==
+	                (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_INTER_STATUS)) 
+	          && ((dp->ii.irb.scsw.actl & SCSW_ACTL_SUSPENDED) == 0))
+	{
+		issense = 0;
+	}
+	else
+	{
+		issense = dp->ii.irb.esw.esw0.erw.cons;
 
-	issense = ioinfo[irq]->devstat.ii.irb.esw.esw0.erw.cons;
+	} /* endif */
 
 	if ( issense )
 	{
@@ -5524,3 +5545,17 @@
 	do_reipl( 0x10000 | sch );
 }
 
+EXPORT_SYMBOL(halt_IO);
+EXPORT_SYMBOL(clear_IO);
+EXPORT_SYMBOL(do_IO);
+EXPORT_SYMBOL(resume_IO);
+EXPORT_SYMBOL(ioinfo);
+EXPORT_SYMBOL(get_dev_info_by_irq);
+EXPORT_SYMBOL(get_dev_info_by_devno);
+EXPORT_SYMBOL(get_irq_by_devno);
+EXPORT_SYMBOL(get_devno_by_irq);
+EXPORT_SYMBOL(get_irq_first);
+EXPORT_SYMBOL(get_irq_next);
+EXPORT_SYMBOL(read_conf_data);
+EXPORT_SYMBOL(read_dev_chars);
+EXPORT_SYMBOL(s390_request_irq_special);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/setup.c linux.19p18/arch/s390/kernel/setup.c
--- linux.vanilla/arch/s390/kernel/setup.c	Mon Dec 11 22:12:36 2000
+++ linux.19p18/arch/s390/kernel/setup.c	Thu Dec 21 22:50:29 2000
@@ -36,6 +36,9 @@
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/smp.h>
+#include "cpcmd.h"
+
+extern void reipl(int ipl_device);
 
 /*
  * Machine setup..
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/signal.c linux.19p18/arch/s390/kernel/signal.c
--- linux.vanilla/arch/s390/kernel/signal.c	Mon Dec 11 22:12:36 2000
+++ linux.19p18/arch/s390/kernel/signal.c	Mon Feb 19 18:32:03 2001
@@ -327,6 +327,11 @@
 #endif
 	/* Martin wants this for pthreads */
 	regs->gprs[3] = (addr_t)&frame->sc;
+
+	/* We forgot to include these in the sigcontext. 
+	   To avoid breaking binary compatibility, they are passed as args. */
+	regs->gprs[4] = current->tss.trap_no;
+	regs->gprs[5] = current->tss.prot_addr;
 	return;
 
 give_sigsegv:
@@ -383,7 +388,7 @@
 	      siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
 {
 	/* Are we from a system call? */
-	if (regs->orig_gpr2 >= 0) {
+	if (regs->trap == __LC_SVC_OLD_PSW) {
 		/* If so, check system call restarting.. */
 		switch (regs->gprs[2]) {
 			case -ERESTARTNOHAND:
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/kernel/smp.c linux.19p18/arch/s390/kernel/smp.c
--- linux.vanilla/arch/s390/kernel/smp.c	Mon Dec 11 22:12:36 2000
+++ linux.19p18/arch/s390/kernel/smp.c	Mon Feb 19 18:33:37 2001
@@ -24,6 +24,7 @@
 #include <asm/timex.h>
 #include <asm/init.h>
 #include <asm/spinlock.h>
+#include <linux/module.h>
 #include <linux/stddef.h>
 #include <linux/kernel.h>
 #include <linux/kernel_stat.h>
@@ -721,3 +722,7 @@
         }
 }
 
+EXPORT_SYMBOL(kernel_flag);
+EXPORT_SYMBOL(smp_ctl_set_bit);
+EXPORT_SYMBOL(smp_ctl_clear_bit);
+EXPORT_SYMBOL(smp_do_callback_all);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/lib/strcmp.S linux.19p18/arch/s390/lib/strcmp.S
--- linux.vanilla/arch/s390/lib/strcmp.S	Fri Apr 21 12:45:48 2000
+++ linux.19p18/arch/s390/lib/strcmp.S	Mon Feb 19 18:37:49 2001
@@ -18,8 +18,8 @@
         CLST    2,3
         JO      .-4
         JE      strcmp_equal
-        IC      0,0(0,3)
-        IC      1,0(0,2)
+        IC      0,0(3)
+        IC      1,0(2)
         SR      1,0
 strcmp_equal:
         LR      2,1
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/lib/strncpy.S linux.19p18/arch/s390/lib/strncpy.S
--- linux.vanilla/arch/s390/lib/strncpy.S	Sun Jun 11 21:44:11 2000
+++ linux.19p18/arch/s390/lib/strncpy.S	Mon Feb 19 18:37:49 2001
@@ -20,9 +20,9 @@
 	SR      0,0
 strncpy_loop:
         ICM     0,1,0(3)       # ICM sets the cc, IC does not
-	LA      3,1(0,3)
-        STC     0,0(0,1)
-	LA      1,1(0,1)
+	LA      3,1(3)
+        STC     0,0(1)
+	LA      1,1(1)
         JZ      strncpy_exit   # ICM inserted a 0x00
         BRCT    4,strncpy_loop # R4 -= 1, jump to strncpy_loop if > 0
 strncpy_exit:
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/mm/init.c linux.19p18/arch/s390/mm/init.c
--- linux.vanilla/arch/s390/mm/init.c	Mon Dec 11 22:12:36 2000
+++ linux.19p18/arch/s390/mm/init.c	Mon Feb 19 18:32:03 2001
@@ -141,7 +141,7 @@
         if(pgtable_cache_size > high) {
                 do {
                         if(pgd_quicklist)
-                                free_pgd_slow(get_pgd_fast()), freed++;
+                                free_pgd_slow(get_pgd_fast()), freed += 2;
                         if(pmd_quicklist)
                                 free_pmd_slow(get_pmd_fast()), freed++;
                         if(pte_quicklist)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/s390/tools/dasdfmt/dasdfmt.c linux.19p18/arch/s390/tools/dasdfmt/dasdfmt.c
--- linux.vanilla/arch/s390/tools/dasdfmt/dasdfmt.c	Mon Dec 11 22:12:37 2000
+++ linux.19p18/arch/s390/tools/dasdfmt/dasdfmt.c	Tue Feb 20 13:26:26 2001
@@ -201,7 +201,7 @@
 
 	/*	fgets(line,sizeof(line),file); omit first line */ 
 	while (fgets(line,sizeof(line),file)!=NULL) {
-		rc=sscanf(line,"%X %*[(A-Z)] at (%d:%d)",&d,&ma_i,&mi_i);
+		rc=sscanf(line,"%X %*[(A-Z) ] at (%d:%d)",&d,&ma_i,&mi_i);
 		ma=ma_i;
 		mi=mi_i;
 		if ( (rc==3) &&
@@ -219,7 +219,8 @@
 	fclose(file);
 
 	ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to find device in the /proc " \
-		"filesystem (are you sure to have the right param line?)\n",
+		    "filesystem (are you sure to have the right parameter " \
+		    "dasd=xxx?)\n",
 		prog_name);
 }
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc/config.in linux.19p18/arch/sparc/config.in
--- linux.vanilla/arch/sparc/config.in	Mon Dec 11 22:12:37 2000
+++ linux.19p18/arch/sparc/config.in	Thu Feb 15 16:19:20 2001
@@ -133,9 +133,11 @@
 mainmenu_option next_comment
 comment 'ISDN subsystem'
 
-tristate 'ISDN support' CONFIG_ISDN
-if [ "$CONFIG_ISDN" != "n" ]; then
-  source drivers/isdn/Config.in
+if [ "$CONFIG_NET" != "n" ]; then
+   tristate 'ISDN support' CONFIG_ISDN
+   if [ "$CONFIG_ISDN" != "n" ]; then
+      source drivers/isdn/Config.in
+   fi
 fi
 endmenu
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc/defconfig linux.19p18/arch/sparc/defconfig
--- linux.vanilla/arch/sparc/defconfig	Mon Dec 11 22:12:37 2000
+++ linux.19p18/arch/sparc/defconfig	Tue Jan  9 11:57:27 2001
@@ -284,6 +284,7 @@
 #
 CONFIG_BSD_DISKLABEL=y
 # CONFIG_MAC_PARTITION is not set
+# CONFIG_MINIX_SUBPARTITION is not set
 CONFIG_SMD_DISKLABEL=y
 CONFIG_SOLARIS_X86_PARTITION=y
 # CONFIG_UNIXWARE_DISKLABEL is not set
@@ -326,6 +327,7 @@
 # CONFIG_NLS_ISO8859_14 is not set
 # CONFIG_NLS_ISO8859_15 is not set
 # CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_RU is not set
 
 #
 # Watchdog
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc/kernel/sys_sunos.c linux.19p18/arch/sparc/kernel/sys_sunos.c
--- linux.vanilla/arch/sparc/kernel/sys_sunos.c	Mon Dec 11 22:12:37 2000
+++ linux.19p18/arch/sparc/kernel/sys_sunos.c	Wed Feb  7 09:45:38 2001
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos.c,v 1.94.2.5 2000/09/16 14:15:15 davem Exp $
+/* $Id: sys_sunos.c,v 1.94.2.6 2001/02/02 05:16:11 davem Exp $
  * sys_sunos.c: SunOS specific syscall compatibility support.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -712,7 +712,7 @@
 
 struct sunos_nfs_mount_args {
 	struct sockaddr_in  *addr; /* file server address */
-	struct nfs_fh *fh;     /* File handle to be mounted */
+	struct nfs3_fh *fh;     /* File handle to be mounted */
 	int        flags;      /* flags */
 	int        wsize;      /* write size in bytes */
 	int        rsize;      /* read size in bytes */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc/kernel/systbls.S linux.19p18/arch/sparc/kernel/systbls.S
--- linux.vanilla/arch/sparc/kernel/systbls.S	Fri Apr 21 12:45:48 2000
+++ linux.19p18/arch/sparc/kernel/systbls.S	Wed Feb  7 09:45:38 2001
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.83.2.2 2000/03/24 00:03:18 davem Exp $
+/* $Id: systbls.S,v 1.83.2.4 2001/01/11 19:12:10 davem Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
@@ -26,7 +26,7 @@
 /*25*/	.long sys_time, sys_ptrace, sys_alarm, sys_sigaltstack, sys_pause
 /*30*/	.long sys_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice
 /*35*/	.long sys_nis_syscall, sys_sync, sys_kill, sys_newstat, sys_sendfile
-/*40*/	.long sys_newlstat, sys_dup, sys_pipe, sys_times, sys_nis_syscall
+/*40*/	.long sys_newlstat, sys_dup, sys_pipe, sys_times, sys_lfs_syscall
 /*45*/	.long sys_umount, sys_setgid, sys_getgid, sys_signal, sys_geteuid
 /*50*/	.long sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys_ioctl
 /*55*/	.long sys_reboot, sys_lfs_syscall, sys_symlink, sys_readlink, sys_execve
@@ -48,8 +48,8 @@
 /*135*/	.long sys_nis_syscall, sys_mkdir, sys_rmdir, sys_utimes, sys_lfs_syscall
 /*140*/	.long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getrlimit
 /*145*/	.long sys_setrlimit, sys_nis_syscall, sys_prctl, sys_pciconfig_read, sys_pciconfig_write
-/*150*/	.long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall
-/*155*/	.long sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount
+/*150*/	.long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_lfs_syscall
+/*155*/	.long sys_lfs_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_oldumount
 /*160*/	.long sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_nis_syscall
 /*165*/	.long sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall
 /*170*/	.long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc/lib/strlen_user.S linux.19p18/arch/sparc/lib/strlen_user.S
--- linux.vanilla/arch/sparc/lib/strlen_user.S	Fri Apr 21 12:45:48 2000
+++ linux.19p18/arch/sparc/lib/strlen_user.S	Tue Feb 27 16:30:13 2001
@@ -47,9 +47,7 @@
 	 mov	3, %o0
 
 	.align 4
-	.global C_LABEL(__strlen_user), C_LABEL(__strnlen_user)
-C_LABEL(__strlen_user):
-	sethi	%hi(32768), %o1
+	.global C_LABEL(__strnlen_user)
 C_LABEL(__strnlen_user):
 	mov	%o1, %g1
 	mov	%o0, %o1
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/config.in linux.19p18/arch/sparc64/config.in
--- linux.vanilla/arch/sparc64/config.in	Mon Dec 11 22:12:37 2000
+++ linux.19p18/arch/sparc64/config.in	Wed Feb  7 09:45:38 2001
@@ -1,4 +1,4 @@
-# $Id: config.in,v 1.67.2.13 2000/10/24 21:00:53 davem Exp $
+# $Id: config.in,v 1.67.2.14 2001/01/26 22:26:07 davem Exp $
 # For a description of the syntax of this configuration file,
 # see Documentation/kbuild/config-language.txt.
 #
@@ -92,6 +92,7 @@
   fi
   tristate 'SUNW,envctrl support' CONFIG_ENVCTRL
   tristate '7-Segment Display support' CONFIG_DISPLAY7SEG
+  tristate 'CP1XXX Hardware Watchdog support' CONFIG_WATCHDOG_CP1XXX
 fi
 endmenu
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/defconfig linux.19p18/arch/sparc64/defconfig
--- linux.vanilla/arch/sparc64/defconfig	Mon Dec 11 22:12:37 2000
+++ linux.19p18/arch/sparc64/defconfig	Wed Feb  7 09:45:38 2001
@@ -19,7 +19,7 @@
 #
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
-# CONFIG_SMP is not set
+CONFIG_SMP=y
 CONFIG_SPARC64=y
 CONFIG_SBUS=y
 CONFIG_SBUSCHAR=y
@@ -100,6 +100,7 @@
 CONFIG_PRINTER_READBACK=y
 CONFIG_ENVCTRL=m
 CONFIG_DISPLAY7SEG=m
+CONFIG_WATCHDOG_CP1XXX=m
 
 #
 # Floppy, IDE, and other block devices
@@ -339,6 +340,7 @@
 #
 CONFIG_BSD_DISKLABEL=y
 # CONFIG_MAC_PARTITION is not set
+# CONFIG_MINIX_SUBPARTITION is not set
 CONFIG_SMD_DISKLABEL=y
 CONFIG_SOLARIS_X86_PARTITION=y
 # CONFIG_UNIXWARE_DISKLABEL is not set
@@ -381,6 +383,7 @@
 # CONFIG_NLS_ISO8859_14 is not set
 # CONFIG_NLS_ISO8859_15 is not set
 # CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_RU is not set
 
 #
 # Watchdog
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/kernel/ebus.c linux.19p18/arch/sparc64/kernel/ebus.c
--- linux.vanilla/arch/sparc64/kernel/ebus.c	Sat Sep  9 18:42:34 2000
+++ linux.19p18/arch/sparc64/kernel/ebus.c	Wed Feb  7 09:45:38 2001
@@ -1,4 +1,4 @@
-/* $Id: ebus.c,v 1.36.2.5 2000/07/27 01:50:59 davem Exp $
+/* $Id: ebus.c,v 1.36.2.6 2001/01/26 22:26:07 davem Exp $
  * ebus.c: PCI to EBus bridge device.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -46,6 +46,9 @@
 #endif
 #ifdef CONFIG_DISPLAY7SEG
 extern int d7s_init(void);
+#endif
+#ifdef CONFIG_WATCHDOG_CP1XXX
+extern int wd_init(void);
 #endif
 
 static inline unsigned long ebus_alloc(size_t size)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/kernel/ioctl32.c linux.19p18/arch/sparc64/kernel/ioctl32.c
--- linux.vanilla/arch/sparc64/kernel/ioctl32.c	Mon Dec 11 22:12:37 2000
+++ linux.19p18/arch/sparc64/kernel/ioctl32.c	Wed Feb  7 09:45:38 2001
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.62.2.17 2000/11/08 09:43:04 davem Exp $
+/* $Id: ioctl32.c,v 1.62.2.18 2001/01/26 22:26:07 davem Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997  Jakub Jelinek  (jj@sunsite.mff.cuni.cz)
@@ -63,6 +63,7 @@
 #include <asm/audioio.h>
 #include <asm/ethtool.h>
 #include <asm/display7seg.h>
+#include <asm/watchdog.h>
 
 #include <linux/soundcard.h>
 
@@ -3093,6 +3094,17 @@
 	case AUTOFS_IOC_CATATONIC:
 	case AUTOFS_IOC_PROTOVER:
 	case AUTOFS_IOC_EXPIRE:
+
+	/* Big W for hardware watchdog timers */
+	/* WIOC_GETSUPPORT not yet implemented -E */
+	case WDIOC_GETSTATUS:
+	case WDIOC_GETBOOTSTATUS:
+	case WDIOC_GETTEMP:
+	case WDIOC_SETOPTIONS:
+	case WDIOC_KEEPALIVE:
+	case WIOCSTART:
+	case WIOCSTOP:
+	case WIOCGSTAT:
 	
 	/* Raw devices */
 	case _IO(0xac, 0): /* RAW_SETBIND */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/kernel/sparc64_ksyms.c linux.19p18/arch/sparc64/kernel/sparc64_ksyms.c
--- linux.vanilla/arch/sparc64/kernel/sparc64_ksyms.c	Mon Dec 11 22:12:37 2000
+++ linux.19p18/arch/sparc64/kernel/sparc64_ksyms.c	Tue Feb 27 16:30:13 2001
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.58.2.11 2000/10/25 21:17:44 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.58.2.13 2001/01/03 22:05:54 anton Exp $
  * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -167,6 +167,7 @@
 
 EXPORT_SYMBOL_PRIVATE(flushw_user);
 
+EXPORT_SYMBOL(flush_icache_range);
 EXPORT_SYMBOL(flush_dcache_page);
 
 EXPORT_SYMBOL(mstk48t02_regs);
@@ -209,6 +210,11 @@
 /* Should really be in linux/kernel/ksyms.c */
 EXPORT_SYMBOL(dump_thread);
 EXPORT_SYMBOL(dump_fpu);
+EXPORT_SYMBOL(get_pmd_slow);
+EXPORT_SYMBOL(get_pte_slow);
+#ifndef CONFIG_SMP
+EXPORT_SYMBOL(pgt_quicklists);
+#endif
 
 /* math-emu wants this */
 EXPORT_SYMBOL(die_if_kernel);
@@ -247,7 +253,6 @@
 #if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 91)
 EXPORT_SYMBOL(strlen);
 #endif
-EXPORT_SYMBOL(__strlen_user);
 EXPORT_SYMBOL(strnlen);
 EXPORT_SYMBOL(strcpy);
 EXPORT_SYMBOL(strncpy);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/kernel/sys_sparc32.c linux.19p18/arch/sparc64/kernel/sys_sparc32.c
--- linux.vanilla/arch/sparc64/kernel/sys_sparc32.c	Mon Dec 11 22:12:37 2000
+++ linux.19p18/arch/sparc64/kernel/sys_sparc32.c	Thu Dec 21 22:57:16 2000
@@ -1,4 +1,4 @@
-/* $Id: sys_sparc32.c,v 1.107.2.14 2000/10/10 04:50:50 davem Exp $
+/* $Id: sys_sparc32.c,v 1.107.2.16 2000/12/20 02:45:00 anton Exp $
  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -3462,7 +3462,7 @@
 	set_fs (KERNEL_DS);
 	sys_get_kernel_syms(tbl);
 	set_fs (old_fs);
-	for (i = 0; i < len; i++, table += sizeof (struct kernel_sym32)) {
+	for (i = 0; i < len; i++, table++) {
 		if (put_user (tbl[i].value, &table->value) ||
 		    copy_to_user (table->name, tbl[i].name, 60))
 			break;
@@ -3553,6 +3553,12 @@
 	s32			gf32_version;
 };
 
+struct nfsctl_fdparm32 {
+	struct sockaddr		gd32_addr;
+	s8			gd32_path[NFS_MAXPATHLEN+1];
+	s32			gd32_version;
+};
+
 struct nfsctl_arg32 {
 	s32			ca32_version;	/* safeguard */
 	union {
@@ -3561,6 +3567,7 @@
 		struct nfsctl_export32	u32_export;
 		struct nfsctl_uidmap32	u32_umap;
 		struct nfsctl_fhparm32	u32_getfh;
+		struct nfsctl_fdparm32  u32_getfd;
 		u32			u32_debug;
 	} u;
 #define ca32_svc	u.u32_svc
@@ -3569,6 +3576,7 @@
 #define ca32_umap	u.u32_umap
 #define ca32_getfh	u.u32_getfh
 #define ca32_authd	u.u32_authd
+#define ca32_getfd	u.u32_getfd
 #define ca32_debug	u.u32_debug
 };
 
@@ -3698,6 +3706,22 @@
 	return err;
 }
 
+static int nfs_getfd32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
+{
+	int err;
+	
+	err = __get_user(karg->ca_version, &arg32->ca32_version);
+	err |= copy_from_user(&karg->ca_getfd.gd_addr,
+			  &arg32->ca32_getfd.gd32_addr,
+			  (sizeof(struct sockaddr)));
+	err |= copy_from_user(&karg->ca_getfd.gd_path,
+			  &arg32->ca32_getfd.gd32_path,
+			  (NFS_MAXPATHLEN+1));
+	err |= __get_user(karg->ca_getfd.gd_version,
+		      &arg32->ca32_getfd.gd32_version);
+	return err;
+}
+
 static int nfs_getfh32_res_trans(union nfsctl_res *kres, union nfsctl_res32 *res32)
 {
 	int err;
@@ -3739,6 +3763,7 @@
 		err = nfs_clnt32_trans(karg, arg32);
 		break;
 	case NFSCTL_EXPORT:
+	case NFSCTL_UNEXPORT:
 		err = nfs_exp32_trans(karg, arg32);
 		break;
 	/* This one is unimplemented, be we're ready for it. */
@@ -3748,6 +3773,9 @@
 	case NFSCTL_GETFH:
 		err = nfs_getfh32_trans(karg, arg32);
 		break;
+	case NFSCTL_GETFD:
+		err = nfs_getfd32_trans(karg, arg32);
+		break;
 	case NFSCTL_LOCKD:
 		/* We still have to copy over the version
 		 * because nfsctl still checks that.
@@ -3765,7 +3793,11 @@
 	err = sys_nfsservctl(cmd, karg, kres);
 	set_fs(oldfs);
 
-	if(!err && cmd == NFSCTL_GETFH)
+	if (err)
+		goto done;
+
+	if((cmd == NFSCTL_GETFH) ||
+	   (cmd == NFSCTL_GETFD))
 		err = nfs_getfh32_res_trans(kres, res32);
 
 done:
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/kernel/sys_sunos32.c linux.19p18/arch/sparc64/kernel/sys_sunos32.c
--- linux.vanilla/arch/sparc64/kernel/sys_sunos32.c	Mon Dec 11 22:12:37 2000
+++ linux.19p18/arch/sparc64/kernel/sys_sunos32.c	Wed Feb  7 09:45:38 2001
@@ -1,4 +1,4 @@
-/* $Id: sys_sunos32.c,v 1.22.2.4 2000/09/16 14:15:15 davem Exp $
+/* $Id: sys_sunos32.c,v 1.22.2.6 2001/02/02 01:30:09 davem Exp $
  * sys_sunos32.c: SunOS binary compatability layer on sparc64.
  *
  * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -677,7 +677,7 @@
 
 struct sunos_nfs_mount_args {
 	struct sockaddr_in  *addr; /* file server address */
-	struct nfs_fh *fh;     /* File handle to be mounted */
+	struct nfs3_fh *fh;     /* File handle to be mounted */
 	int        flags;      /* flags */
 	int        wsize;      /* write size in bytes */
 	int        rsize;      /* read size in bytes */
@@ -1168,6 +1168,7 @@
 			(current->tss.kregs->u_regs[UREG_FP] & 0xffffffffUL);
 		if(get_user(arg5, &sp->xxargs[0])) {
 			rval = -EFAULT;
+			kfree(kmbuf);
 			break;
 		}
 		set_fs(KERNEL_DS);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/kernel/systbls.S linux.19p18/arch/sparc64/kernel/systbls.S
--- linux.vanilla/arch/sparc64/kernel/systbls.S	Mon Dec 11 22:12:37 2000
+++ linux.19p18/arch/sparc64/kernel/systbls.S	Wed Feb  7 09:45:38 2001
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.53.2.5 2000/08/23 04:18:26 davem Exp $
+/* $Id: systbls.S,v 1.53.2.7 2001/01/11 19:12:10 davem Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
@@ -27,7 +27,7 @@
 /*25*/	.word sys_time, sys_ptrace, sys_alarm, sys32_sigaltstack, sys32_pause
 /*30*/	.word sys32_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice
 	.word sys_nis_syscall, sys_sync, sys_kill, sys32_newstat, sys32_sendfile
-/*40*/	.word sys32_newlstat, sys_dup, sys_pipe, sys32_times, sys_nis_syscall
+/*40*/	.word sys32_newlstat, sys_dup, sys_pipe, sys32_times, sys_lfs_syscall
 	.word sys_umount, sys_setgid, sys_getgid, sys_signal, sys_geteuid
 /*50*/	.word sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys32_ioctl
 	.word sys_reboot, sys_lfs_syscall, sys_symlink, sys_readlink, sys32_execve
@@ -49,8 +49,8 @@
 	.word sys_nis_syscall, sys_mkdir, sys_rmdir, sys32_utimes, sys_lfs_syscall
 /*140*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getrlimit
 	.word sys32_setrlimit, sys_nis_syscall, sys32_prctl, sys32_pciconfig_read, sys32_pciconfig_write
-/*150*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall
-	.word sys_nis_syscall, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys_oldumount
+/*150*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_lfs_syscall
+	.word sys_lfs_syscall, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys_oldumount
 /*160*/	.word sys_nis_syscall, sys_nis_syscall, sys_getdomainname, sys_setdomainname, sys_nis_syscall
 	.word sys32_quotactl, sys_nis_syscall, sys32_mount, sys_ustat, sys_nis_syscall
 /*170*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/lib/strlen_user.S linux.19p18/arch/sparc64/lib/strlen_user.S
--- linux.vanilla/arch/sparc64/lib/strlen_user.S	Fri Apr 21 12:45:48 2000
+++ linux.19p18/arch/sparc64/lib/strlen_user.S	Tue Feb 27 16:30:13 2001
@@ -14,9 +14,7 @@
 #define HI_MAGIC 0x80808080
 
 	.align 4
-	.global __strlen_user, __strnlen_user
-__strlen_user:
-	sethi	%hi(32768), %o1
+	.global __strnlen_user
 __strnlen_user:	
 	mov	%o1, %g1
 	mov	%o0, %o1
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/arch/sparc64/mm/init.c linux.19p18/arch/sparc64/mm/init.c
--- linux.vanilla/arch/sparc64/mm/init.c	Fri Apr 21 12:45:48 2000
+++ linux.19p18/arch/sparc64/mm/init.c	Tue Jan  9 11:57:27 2001
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.127.2.8 2000/03/03 23:50:41 davem Exp $
+/*  $Id: init.c,v 1.127.2.9 2000/12/11 12:31:06 anton Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu)
@@ -87,6 +87,14 @@
         }
 #endif
         return freed;
+}
+
+void flush_icache_range(unsigned long start, unsigned long end)
+{
+	unsigned long kaddr;
+
+	for (kaddr = start; kaddr < end; kaddr += PAGE_SIZE)
+		flush_icache_page(__get_phys(kaddr));
 }
 
 /*
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/DAC960.c linux.19p18/drivers/block/DAC960.c
--- linux.vanilla/drivers/block/DAC960.c	Mon Dec 11 22:12:39 2000
+++ linux.19p18/drivers/block/DAC960.c	Wed Feb 14 14:23:34 2001
@@ -2,7 +2,7 @@
 
   Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers
 
-  Copyright 1998-2000 by Leonard N. Zubkoff <lnz@dandelion.com>
+  Copyright 1998-2001 by Leonard N. Zubkoff <lnz@dandelion.com>
 
   This program is free software; you may redistribute and/or modify it under
   the terms of the GNU General Public License Version 2 as published by the
@@ -19,8 +19,8 @@
 */
 
 
-#define DAC960_DriverVersion			"2.2.9"
-#define DAC960_DriverDate			"7 September 2000"
+#define DAC960_DriverVersion			"2.2.10"
+#define DAC960_DriverDate			"1 February 2001"
 
 
 #include <linux/version.h>
@@ -120,7 +120,7 @@
   DAC960_Announce("***** DAC960 RAID Driver Version "
 		  DAC960_DriverVersion " of "
 		  DAC960_DriverDate " *****\n", Controller);
-  DAC960_Announce("Copyright 1998-2000 by Leonard N. Zubkoff "
+  DAC960_Announce("Copyright 1998-2001 by Leonard N. Zubkoff "
 		  "<lnz@dandelion.com>\n", Controller);
 }
 
@@ -521,7 +521,7 @@
   DAC960_V1_ClearCommand(Command);
   Command->CommandType = DAC960_ImmediateCommand;
   CommandMailbox->Type3.CommandOpcode = CommandOpcode;
-  CommandMailbox->Type3.BusAddress = Virtual_to_Bus(DataPointer);
+  CommandMailbox->Type3.BusAddress = Virtual_to_Bus32(DataPointer);
   DAC960_ExecuteCommand(Command);
   CommandStatus = Command->V1.CommandStatus;
   DAC960_DeallocateCommand(Command);
@@ -549,7 +549,7 @@
   CommandMailbox->Type3D.CommandOpcode = CommandOpcode;
   CommandMailbox->Type3D.Channel = Channel;
   CommandMailbox->Type3D.TargetID = TargetID;
-  CommandMailbox->Type3D.BusAddress = Virtual_to_Bus(DataPointer);
+  CommandMailbox->Type3D.BusAddress = Virtual_to_Bus32(DataPointer);
   DAC960_ExecuteCommand(Command);
   CommandStatus = Command->V1.CommandStatus;
   DAC960_DeallocateCommand(Command);
@@ -583,7 +583,7 @@
   CommandMailbox->Common.DataTransferMemoryAddress
 			.ScatterGatherSegments[0]
 			.SegmentDataPointer =
-    Virtual_to_Bus(DataPointer);
+    Virtual_to_Bus64(DataPointer);
   CommandMailbox->Common.DataTransferMemoryAddress
 			.ScatterGatherSegments[0]
 			.SegmentByteCount =
@@ -622,7 +622,7 @@
   CommandMailbox->ControllerInfo.DataTransferMemoryAddress
 				.ScatterGatherSegments[0]
 				.SegmentDataPointer =
-    Virtual_to_Bus(DataPointer);
+    Virtual_to_Bus64(DataPointer);
   CommandMailbox->ControllerInfo.DataTransferMemoryAddress
 				.ScatterGatherSegments[0]
 				.SegmentByteCount =
@@ -665,7 +665,7 @@
   CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress
 				   .ScatterGatherSegments[0]
 				   .SegmentDataPointer =
-    Virtual_to_Bus(DataPointer);
+    Virtual_to_Bus64(DataPointer);
   CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress
 				   .ScatterGatherSegments[0]
 				   .SegmentByteCount =
@@ -710,7 +710,7 @@
   CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress
 				    .ScatterGatherSegments[0]
 				    .SegmentDataPointer =
-    Virtual_to_Bus(DataPointer);
+    Virtual_to_Bus64(DataPointer);
   CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress
 				    .ScatterGatherSegments[0]
 				    .SegmentByteCount =
@@ -826,9 +826,9 @@
   CommandMailbox.TypeX.CommandIdentifier = 0;
   CommandMailbox.TypeX.CommandOpcode2 = 0x14;
   CommandMailbox.TypeX.CommandMailboxesBusAddress =
-    Virtual_to_Bus(Controller->V1.FirstCommandMailbox);
+    Virtual_to_Bus32(Controller->V1.FirstCommandMailbox);
   CommandMailbox.TypeX.StatusMailboxesBusAddress =
-    Virtual_to_Bus(Controller->V1.FirstStatusMailbox);
+    Virtual_to_Bus32(Controller->V1.FirstStatusMailbox);
   for (i = 0; i < 2; i++)
     switch (Controller->HardwareType)
       {
@@ -950,11 +950,11 @@
   CommandMailbox.SetMemoryMailbox.IOCTL_Opcode = DAC960_V2_SetMemoryMailbox;
   CommandMailbox.SetMemoryMailbox.HealthStatusBufferSizeKB = 1;
   CommandMailbox.SetMemoryMailbox.HealthStatusBufferBusAddress =
-    Virtual_to_Bus(Controller->V2.HealthStatusBuffer);
+    Virtual_to_Bus64(Controller->V2.HealthStatusBuffer);
   CommandMailbox.SetMemoryMailbox.FirstCommandMailboxBusAddress =
-    Virtual_to_Bus(Controller->V2.FirstCommandMailbox);
+    Virtual_to_Bus64(Controller->V2.FirstCommandMailbox);
   CommandMailbox.SetMemoryMailbox.FirstStatusMailboxBusAddress =
-    Virtual_to_Bus(Controller->V2.FirstStatusMailbox);
+    Virtual_to_Bus64(Controller->V2.FirstStatusMailbox);
   switch (Controller->HardwareType)
     {
     case DAC960_BA_Controller:
@@ -1344,7 +1344,7 @@
 	  Command->CommandType = DAC960_ImmediateCommand;
 	  Command->Semaphore = Semaphore;
 	  Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_DCDB;
-	  Command->V1.CommandMailbox.Type3.BusAddress = Virtual_to_Bus(DCDB);
+	  Command->V1.CommandMailbox.Type3.BusAddress = Virtual_to_Bus32(DCDB);
 	  DCDB->Channel = Channel;
 	  DCDB->TargetID = TargetID;
 	  DCDB->Direction = DAC960_V1_DCDB_DataTransferDeviceToSystem;
@@ -1353,7 +1353,7 @@
 	  DCDB->NoAutomaticRequestSense = false;
 	  DCDB->DisconnectPermitted = true;
 	  DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_T);
-	  DCDB->BusAddress = Virtual_to_Bus(InquiryStandardData);
+	  DCDB->BusAddress = Virtual_to_Bus32(InquiryStandardData);
 	  DCDB->CDBLength = 6;
 	  DCDB->TransferLengthHigh4 = 0;
 	  DCDB->SenseLength = sizeof(DCDB->SenseData);
@@ -1380,7 +1380,7 @@
 	  Command->Semaphore = Semaphore;
 	  DCDB = &DCDBs[Channel];
 	  DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T);
-	  DCDB->BusAddress = Virtual_to_Bus(InquiryUnitSerialNumber);
+	  DCDB->BusAddress = Virtual_to_Bus32(InquiryUnitSerialNumber);
 	  DCDB->SenseLength = sizeof(DCDB->SenseData);
 	  DCDB->CDB[0] = 0x12; /* INQUIRY */
 	  DCDB->CDB[1] = 1; /* EVPD = 1 */
@@ -1471,7 +1471,7 @@
       CommandMailbox->SCSI_10.DataTransferMemoryAddress
 			     .ScatterGatherSegments[0]
 			     .SegmentDataPointer =
-	Virtual_to_Bus(InquiryUnitSerialNumber);
+	Virtual_to_Bus64(InquiryUnitSerialNumber);
       CommandMailbox->SCSI_10.DataTransferMemoryAddress
 			     .ScatterGatherSegments[0]
 			     .SegmentByteCount =
@@ -2541,7 +2541,8 @@
       CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
       CommandMailbox->Type5.LD.LogicalDriveNumber = Command->LogicalDriveNumber;
       CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber;
-      CommandMailbox->Type5.BusAddress = Virtual_to_Bus(Command->RequestBuffer);
+      CommandMailbox->Type5.BusAddress =
+	Virtual_to_Bus32(Command->RequestBuffer);
     }
   else
     {
@@ -2559,7 +2560,7 @@
       CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
       CommandMailbox->Type5.LD.LogicalDriveNumber = Command->LogicalDriveNumber;
       CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber;
-      CommandMailbox->Type5.BusAddress = Virtual_to_Bus(ScatterGatherList);
+      CommandMailbox->Type5.BusAddress = Virtual_to_Bus32(ScatterGatherList);
       CommandMailbox->Type5.ScatterGatherCount = Command->SegmentCount;
       while (BufferHeader != NULL)
 	{
@@ -2572,7 +2573,7 @@
 	  else
 	    {
 	      ScatterGatherList[SegmentNumber].SegmentDataPointer =
-		Virtual_to_Bus(BufferHeader->b_data);
+		Virtual_to_Bus32(BufferHeader->b_data);
 	      ScatterGatherList[SegmentNumber].SegmentByteCount =
 		BufferHeader->b_size;
 	      LastDataEndPointer = BufferHeader->b_data + BufferHeader->b_size;
@@ -2604,7 +2605,7 @@
   CommandMailbox->SCSI_10.DataTransferSize =
     Command->BlockCount << DAC960_BlockSizeBits;
   CommandMailbox->SCSI_10.RequestSenseBusAddress =
-    Virtual_to_Bus(&Command->V2.RequestSense);
+    Virtual_to_Bus64(&Command->V2.RequestSense);
   CommandMailbox->SCSI_10.PhysicalDevice =
     Controller->V2.LogicalDriveToVirtualDevice[Command->LogicalDriveNumber];
   CommandMailbox->SCSI_10.RequestSenseSize =
@@ -2623,7 +2624,7 @@
       CommandMailbox->SCSI_10.DataTransferMemoryAddress
 			     .ScatterGatherSegments[0]
 			     .SegmentDataPointer =
-	Virtual_to_Bus(Command->RequestBuffer);
+	Virtual_to_Bus64(Command->RequestBuffer);
       CommandMailbox->SCSI_10.DataTransferMemoryAddress
 			     .ScatterGatherSegments[0]
 			     .SegmentByteCount =
@@ -2645,7 +2646,7 @@
 	    Command->SegmentCount;
 	  CommandMailbox->SCSI_10.DataTransferMemoryAddress
 			 .ExtendedScatterGather.ScatterGatherList0Address =
-	    Virtual_to_Bus(ScatterGatherList);
+	    Virtual_to_Bus64(ScatterGatherList);
 	}
       else
 	ScatterGatherList =
@@ -2662,7 +2663,7 @@
 	  else
 	    {
 	      ScatterGatherList[SegmentNumber].SegmentDataPointer =
-		Virtual_to_Bus(BufferHeader->b_data);
+		Virtual_to_Bus64(BufferHeader->b_data);
 	      ScatterGatherList[SegmentNumber].SegmentByteCount =
 		BufferHeader->b_size;
 	      LastDataEndPointer = BufferHeader->b_data + BufferHeader->b_size;
@@ -3047,7 +3048,7 @@
 	  Command->BlockCount = BufferHeader->b_size >> DAC960_BlockSizeBits;
 	  CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
 	  CommandMailbox->Type5.BusAddress =
-	    Virtual_to_Bus(BufferHeader->b_data);
+	    Virtual_to_Bus32(BufferHeader->b_data);
 	  DAC960_QueueCommand(Command);
 	  return;
 	}
@@ -3103,7 +3104,7 @@
 	  CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
 	  CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber;
 	  CommandMailbox->Type5.BusAddress =
-	    Virtual_to_Bus(NextBufferHeader->b_data);
+	    Virtual_to_Bus32(NextBufferHeader->b_data);
 	  DAC960_QueueCommand(Command);
 	  return;
 	}
@@ -3116,11 +3117,13 @@
 	{
 	  if (CommandOpcode == DAC960_V1_Enquiry)
 	    memcpy(&Controller->V1.NewEnquiry,
-		   Bus_to_Virtual(Command->V1.CommandMailbox.Type3.BusAddress),
+		   Bus32_to_Virtual(Command->V1.CommandMailbox
+					       .Type3.BusAddress),
 		   sizeof(DAC960_V1_Enquiry_T));
 	  else if (CommandOpcode == DAC960_V1_GetRebuildProgress)
 	    memcpy(&Controller->V1.RebuildProgress,
-		   Bus_to_Virtual(Command->V1.CommandMailbox.Type3.BusAddress),
+		   Bus32_to_Virtual(Command->V1.CommandMailbox
+					       .Type3.BusAddress),
 		   sizeof(DAC960_V1_RebuildProgress_T));
 	}
       if (CommandOpcode == DAC960_V1_Enquiry &&
@@ -3134,18 +3137,25 @@
 	    NewEnquiry->CriticalLogicalDriveCount;
 	  if (NewEnquiry->NumberOfLogicalDrives > Controller->LogicalDriveCount)
 	    {
-	      int LogicalDriveNumber = Controller->LogicalDriveCount;
-	      while (LogicalDriveNumber < NewEnquiry->NumberOfLogicalDrives)
-		{
-		  DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
-				  "Now Exists\n", Controller,
-				  LogicalDriveNumber,
-				  Controller->ControllerNumber,
-				  LogicalDriveNumber);
-		  LogicalDriveNumber++;
-		}
-	      Controller->LogicalDriveCount = LogicalDriveNumber;
+	      int LogicalDriveNumber = Controller->LogicalDriveCount - 1;
+	      while (++LogicalDriveNumber < NewEnquiry->NumberOfLogicalDrives)
+		DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
+				"Now Exists\n", Controller,
+				LogicalDriveNumber,
+				Controller->ControllerNumber,
+				LogicalDriveNumber);
+	    }
+	  if (NewEnquiry->NumberOfLogicalDrives < Controller->LogicalDriveCount)
+	    {
+	      int LogicalDriveNumber = NewEnquiry->NumberOfLogicalDrives - 1;
+	      while (++LogicalDriveNumber < Controller->LogicalDriveCount)
+		DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
+				"No Longer Exists\n", Controller,
+				LogicalDriveNumber,
+				Controller->ControllerNumber,
+				LogicalDriveNumber);
 	    }
+	  Controller->LogicalDriveCount = NewEnquiry->NumberOfLogicalDrives;
 	  if (NewEnquiry->StatusFlags.DeferredWriteError !=
 	      OldEnquiry->StatusFlags.DeferredWriteError)
 	    DAC960_Critical("Deferred Write Error Flag is now %s\n", Controller,
@@ -3170,8 +3180,7 @@
 		NewEnquiry->EventLogSequenceNumber;
 	      Controller->V1.NeedErrorTableInformation = true;
 	      Controller->V1.NeedDeviceStateInformation = true;
-	      Controller->V1.DeviceStateChannel = 0;
-	      Controller->V1.DeviceStateTargetID = -1;
+	      Controller->V1.StartDeviceStateScan = true;
 	      Controller->SecondaryMonitoringTime = jiffies;
 	    }
 	  if (NewEnquiry->RebuildFlag == DAC960_V1_StandbyRebuildInProgress ||
@@ -3230,7 +3239,7 @@
 	      Controller->V1.RebuildFlagPending)
 	    {
 	      DAC960_V1_Enquiry_T *Enquiry = (DAC960_V1_Enquiry_T *)
-		Bus_to_Virtual(Command->V1.CommandMailbox.Type3.BusAddress);
+		Bus32_to_Virtual(Command->V1.CommandMailbox.Type3.BusAddress);
 	      Enquiry->RebuildFlag = Controller->V1.PendingRebuildFlag;
 	      Controller->V1.RebuildFlagPending = false;
 	    }
@@ -3376,6 +3385,9 @@
 	    {
 	      Controller->V1.NeedDeviceInquiryInformation = true;
 	      Controller->V1.NeedDeviceSerialNumberInformation = true;
+	      Controller->V1.DeviceResetCount
+			     [Controller->V1.DeviceStateChannel]
+			     [Controller->V1.DeviceStateTargetID] = 0;
 	    }
 	  memcpy(OldDeviceState, NewDeviceState,
 		 sizeof(DAC960_V1_DeviceState_T));
@@ -3515,7 +3527,7 @@
 	  Command->V1.CommandMailbox.Type3E.SequenceNumber =
 	    Controller->V1.OldEventLogSequenceNumber;
 	  Command->V1.CommandMailbox.Type3E.BusAddress =
-	    Virtual_to_Bus(&Controller->V1.EventLogEntry);
+	    Virtual_to_Bus32(&Controller->V1.EventLogEntry);
 	  DAC960_QueueCommand(Command);
 	  return;
 	}
@@ -3525,7 +3537,7 @@
 	  Command->V1.CommandMailbox.Type3.CommandOpcode =
 	    DAC960_V1_GetErrorTable;
 	  Command->V1.CommandMailbox.Type3.BusAddress =
-	    Virtual_to_Bus(&Controller->V1.NewErrorTable);
+	    Virtual_to_Bus32(&Controller->V1.NewErrorTable);
 	  DAC960_QueueCommand(Command);
 	  return;
 	}
@@ -3536,7 +3548,7 @@
 	  Command->V1.CommandMailbox.Type3.CommandOpcode =
 	    DAC960_V1_GetRebuildProgress;
 	  Command->V1.CommandMailbox.Type3.BusAddress =
-	    Virtual_to_Bus(&Controller->V1.RebuildProgress);
+	    Virtual_to_Bus32(&Controller->V1.RebuildProgress);
 	  DAC960_QueueCommand(Command);
 	  return;
 	}
@@ -3552,7 +3564,7 @@
 	      InquiryStandardData->PeripheralDeviceType = 0x1F;
 	      Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_DCDB;
 	      Command->V1.CommandMailbox.Type3.BusAddress =
-		Virtual_to_Bus(DCDB);
+		Virtual_to_Bus32(DCDB);
 	      DCDB->Channel = Controller->V1.DeviceStateChannel;
 	      DCDB->TargetID = Controller->V1.DeviceStateTargetID;
 	      DCDB->Direction = DAC960_V1_DCDB_DataTransferDeviceToSystem;
@@ -3561,7 +3573,7 @@
 	      DCDB->NoAutomaticRequestSense = false;
 	      DCDB->DisconnectPermitted = true;
 	      DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_T);
-	      DCDB->BusAddress = Virtual_to_Bus(InquiryStandardData);
+	      DCDB->BusAddress = Virtual_to_Bus32(InquiryStandardData);
 	      DCDB->CDBLength = 6;
 	      DCDB->TransferLengthHigh4 = 0;
 	      DCDB->SenseLength = sizeof(DCDB->SenseData);
@@ -3585,7 +3597,7 @@
 	      InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F;
 	      Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_DCDB;
 	      Command->V1.CommandMailbox.Type3.BusAddress =
-		Virtual_to_Bus(DCDB);
+		Virtual_to_Bus32(DCDB);
 	      DCDB->Channel = Controller->V1.DeviceStateChannel;
 	      DCDB->TargetID = Controller->V1.DeviceStateTargetID;
 	      DCDB->Direction = DAC960_V1_DCDB_DataTransferDeviceToSystem;
@@ -3595,7 +3607,7 @@
 	      DCDB->DisconnectPermitted = true;
 	      DCDB->TransferLength =
 		sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T);
-	      DCDB->BusAddress = Virtual_to_Bus(InquiryUnitSerialNumber);
+	      DCDB->BusAddress = Virtual_to_Bus32(InquiryUnitSerialNumber);
 	      DCDB->CDBLength = 6;
 	      DCDB->TransferLengthHigh4 = 0;
 	      DCDB->SenseLength = sizeof(DCDB->SenseData);
@@ -3609,35 +3621,31 @@
 	      Controller->V1.NeedDeviceSerialNumberInformation = false;
 	      return;
 	    }
-	  if (++Controller->V1.DeviceStateTargetID == Controller->Targets)
+	  if (Controller->V1.StartDeviceStateScan)
+	    {
+	      Controller->V1.DeviceStateChannel = 0;
+	      Controller->V1.DeviceStateTargetID = 0;
+	      Controller->V1.StartDeviceStateScan = false;
+	    }
+	  else if (++Controller->V1.DeviceStateTargetID == Controller->Targets)
 	    {
 	      Controller->V1.DeviceStateChannel++;
 	      Controller->V1.DeviceStateTargetID = 0;
 	    }
-	  while (Controller->V1.DeviceStateChannel < Controller->Channels)
+	  if (Controller->V1.DeviceStateChannel < Controller->Channels)
 	    {
-	      DAC960_V1_DeviceState_T *OldDeviceState =
-		&Controller->V1.DeviceState[Controller->V1.DeviceStateChannel]
-					   [Controller->V1.DeviceStateTargetID];
-	      if (OldDeviceState->Present &&
-		  OldDeviceState->DeviceType == DAC960_V1_DiskType)
-		{
-		  Command->V1.CommandMailbox.Type3D.CommandOpcode =
-		    DAC960_V1_GetDeviceState;
-		  Command->V1.CommandMailbox.Type3D.Channel =
-		    Controller->V1.DeviceStateChannel;
-		  Command->V1.CommandMailbox.Type3D.TargetID =
-		    Controller->V1.DeviceStateTargetID;
-		  Command->V1.CommandMailbox.Type3D.BusAddress =
-		    Virtual_to_Bus(&Controller->V1.NewDeviceState);
-		  DAC960_QueueCommand(Command);
-		  return;
-		}
-	      if (++Controller->V1.DeviceStateTargetID == Controller->Targets)
-		{
-		  Controller->V1.DeviceStateChannel++;
-		  Controller->V1.DeviceStateTargetID = 0;
-		}
+	      Controller->V1.NewDeviceState.DeviceState =
+		DAC960_V1_Device_Dead;
+	      Command->V1.CommandMailbox.Type3D.CommandOpcode =
+		DAC960_V1_GetDeviceState;
+	      Command->V1.CommandMailbox.Type3D.Channel =
+		Controller->V1.DeviceStateChannel;
+	      Command->V1.CommandMailbox.Type3D.TargetID =
+		Controller->V1.DeviceStateTargetID;
+	      Command->V1.CommandMailbox.Type3D.BusAddress =
+		Virtual_to_Bus32(&Controller->V1.NewDeviceState);
+	      DAC960_QueueCommand(Command);
+	      return;
 	    }
 	  Controller->V1.NeedDeviceStateInformation = false;
 	}
@@ -3647,7 +3655,7 @@
 	  Command->V1.CommandMailbox.Type3.CommandOpcode =
 	    DAC960_V1_GetLogicalDriveInformation;
 	  Command->V1.CommandMailbox.Type3.BusAddress =
-	    Virtual_to_Bus(&Controller->V1.NewLogicalDriveInformation);
+	    Virtual_to_Bus32(&Controller->V1.NewLogicalDriveInformation);
 	  DAC960_QueueCommand(Command);
 	  return;
 	}
@@ -3657,7 +3665,7 @@
 	  Command->V1.CommandMailbox.Type3.CommandOpcode =
 	    DAC960_V1_GetRebuildProgress;
 	  Command->V1.CommandMailbox.Type3.BusAddress =
-	    Virtual_to_Bus(&Controller->V1.RebuildProgress);
+	    Virtual_to_Bus32(&Controller->V1.RebuildProgress);
 	  DAC960_QueueCommand(Command);
 	  return;
 	}
@@ -3667,7 +3675,7 @@
 	  Command->V1.CommandMailbox.Type3.CommandOpcode =
 	    DAC960_V1_RebuildStat;
 	  Command->V1.CommandMailbox.Type3.BusAddress =
-	    Virtual_to_Bus(&Controller->V1.RebuildProgress);
+	    Virtual_to_Bus32(&Controller->V1.RebuildProgress);
 	  DAC960_QueueCommand(Command);
 	  return;
 	}
@@ -4045,7 +4053,7 @@
 	    Command->BlockCount << DAC960_BlockSizeBits;
 	  CommandMailbox->SCSI_10.DataTransferMemoryAddress
 				 .ScatterGatherSegments[0].SegmentDataPointer =
-	    Virtual_to_Bus(BufferHeader->b_data);
+	    Virtual_to_Bus64(BufferHeader->b_data);
 	  CommandMailbox->SCSI_10.DataTransferMemoryAddress
 				 .ScatterGatherSegments[0].SegmentByteCount =
 	    CommandMailbox->SCSI_10.DataTransferSize;
@@ -4106,7 +4114,7 @@
 	  CommandMailbox->SCSI_10.DataTransferMemoryAddress
 				 .ScatterGatherSegments[0]
 				 .SegmentDataPointer =
-	    Virtual_to_Bus(NextBufferHeader->b_data);
+	    Virtual_to_Bus64(NextBufferHeader->b_data);
 	  CommandMailbox->SCSI_10.DataTransferMemoryAddress
 				 .ScatterGatherSegments[0]
 				 .SegmentByteCount =
@@ -4132,12 +4140,9 @@
 	  Controller->LogicalDriveCount =
 	    NewControllerInfo->LogicalDevicesPresent;
 	  Controller->V2.NeedLogicalDeviceInformation = true;
-	  Controller->V2.NewLogicalDeviceInformation.LogicalDeviceNumber = 0;
 	  Controller->V2.NeedPhysicalDeviceInformation = true;
-	  Controller->V2.PhysicalDeviceIndex = 0;
-	  Controller->V2.NewPhysicalDeviceInformation.Channel = 0;
-	  Controller->V2.NewPhysicalDeviceInformation.TargetID = 0;
-	  Controller->V2.NewPhysicalDeviceInformation.LogicalUnit = 0;
+	  Controller->V2.StartLogicalDeviceInformationScan = true;
+	  Controller->V2.StartPhysicalDeviceInformationScan = true;
 	  Controller->MonitoringAlertMode =
 	    (NewControllerInfo->LogicalDevicesCritical > 0 ||
 	     NewControllerInfo->LogicalDevicesOffline > 0 ||
@@ -4160,7 +4165,49 @@
 	  unsigned int PhysicalDeviceIndex = Controller->V2.PhysicalDeviceIndex;
 	  DAC960_V2_PhysicalDeviceInfo_T *PhysicalDeviceInfo =
 	    Controller->V2.PhysicalDeviceInformation[PhysicalDeviceIndex];
-	  DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber;
+	  DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber =
+	    Controller->V2.InquiryUnitSerialNumber[PhysicalDeviceIndex];
+	  unsigned int DeviceIndex;
+	  while (PhysicalDeviceInfo != NULL &&
+		 (NewPhysicalDeviceInfo->Channel >
+		  PhysicalDeviceInfo->Channel ||
+		  (NewPhysicalDeviceInfo->Channel ==
+		   PhysicalDeviceInfo->Channel &&
+		   (NewPhysicalDeviceInfo->TargetID >
+		    PhysicalDeviceInfo->TargetID ||
+		   (NewPhysicalDeviceInfo->TargetID ==
+		    PhysicalDeviceInfo->TargetID &&
+		    NewPhysicalDeviceInfo->LogicalUnit >
+		    PhysicalDeviceInfo->LogicalUnit)))))
+	    {
+	      DAC960_Critical("Physical Device %d:%d No Longer Exists\n",
+			      Controller,
+			      PhysicalDeviceInfo->Channel,
+			      PhysicalDeviceInfo->TargetID);
+	      Controller->V2.PhysicalDeviceInformation
+			     [PhysicalDeviceIndex] = NULL;
+	      Controller->V2.InquiryUnitSerialNumber
+			     [PhysicalDeviceIndex] = NULL;
+	      kfree(PhysicalDeviceInfo);
+	      kfree(InquiryUnitSerialNumber);
+	      for (DeviceIndex = PhysicalDeviceIndex;
+		   DeviceIndex < DAC960_V2_MaxPhysicalDevices - 1;
+		   DeviceIndex++)
+		{
+		  Controller->V2.PhysicalDeviceInformation[DeviceIndex] =
+		    Controller->V2.PhysicalDeviceInformation[DeviceIndex+1];
+		  Controller->V2.InquiryUnitSerialNumber[DeviceIndex] =
+		    Controller->V2.InquiryUnitSerialNumber[DeviceIndex+1];
+		}
+	      Controller->V2.PhysicalDeviceInformation
+			     [DAC960_V2_MaxPhysicalDevices-1] = NULL;
+	      Controller->V2.InquiryUnitSerialNumber
+			     [DAC960_V2_MaxPhysicalDevices-1] = NULL;
+	      PhysicalDeviceInfo =
+		Controller->V2.PhysicalDeviceInformation[PhysicalDeviceIndex];
+	      InquiryUnitSerialNumber =
+		Controller->V2.InquiryUnitSerialNumber[PhysicalDeviceIndex];
+	    }
 	  if (PhysicalDeviceInfo == NULL ||
 	      (NewPhysicalDeviceInfo->Channel !=
 	       PhysicalDeviceInfo->Channel) ||
@@ -4169,14 +4216,14 @@
 	      (NewPhysicalDeviceInfo->LogicalUnit !=
 	       PhysicalDeviceInfo->LogicalUnit))
 	    {
-	      unsigned int DeviceIndex;
 	      PhysicalDeviceInfo = (DAC960_V2_PhysicalDeviceInfo_T *)
 		kmalloc(sizeof(DAC960_V2_PhysicalDeviceInfo_T), GFP_ATOMIC);
 	      InquiryUnitSerialNumber =
 		(DAC960_SCSI_Inquiry_UnitSerialNumber_T *)
 		  kmalloc(sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T),
 			  GFP_ATOMIC);
-	      if (InquiryUnitSerialNumber == NULL)
+	      if (InquiryUnitSerialNumber == NULL &&
+		  PhysicalDeviceInfo != NULL)
 		{
 		  kfree(PhysicalDeviceInfo);
 		  PhysicalDeviceInfo = NULL;
@@ -4189,21 +4236,6 @@
 			       ? "" : " - Allocation Failed"));
 	      if (PhysicalDeviceInfo != NULL)
 		{
-		  for (DeviceIndex = PhysicalDeviceIndex;
-		       DeviceIndex < DAC960_V2_MaxPhysicalDevices - 1;
-		       DeviceIndex++)
-		    {
-		      Controller->V2.PhysicalDeviceInformation[DeviceIndex+1] =
-			Controller->V2.PhysicalDeviceInformation[DeviceIndex];
-		      Controller->V2.InquiryUnitSerialNumber[DeviceIndex+1] =
-			Controller->V2.InquiryUnitSerialNumber[DeviceIndex];
-		      Controller->V2.PhysicalDeviceInformation
-				     [PhysicalDeviceIndex] =
-			PhysicalDeviceInfo;
-		      Controller->V2.InquiryUnitSerialNumber
-				     [PhysicalDeviceIndex] =
-			InquiryUnitSerialNumber;
-		    }
 		  memset(PhysicalDeviceInfo, 0,
 			 sizeof(DAC960_V2_PhysicalDeviceInfo_T));
 		  PhysicalDeviceInfo->PhysicalDeviceState =
@@ -4211,6 +4243,21 @@
 		  memset(InquiryUnitSerialNumber, 0,
 			 sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T));
 		  InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F;
+		  for (DeviceIndex = DAC960_V2_MaxPhysicalDevices - 1;
+		       DeviceIndex > PhysicalDeviceIndex;
+		       DeviceIndex--)
+		    {
+		      Controller->V2.PhysicalDeviceInformation[DeviceIndex] =
+			Controller->V2.PhysicalDeviceInformation[DeviceIndex-1];
+		      Controller->V2.InquiryUnitSerialNumber[DeviceIndex] =
+			Controller->V2.InquiryUnitSerialNumber[DeviceIndex-1];
+		    }
+		  Controller->V2.PhysicalDeviceInformation
+				 [PhysicalDeviceIndex] =
+		    PhysicalDeviceInfo;
+		  Controller->V2.InquiryUnitSerialNumber
+				 [PhysicalDeviceIndex] =
+		    InquiryUnitSerialNumber;
 		  Controller->V2.NeedDeviceSerialNumberInformation = true;
 		}
 	    }
@@ -4273,8 +4320,10 @@
 				  NewPhysicalDeviceInfo
 				  ->PredictedFailuresDetected);
 		}
-	      if (PhysicalDeviceInfo->PhysicalDeviceState
-		  == DAC960_V2_Device_Dead &&
+	      if ((PhysicalDeviceInfo->PhysicalDeviceState
+		   == DAC960_V2_Device_Dead ||
+		   PhysicalDeviceInfo->PhysicalDeviceState
+		   == DAC960_V2_Device_InvalidState) &&
 		  NewPhysicalDeviceInfo->PhysicalDeviceState
 		  != DAC960_V2_Device_Dead)
 		Controller->V2.NeedDeviceSerialNumberInformation = true;
@@ -4285,7 +4334,28 @@
 	  Controller->V2.PhysicalDeviceIndex++;
 	}
       else if (CommandOpcode == DAC960_V2_GetPhysicalDeviceInfoValid)
-	Controller->V2.NeedPhysicalDeviceInformation = false;
+	{
+	  unsigned int DeviceIndex;
+	  for (DeviceIndex = Controller->V2.PhysicalDeviceIndex;
+	       DeviceIndex < DAC960_V2_MaxPhysicalDevices;
+	       DeviceIndex++)
+	    {
+	      DAC960_V2_PhysicalDeviceInfo_T *PhysicalDeviceInfo =
+		Controller->V2.PhysicalDeviceInformation[DeviceIndex];
+	      DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber =
+		Controller->V2.InquiryUnitSerialNumber[DeviceIndex];
+	      if (PhysicalDeviceInfo == NULL) break;
+	      DAC960_Critical("Physical Device %d:%d No Longer Exists\n",
+			      Controller,
+			      PhysicalDeviceInfo->Channel,
+			      PhysicalDeviceInfo->TargetID);
+	      Controller->V2.PhysicalDeviceInformation[DeviceIndex] = NULL;
+	      Controller->V2.InquiryUnitSerialNumber[DeviceIndex] = NULL;
+	      kfree(PhysicalDeviceInfo);
+	      kfree(InquiryUnitSerialNumber);
+	    }
+	  Controller->V2.NeedPhysicalDeviceInformation = false;
+	}
       else if (CommandOpcode == DAC960_V2_GetLogicalDeviceInfoValid &&
 	       CommandStatus == DAC960_V2_NormalCompletion)
 	{
@@ -4392,13 +4462,50 @@
 					 NewLogicalDeviceInfo
 					 ->PatrolOperationBlockNumber,
 					 LogicalDeviceSize);
+	      if (LogicalDeviceInfo->BackgroundInitializationInProgress &&
+		  !NewLogicalDeviceInfo->BackgroundInitializationInProgress)
+		DAC960_Progress("Logical Drive %d (/dev/rd/c%dd%d) "
+				"Background Initialization %s\n",
+				Controller,
+				LogicalDeviceNumber,
+				Controller->ControllerNumber,
+				LogicalDeviceNumber,
+				(NewLogicalDeviceInfo->LogicalDeviceControl
+						      .LogicalDeviceInitialized
+				 ? "Completed" : "Failed"));
 	      memcpy(LogicalDeviceInfo, NewLogicalDeviceInfo,
 		     sizeof(DAC960_V2_LogicalDeviceInfo_T));
 	    }
+	  Controller->V2.LogicalDriveFoundDuringScan
+			 [LogicalDeviceNumber] = true;
 	  NewLogicalDeviceInfo->LogicalDeviceNumber++;
 	}
       else if (CommandOpcode == DAC960_V2_GetLogicalDeviceInfoValid)
-	Controller->V2.NeedLogicalDeviceInformation = false;
+	{
+	  int LogicalDriveNumber;
+	  for (LogicalDriveNumber = 0;
+	       LogicalDriveNumber < DAC960_MaxLogicalDrives;
+	       LogicalDriveNumber++)
+	    {
+	      DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo =
+		Controller->V2.LogicalDeviceInformation[LogicalDriveNumber];
+	      if (LogicalDeviceInfo == NULL ||
+		  Controller->V2.LogicalDriveFoundDuringScan
+				 [LogicalDriveNumber])
+		continue;
+	      DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
+			      "No Longer Exists\n", Controller,
+			      LogicalDriveNumber,
+			      Controller->ControllerNumber,
+			      LogicalDriveNumber);
+	      Controller->V2.LogicalDeviceInformation
+			     [LogicalDriveNumber] = NULL;
+	      kfree(LogicalDeviceInfo);
+	      Controller->LogicalDriveInitiallyAccessible
+			  [LogicalDriveNumber] = false;
+	    }
+	  Controller->V2.NeedLogicalDeviceInformation = false;
+	}
       if (Controller->V2.HealthStatusBuffer->NextEventSequenceNumber
 	  - Controller->V2.NextEventSequenceNumber > 0)
 	{
@@ -4414,7 +4521,7 @@
 	  CommandMailbox->GetEvent.DataTransferMemoryAddress
 				  .ScatterGatherSegments[0]
 				  .SegmentDataPointer =
-	    Virtual_to_Bus(&Controller->V2.Event);
+	    Virtual_to_Bus64(&Controller->V2.Event);
 	  CommandMailbox->GetEvent.DataTransferMemoryAddress
 				  .ScatterGatherSegments[0]
 				  .SegmentByteCount =
@@ -4451,7 +4558,7 @@
 	      CommandMailbox->SCSI_10.DataTransferMemoryAddress
 				     .ScatterGatherSegments[0]
 				     .SegmentDataPointer =
-		Virtual_to_Bus(InquiryUnitSerialNumber);
+		Virtual_to_Bus64(InquiryUnitSerialNumber);
 	      CommandMailbox->SCSI_10.DataTransferMemoryAddress
 				     .ScatterGatherSegments[0]
 				     .SegmentByteCount =
@@ -4460,6 +4567,14 @@
 	      Controller->V2.NeedDeviceSerialNumberInformation = false;
 	      return;
 	    }
+	  if (Controller->V2.StartPhysicalDeviceInformationScan)
+	    {
+	      Controller->V2.PhysicalDeviceIndex = 0;
+	      Controller->V2.NewPhysicalDeviceInformation.Channel = 0;
+	      Controller->V2.NewPhysicalDeviceInformation.TargetID = 0;
+	      Controller->V2.NewPhysicalDeviceInformation.LogicalUnit = 0;
+	      Controller->V2.StartPhysicalDeviceInformationScan = false;
+	    }
 	  CommandMailbox->PhysicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL;
 	  CommandMailbox->PhysicalDeviceInfo.DataTransferSize =
 	    sizeof(DAC960_V2_PhysicalDeviceInfo_T);
@@ -4474,7 +4589,7 @@
 	  CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress
 					    .ScatterGatherSegments[0]
 					    .SegmentDataPointer =
-	    Virtual_to_Bus(&Controller->V2.NewPhysicalDeviceInformation);
+	    Virtual_to_Bus64(&Controller->V2.NewPhysicalDeviceInformation);
 	  CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress
 					    .ScatterGatherSegments[0]
 					    .SegmentByteCount =
@@ -4484,6 +4599,18 @@
 	}
       if (Controller->V2.NeedLogicalDeviceInformation)
 	{
+	  if (Controller->V2.StartLogicalDeviceInformationScan)
+	    {
+	      int LogicalDriveNumber;
+	      for (LogicalDriveNumber = 0;
+		   LogicalDriveNumber < DAC960_MaxLogicalDrives;
+		   LogicalDriveNumber++)
+		Controller->V2.LogicalDriveFoundDuringScan
+			       [LogicalDriveNumber] = false;
+	      Controller->V2.NewLogicalDeviceInformation
+			    .LogicalDeviceNumber = 0;
+	      Controller->V2.StartLogicalDeviceInformationScan = false;
+	    }
 	  CommandMailbox->LogicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL;
 	  CommandMailbox->LogicalDeviceInfo.DataTransferSize =
 	    sizeof(DAC960_V2_LogicalDeviceInfo_T);
@@ -4494,7 +4621,7 @@
 	  CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress
 					   .ScatterGatherSegments[0]
 					   .SegmentDataPointer =
-	    Virtual_to_Bus(&Controller->V2.NewLogicalDeviceInformation);
+	    Virtual_to_Bus64(&Controller->V2.NewLogicalDeviceInformation);
 	  CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress
 					   .ScatterGatherSegments[0]
 					   .SegmentByteCount =
@@ -4792,7 +4919,8 @@
   DAC960_V1_ClearCommand(Command);
   Command->CommandType = DAC960_MonitoringCommand;
   CommandMailbox->Type3.CommandOpcode = DAC960_V1_Enquiry;
-  CommandMailbox->Type3.BusAddress = Virtual_to_Bus(&Controller->V1.NewEnquiry);
+  CommandMailbox->Type3.BusAddress =
+    Virtual_to_Bus32(&Controller->V1.NewEnquiry);
   DAC960_QueueCommand(Command);
 }
 
@@ -4820,7 +4948,7 @@
   CommandMailbox->ControllerInfo.DataTransferMemoryAddress
 				.ScatterGatherSegments[0]
 				.SegmentDataPointer =
-    Virtual_to_Bus(&Controller->V2.NewControllerInformation);
+    Virtual_to_Bus64(&Controller->V2.NewControllerInformation);
   CommandMailbox->ControllerInfo.DataTransferMemoryAddress
 				.ScatterGatherSegments[0]
 				.SegmentByteCount =
@@ -4863,6 +4991,28 @@
 	&Controller->V2.ControllerInformation;
       unsigned int StatusChangeCounter =
 	Controller->V2.HealthStatusBuffer->StatusChangeCounter;
+      boolean ForceMonitoringCommand = false;
+      if (jiffies - Controller->SecondaryMonitoringTime
+	  > DAC960_SecondaryMonitoringInterval)
+	{
+	  int LogicalDriveNumber;
+	  for (LogicalDriveNumber = 0;
+	       LogicalDriveNumber < DAC960_MaxLogicalDrives;
+	       LogicalDriveNumber++)
+	    {
+	      DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo =
+		Controller->V2.LogicalDeviceInformation[LogicalDriveNumber];
+	      if (LogicalDeviceInfo == NULL) continue;
+	      if (!LogicalDeviceInfo->LogicalDeviceControl
+				     .LogicalDeviceInitialized &&
+		  Controller->LogicalDriveUsageCount[LogicalDriveNumber] > 0)
+		{
+		  ForceMonitoringCommand = true;
+		  break;
+		}
+	    }
+	  Controller->SecondaryMonitoringTime = jiffies;
+	}
       if (StatusChangeCounter == Controller->V2.StatusChangeCounter &&
 	  Controller->V2.HealthStatusBuffer->NextEventSequenceNumber
 	  == Controller->V2.NextEventSequenceNumber &&
@@ -4873,7 +5023,8 @@
 	   ControllerInfo->RebuildsActive +
 	   ControllerInfo->OnlineExpansionsActive == 0 ||
 	   jiffies - Controller->PrimaryMonitoringTime
-	   < DAC960_MonitoringTimerInterval))
+	   < DAC960_MonitoringTimerInterval) &&
+	  !ForceMonitoringCommand)
 	{
 	  Controller->MonitoringTimer.expires =
 	    jiffies + DAC960_HealthStatusMonitoringInterval;
@@ -4997,8 +5148,7 @@
   DiskGeometry_T Geometry, *UserGeometry;
   DAC960_Controller_T *Controller;
   int PartitionNumber;
-  if (File == NULL) return -EINVAL;
-  if (File->f_flags & O_NONBLOCK)
+  if (File != NULL && (File->f_flags & O_NONBLOCK))
     return DAC960_UserIOCTL(Inode, File, Request, Argument);
   if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1)
     return -ENXIO;
@@ -5225,10 +5375,17 @@
 	if (CommandOpcode == DAC960_V1_DCDB)
 	  {
 	    DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
-	    while (Controller->V1.DirectCommandActive[DCDB.Channel]
-						     [DCDB.TargetID] ||
-		   (Command = DAC960_AllocateCommand(Controller)) == NULL)
+	    while ((Command = DAC960_AllocateCommand(Controller)) == NULL)
 	      DAC960_WaitForCommand(Controller);
+	    while (Controller->V1.DirectCommandActive[DCDB.Channel]
+						     [DCDB.TargetID])
+	      {
+		spin_unlock_irq(&io_request_lock);
+		__wait_event(Controller->CommandWaitQueue,
+			     !Controller->V1.DirectCommandActive
+					     [DCDB.Channel][DCDB.TargetID]);
+		spin_lock_irq(&io_request_lock);
+	      }
 	    Controller->V1.DirectCommandActive[DCDB.Channel]
 					      [DCDB.TargetID] = true;
 	    DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
@@ -5237,8 +5394,8 @@
 	    memcpy(&Command->V1.CommandMailbox, &UserCommand.CommandMailbox,
 		   sizeof(DAC960_V1_CommandMailbox_T));
 	    Command->V1.CommandMailbox.Type3.BusAddress =
-	      Virtual_to_Bus(&DCDB);
-	    DCDB.BusAddress = Virtual_to_Bus(DataTransferBuffer);
+	      Virtual_to_Bus32(&DCDB);
+	    DCDB.BusAddress = Virtual_to_Bus32(DataTransferBuffer);
 	  }
 	else
 	  {
@@ -5252,7 +5409,7 @@
 		   sizeof(DAC960_V1_CommandMailbox_T));
 	    if (DataTransferBuffer != NULL)
 	      Command->V1.CommandMailbox.Type3.BusAddress =
-		Virtual_to_Bus(DataTransferBuffer);
+		Virtual_to_Bus32(DataTransferBuffer);
 	  }
 	DAC960_ExecuteCommand(Command);
 	CommandStatus = Command->V1.CommandStatus;
@@ -5365,7 +5522,7 @@
 	    CommandMailbox->Common.DataTransferMemoryAddress
 				  .ScatterGatherSegments[0]
 				  .SegmentDataPointer =
-	      Virtual_to_Bus(DataTransferBuffer);
+	      Virtual_to_Bus64(DataTransferBuffer);
 	    CommandMailbox->Common.DataTransferMemoryAddress
 				  .ScatterGatherSegments[0]
 				  .SegmentByteCount =
@@ -5377,7 +5534,7 @@
 				  .NoAutoRequestSense = false;
 	    CommandMailbox->Common.RequestSenseSize = RequestSenseLength;
 	    CommandMailbox->Common.RequestSenseBusAddress =
-	      Virtual_to_Bus(RequestSenseBuffer);
+	      Virtual_to_Bus64(RequestSenseBuffer);
 	  }
 	DAC960_ExecuteCommand(Command);
 	CommandStatus = Command->V2.CommandStatus;
@@ -5557,9 +5714,9 @@
 	    memcpy(&Command->V1.CommandMailbox, &KernelCommand->CommandMailbox,
 		   sizeof(DAC960_V1_CommandMailbox_T));
 	    Command->V1.CommandMailbox.Type3.BusAddress =
-	      Virtual_to_Bus(DCDB);
+	      Virtual_to_Bus32(DCDB);
 	    Command->V1.KernelCommand = KernelCommand;
-	    DCDB->BusAddress = Virtual_to_Bus(DataTransferBuffer);
+	    DCDB->BusAddress = Virtual_to_Bus32(DataTransferBuffer);
 	    DAC960_QueueCommand(Command);
 	    DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
 	  }
@@ -5578,7 +5735,7 @@
 		   sizeof(DAC960_V1_CommandMailbox_T));
 	    if (DataTransferBuffer != NULL)
 	      Command->V1.CommandMailbox.Type3.BusAddress =
-		Virtual_to_Bus(DataTransferBuffer);
+		Virtual_to_Bus32(DataTransferBuffer);
 	    Command->V1.KernelCommand = KernelCommand;
 	    DAC960_QueueCommand(Command);
 	    DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
@@ -5655,7 +5812,7 @@
 	    CommandMailbox->Common.DataTransferMemoryAddress
 				  .ScatterGatherSegments[0]
 				  .SegmentDataPointer =
-	      Virtual_to_Bus(DataTransferBuffer);
+	      Virtual_to_Bus64(DataTransferBuffer);
 	    CommandMailbox->Common.DataTransferMemoryAddress
 				  .ScatterGatherSegments[0]
 				  .SegmentByteCount =
@@ -5666,7 +5823,7 @@
 	    CommandMailbox->Common.CommandControlBits
 				  .NoAutoRequestSense = false;
 	    CommandMailbox->Common.RequestSenseBusAddress =
-	      Virtual_to_Bus(RequestSenseBuffer);
+	      Virtual_to_Bus64(RequestSenseBuffer);
 	  }
 	Command->V2.KernelCommand = KernelCommand;
 	DAC960_QueueCommand(Command);
@@ -6104,7 +6261,7 @@
       CommandMailbox->Type3R.CommandOpcode = DAC960_V1_RebuildControl;
       CommandMailbox->Type3R.RebuildRateConstant = 0xFF;
       CommandMailbox->Type3R.BusAddress =
-	Virtual_to_Bus(&OldRebuildRateConstant);
+	Virtual_to_Bus32(&OldRebuildRateConstant);
       DAC960_ExecuteCommand(Command);
       switch (Command->V1.CommandStatus)
 	{
@@ -6160,7 +6317,7 @@
   CommandMailbox->Common.DataTransferMemoryAddress
 			.ScatterGatherSegments[0]
 			.SegmentDataPointer =
-    Virtual_to_Bus(&PhysicalToLogicalDevice);
+    Virtual_to_Bus64(&PhysicalToLogicalDevice);
   CommandMailbox->Common.DataTransferMemoryAddress
 			.ScatterGatherSegments[0]
 			.SegmentByteCount =
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/DAC960.h linux.19p18/drivers/block/DAC960.h
--- linux.vanilla/drivers/block/DAC960.h	Sat Sep  9 18:42:34 2000
+++ linux.19p18/drivers/block/DAC960.h	Wed Feb 14 14:23:34 2001
@@ -2,7 +2,7 @@
 
   Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers
 
-  Copyright 1998-2000 by Leonard N. Zubkoff <lnz@dandelion.com>
+  Copyright 1998-2001 by Leonard N. Zubkoff <lnz@dandelion.com>
 
   This program is free software; you may redistribute and/or modify it under
   the terms of the GNU General Public License Version 2 as published by the
@@ -259,6 +259,7 @@
   DAC960_V1_ClearBadDataTable =			0x26,
   DAC960_V1_GetErrorTable =			0x17,
   DAC960_V1_AddCapacityAsync =			0x2A,
+  DAC960_V1_BackgroundInitializationControl =	0x2B,
   /* Configuration Related Commands */
   DAC960_V1_ReadConfig2 =			0x3D,
   DAC960_V1_WriteConfig2 =			0x3C,
@@ -450,14 +451,16 @@
   unsigned int NonVolatileMemorySize;			/* Bytes 36-39 */
   struct {
     enum {
-      DAC960_V1_DRAM =				0x0,
-      DAC960_V1_EDO =				0x1,
-      DAC960_V1_SDRAM =				0x2
+      DAC960_V1_RamType_DRAM =			0x0,
+      DAC960_V1_RamType_EDO =			0x1,
+      DAC960_V1_RamType_SDRAM =			0x2,
+      DAC960_V1_RamType_Last =			0x7
     } __attribute__ ((packed)) RamType:3;		/* Byte 40 Bits 0-2 */
     enum {
-      DAC960_V1_None =				0x0,
-      DAC960_V1_Parity =			0x1,
-      DAC960_V1_ECC =				0x2
+      DAC960_V1_ErrorCorrection_None =		0x0,
+      DAC960_V1_ErrorCorrection_Parity =	0x1,
+      DAC960_V1_ErrorCorrection_ECC =		0x2,
+      DAC960_V1_ErrorCorrection_Last =		0x7
     } __attribute__ ((packed)) ErrorCorrection:3;	/* Byte 40 Bits 3-5 */
     boolean FastPageMode:1;				/* Byte 40 Bit 6 */
     boolean LowPowerMemory:1;				/* Byte 40 Bit 7 */
@@ -523,7 +526,9 @@
   struct {
     boolean Clustering:1;				/* Byte 116 Bit 0 */
     boolean MylexOnlineRAIDExpansion:1;			/* Byte 116 Bit 1 */
-    unsigned int :30;					/* Bytes 116-119 */
+    boolean ReadAhead:1;				/* Byte 116 Bit 2 */
+    boolean BackgroundInitialization:1;			/* Byte 116 Bit 3 */
+    unsigned int :28;					/* Bytes 116-119 */
   } FirmwareFeatures;
   unsigned int :32;					/* Bytes 120-123 */
   unsigned int :32;					/* Bytes 124-127 */
@@ -993,7 +998,8 @@
     DAC960_V2_MemoryType_DRAM =			0x01,
     DAC960_V2_MemoryType_EDRAM =		0x02,
     DAC960_V2_MemoryType_EDO =			0x03,
-    DAC960_V2_MemoryType_SDRAM =		0x04
+    DAC960_V2_MemoryType_SDRAM =		0x04,
+    DAC960_V2_MemoryType_Last =			0x1F
   } __attribute__ ((packed)) MemoryType:5;		/* Byte 0 Bits 0-4 */
   boolean :1;						/* Byte 0 Bit 5 */
   boolean MemoryParity:1;				/* Byte 0 Bit 6 */
@@ -1269,13 +1275,15 @@
       DAC960_V2_ReadCacheDisabled =		0x0,
       DAC960_V2_ReadCacheEnabled =		0x1,
       DAC960_V2_ReadAheadEnabled =		0x2,
-      DAC960_V2_IntelligentReadAheadEnabled =	0x3
+      DAC960_V2_IntelligentReadAheadEnabled =	0x3,
+      DAC960_V2_ReadCache_Last =		0x7
     } __attribute__ ((packed)) ReadCache:3;		/* Byte 8 Bits 0-2 */
     enum {
       DAC960_V2_WriteCacheDisabled =		0x0,
       DAC960_V2_LogicalDeviceReadOnly =		0x1,
       DAC960_V2_WriteCacheEnabled =		0x2,
-      DAC960_V2_IntelligentWriteCacheEnabled =	0x3
+      DAC960_V2_IntelligentWriteCacheEnabled =	0x3,
+      DAC960_V2_WriteCache_Last =		0x7
     } __attribute__ ((packed)) WriteCache:3;		/* Byte 8 Bits 3-5 */
     boolean :1;						/* Byte 8 Bit 6 */
     boolean LogicalDeviceInitialized:1;			/* Byte 8 Bit 7 */
@@ -2336,6 +2344,7 @@
       boolean NeedDeviceSerialNumberInformation;
       boolean NeedRebuildProgress;
       boolean NeedConsistencyCheckProgress;
+      boolean StartDeviceStateScan;
       boolean RebuildProgressFirst;
       boolean RebuildFlagPending;
       boolean RebuildStatusPending;
@@ -2375,6 +2384,8 @@
       boolean NeedLogicalDeviceInformation;
       boolean NeedPhysicalDeviceInformation;
       boolean NeedDeviceSerialNumberInformation;
+      boolean StartLogicalDeviceInformationScan;
+      boolean StartPhysicalDeviceInformationScan;
       DAC960_V2_CommandMailbox_T *FirstCommandMailbox;
       DAC960_V2_CommandMailbox_T *LastCommandMailbox;
       DAC960_V2_CommandMailbox_T *NextCommandMailbox;
@@ -2397,6 +2408,7 @@
       DAC960_V2_PhysicalDevice_T
 	LogicalDriveToVirtualDevice[DAC960_MaxLogicalDrives];
       DAC960_V2_Event_T Event;
+      boolean LogicalDriveFoundDuringScan[DAC960_MaxLogicalDrives];
     } V2;
   } FW;
   DiskPartition_T DiskPartitions[DAC960_MinorCount];
@@ -2504,26 +2516,39 @@
 
 
 /*
-  Virtual_to_Bus maps from Kernel Virtual Addresses to PCI Bus Addresses.
+  Virtual_to_Bus32 maps from Kernel Virtual Addresses to 32 Bit PCI Bus
+  Addresses.
 */
 
-static inline DAC960_BusAddress32_T Virtual_to_Bus(void *VirtualAddress)
+static inline DAC960_BusAddress32_T Virtual_to_Bus32(void *VirtualAddress)
 {
   return (DAC960_BusAddress32_T) virt_to_bus(VirtualAddress);
 }
 
 
 /*
-  Bus_to_Virtual maps from PCI Bus Addresses to Kernel Virtual Addresses.
+  Bus32_to_Virtual maps from 32 Bit PCI Bus Addresses to Kernel Virtual
+  Addresses.
 */
 
-static inline void *Bus_to_Virtual(DAC960_BusAddress32_T BusAddress)
+static inline void *Bus32_to_Virtual(DAC960_BusAddress32_T BusAddress)
 {
   return (void *) bus_to_virt(BusAddress);
 }
 
 
 /*
+  Virtual_to_Bus64 maps from Kernel Virtual Addresses to 64 Bit PCI Bus
+  Addresses.
+*/
+
+static inline DAC960_BusAddress64_T Virtual_to_Bus64(void *VirtualAddress)
+{
+  return (DAC960_BusAddress64_T) virt_to_bus(VirtualAddress);
+}
+
+
+/*
   Define the DAC960 BA Series Controller Interface Register Offsets.
 */
 
@@ -2790,8 +2815,13 @@
 void DAC960_BA_WriteHardwareMailbox(void *ControllerBaseAddress,
 				    DAC960_V2_CommandMailbox_T *CommandMailbox)
 {
-  writel(Virtual_to_Bus(CommandMailbox),
+#ifdef __ia64__
+  writeq(Virtual_to_Bus64(CommandMailbox),
 	 ControllerBaseAddress + DAC960_BA_CommandMailboxBusAddressOffset);
+#else
+  writel(Virtual_to_Bus32(CommandMailbox),
+	 ControllerBaseAddress + DAC960_BA_CommandMailboxBusAddressOffset);
+#endif
 }
 
 static inline DAC960_V2_CommandIdentifier_T
@@ -3091,8 +3121,13 @@
 void DAC960_LP_WriteHardwareMailbox(void *ControllerBaseAddress,
 				    DAC960_V2_CommandMailbox_T *CommandMailbox)
 {
-  writel(Virtual_to_Bus(CommandMailbox),
+#ifdef __ia64__
+  writeq(Virtual_to_Bus64(CommandMailbox),
+	 ControllerBaseAddress + DAC960_LP_CommandMailboxBusAddressOffset);
+#else
+  writel(Virtual_to_Bus32(CommandMailbox),
 	 ControllerBaseAddress + DAC960_LP_CommandMailboxBusAddressOffset);
+#endif
 }
 
 static inline DAC960_V2_CommandIdentifier_T
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/genhd.c linux.19p18/drivers/block/genhd.c
--- linux.vanilla/drivers/block/genhd.c	Mon Dec 11 22:12:40 2000
+++ linux.19p18/drivers/block/genhd.c	Tue Feb 20 13:27:20 2001
@@ -54,6 +54,14 @@
 				le32_to_cpu(__a); \
 			})
 
+#define MSDOS_LABEL_MAGIC1		0x55
+#define MSDOS_LABEL_MAGIC2		0xAA
+
+static inline int
+msdos_magic_present(unsigned char *p) {
+	return (p[0] == MSDOS_LABEL_MAGIC1 && p[1] == MSDOS_LABEL_MAGIC2);
+}
+
 struct gendisk *gendisk_head = NULL;
 
 static int current_minor = 0;
@@ -244,8 +252,6 @@
  * only for the actual data partitions.
  */
 
-#define MSDOS_LABEL_MAGIC		0xAA55
-
 static void extended_partition(struct gendisk *hd, kdev_t dev, int sector_size)
 {
 	struct buffer_head *bh;
@@ -273,10 +279,10 @@
 	   */
 		bh->b_state = 0;
 
-		if ((*(unsigned short *) (bh->b_data+510)) != cpu_to_le16(MSDOS_LABEL_MAGIC))
+		if (!(msdos_magic_present(bh->b_data + 510)))
 			goto done;
 
-		p = (struct partition *) (0x1BE + bh->b_data);
+		p = (struct partition *) (bh->b_data + 0x1be);
 
 		this_size = hd->part[MINOR(dev)].nr_sects;
 
@@ -499,7 +505,51 @@
 	printk(" >");
 }
 #endif
+		
+#ifdef CONFIG_MINIX_SUBPARTITION
+/*
+ * Minix 2.0.0/2.0.2 subpartition support.
+ * Anand Krishnamurthy <anandk@wiproge.med.ge.com>
+ * Rajeev V. Pillai    <rajeevvp@yahoo.com>
+ */
+#define MINIX_PARTITION         0x81  /* Minix Partition ID */
+#define MINIX_NR_SUBPARTITIONS  4
+static void minix_partition(struct gendisk *hd, kdev_t dev)
+{
+	struct buffer_head *bh;
+	struct partition *p;
+	int mask = (1 << hd->minor_shift) - 1;
+	int i;
 
+	if (!(bh = bread(dev, 0, get_ptable_blocksize(dev))))
+		return;
+	bh->b_state = 0;
+
+	p = (struct partition *)(bh->b_data + 0x1be);
+
+	/* The first sector of a Minix partition can have either
+	 * a secondary MBR describing its subpartitions, or
+	 * the normal boot sector. */
+	if (msdos_magic_present(bh->b_data + 510) &&
+	    SYS_IND(p) == MINIX_PARTITION) { /* subpartition table present */
+
+		printk(" <");
+		for (i = 0; i < MINIX_NR_SUBPARTITIONS; i++, p++) {
+			if ((current_minor & mask) == 0) 
+				break;
+			/* add each partition in use */
+			if (SYS_IND(p) == MINIX_PARTITION) {
+				add_partition(hd, current_minor,
+					      START_SECT(p), NR_SECTS(p), 0);
+				current_minor++;
+			}
+		}
+		printk(" >");
+	}
+	brelse(bh);
+}
+#endif /* CONFIG_MINIX_SUBPARTITION */
+ 
 static int msdos_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector)
 {
 	int i, minor = current_minor;
@@ -540,11 +590,11 @@
 #ifdef CONFIG_BLK_DEV_IDE
 check_table:
 #endif
-	if (*(unsigned short *)  (0x1fe + data) != cpu_to_le16(MSDOS_LABEL_MAGIC)) {
+	if (!(msdos_magic_present(data + 510))) {
 		brelse(bh);
 		return 0;
 	}
-	p = (struct partition *) (0x1be + data);
+	p = (struct partition *) (data + 0x1be);
 
 #ifdef CONFIG_BLK_DEV_IDE
 	if (!tested_for_xlate++) {	/* Do this only once per disk */
@@ -649,8 +699,8 @@
 	for (i=1 ; i<=4 ; minor++,i++,p++) {
 		if (!NR_SECTS(p))
 			continue;
-               add_partition(hd, minor, first_sector+START_SECT(p)*sector_size, NR_SECTS(p)*sector_size, 
-               		     ptype(SYS_IND(p)));
+               add_partition(hd, minor, first_sector+START_SECT(p)*sector_size,
+			     NR_SECTS(p)*sector_size, ptype(SYS_IND(p)));
 		if (is_extended_partition(p)) {
 			printk(" <");
 			/*
@@ -682,6 +732,12 @@
 			}
 		}
 #endif
+#ifdef CONFIG_MINIX_SUBPARTITION
+		if (SYS_IND(p) == MINIX_PARTITION) {
+			printk("@");	/* Minix partitions are indicated by '@' */
+			minix_partition(hd, MKDEV(hd->major, minor));
+		}
+#endif
 #ifdef CONFIG_UNIXWARE_DISKLABEL
 		if (SYS_IND(p) == UNIXWARE_PARTITION)
 			unixware_partition(hd, MKDEV(hd->major, minor));
@@ -709,7 +765,7 @@
 	/*
 	 *  Check for old-style Disk Manager partition table
 	 */
-	if (*(unsigned short *) (data+0xfc) == cpu_to_le16(MSDOS_LABEL_MAGIC)) {
+	if (msdos_magic_present(data + 0xfc)) {
 		p = (struct partition *) (0x1be + data);
 		for (i = 4 ; i < 16 ; i++, current_minor++) {
 			p--;
@@ -1736,7 +1792,7 @@
 }
 
 #ifdef CONFIG_PROC_FS
-int get_partition_list(char * page)
+int get_partition_list(char *page, char **start, off_t offset, int count)
 {
 	struct gendisk *p;
 	char buf[MAX_DISKNAME_LEN];
@@ -1745,14 +1801,23 @@
 	len = sprintf(page, "major minor  #blocks  name\n\n");
 	for (p = gendisk_head; p; p = p->next) {
 		for (n=0; n < (p->nr_real << p->minor_shift); n++) {
-			if (p->part[n].nr_sects && len < PAGE_SIZE - 80) {
+			if (p->part[n].nr_sects) {
 				len += sprintf(page+len,
 					       "%4d  %4d %10d %s\n",
 					       p->major, n, p->sizes[n],
 					       disk_name(p, n, buf));
+				if (len < offset) 
+					offset -= len, len = 0;
+				else if (len >= offset + count)
+					goto leave_loops;
 			}
 		}
 	}
-	return len;
+leave_loops:
+	*start = page + offset;
+	len -= offset;
+	if (len < 0)
+		len = 0;
+	return len > count ? count : len;
 }
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/hd.c linux.19p18/drivers/block/hd.c
--- linux.vanilla/drivers/block/hd.c	Mon Dec 11 22:12:40 2000
+++ linux.19p18/drivers/block/hd.c	Tue Jan  9 12:14:00 2001
@@ -703,12 +703,12 @@
 static void hd_geninit(struct gendisk *ignored)
 {
 	int drive;
-	unsigned long flags;
 
 #ifdef __i386__
 	if (!NR_HD) {
 		extern struct drive_info drive_info;
 		unsigned char *BIOS = (unsigned char *) &drive_info;
+		unsigned long flags;
 		int cmos_disks;
 
 		for (drive=0 ; drive<2 ; drive++) {
@@ -747,13 +747,15 @@
 		
 	*/
                 spin_lock_irqsave(&rtc_lock, flags);
-		if ((cmos_disks = CMOS_READ(0x12)) & 0xf0) {
+		cmos_disks = CMOS_READ(0x12);
+		spin_unlock_irqrestore(&rtc_lock, flags);
+
+		if (cmos_disks & 0xf0) {
 			if (cmos_disks & 0x0f)
 				NR_HD = 2;
 			else
 				NR_HD = 1;
 		}
-		spin_unlock_irqrestore(&rtc_lock, flags);
 	}
 #endif /* __i386__ */
 	for (drive=0 ; drive < NR_HD ; drive++) {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/ide-pmac.c linux.19p18/drivers/block/ide-pmac.c
--- linux.vanilla/drivers/block/ide-pmac.c	Mon Dec 11 22:12:40 2000
+++ linux.19p18/drivers/block/ide-pmac.c	Sat Mar  3 22:33:53 2001
@@ -905,7 +905,8 @@
 	 * Problem: This can schedule. I moved the block device
 	 * wakeup almost late by priority because of that.
 	 */
-	DRIVER(drive)->media_change(drive);
+	if (DRIVER(drive))
+		DRIVER(drive)->media_change(drive);
 
 	/* We kick the VFS too (see fix in ide.c revalidate) */
 	check_disk_change(MKDEV(HWIF(drive)->major, (drive->select.b.unit) << PARTN_BITS));
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/ll_rw_blk.c linux.19p18/drivers/block/ll_rw_blk.c
--- linux.vanilla/drivers/block/ll_rw_blk.c	Mon Dec 11 22:12:40 2000
+++ linux.19p18/drivers/block/ll_rw_blk.c	Thu Feb 15 16:12:00 2001
@@ -24,6 +24,10 @@
 #include <asm/uaccess.h>
 #include <linux/blk.h>
 
+#ifdef CONFIG_POWERMAC
+#include <asm/ide.h>
+#endif
+
 #include <linux/module.h>
 
 /*
@@ -971,7 +975,11 @@
 	isp16_init();
 #endif CONFIG_ISP16_CDI
 #ifdef CONFIG_BLK_DEV_IDE
+#ifdef CONFIG_POWERMAC
+	ide_pmac_init();
+#else
 	ide_init();		/* this MUST precede hd_init */
+#endif
 #endif
 #ifdef CONFIG_BLK_DEV_HD
 	hd_init();
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/block/rd.c linux.19p18/drivers/block/rd.c
--- linux.vanilla/drivers/block/rd.c	Mon Dec 11 22:12:40 2000
+++ linux.19p18/drivers/block/rd.c	Thu Dec 21 22:51:11 2000
@@ -173,7 +173,7 @@
 	if (CURRENT->cmd == READ) 
 		memset(CURRENT->buffer, 0, len); 
 	else	
-		set_bit(BH_Protected, &CURRENT->bh->b_state);
+		mark_buffer_protected(CURRENT->bh);
 
 	end_request(1);
 	goto repeat;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/cdrom/cdrom.c linux.19p18/drivers/cdrom/cdrom.c
--- linux.vanilla/drivers/cdrom/cdrom.c	Mon Dec 11 22:12:40 2000
+++ linux.19p18/drivers/cdrom/cdrom.c	Sun Mar 11 13:10:26 2001
@@ -1140,15 +1140,18 @@
 
 static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s)
 {
-	int ret, i;
-	u_char buf[4 + 4 * 20], *base;
+	unsigned char buf[20], *base;
 	struct dvd_layer *layer;
 	struct cdrom_generic_command cgc;
 	struct cdrom_device_ops *cdo = cdi->ops;
+	int ret, layer_num = s->physical.layer_num;
+
+	if (layer_num >= DVD_LAYERS)
+		return -EINVAL;
 
 	init_cdrom_command(&cgc, buf, sizeof(buf));
 	cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
-	cgc.cmd[6] = s->physical.layer_num;
+	cgc.cmd[6] = layer_num;
 	cgc.cmd[7] = s->type;
 	cgc.cmd[9] = cgc.buflen & 0xff;
 
@@ -1156,26 +1159,26 @@
 		return ret;
 
 	base = &buf[4];
-	layer = &s->physical.layer[0];
+	layer = &s->physical.layer[layer_num];
 
-	/* place the data... really ugly, but at least we won't have to
-	   worry about endianess in userspace or here. */
-	for (i = 0; i < 4; ++i, base += 20, ++layer) {
-		memset(layer, 0, sizeof(*layer));
-		layer->book_version = base[0] & 0xf;
-		layer->book_type = base[0] >> 4;
-		layer->min_rate = base[1] & 0xf;
-		layer->disc_size = base[1] >> 4;
-		layer->layer_type = base[2] & 0xf;
-		layer->track_path = (base[2] >> 4) & 1;
-		layer->nlayers = (base[2] >> 5) & 3;
-		layer->track_density = base[3] & 0xf;
-		layer->linear_density = base[3] >> 4;
-		layer->start_sector = base[5] << 16 | base[6] << 8 | base[7];
-		layer->end_sector = base[9] << 16 | base[10] << 8 | base[11];
-		layer->end_sector_l0 = base[13] << 16 | base[14] << 8 | base[15];
-		layer->bca = base[16] >> 7;
-	}
+	/*
+	 * place the data... really ugly, but at least we won't have to
+	 * worry about endianess in userspace.
+	 */
+	memset(layer, 0, sizeof(*layer));
+	layer->book_version = base[0] & 0xf;
+	layer->book_type = base[0] >> 4;
+	layer->min_rate = base[1] & 0xf;
+	layer->disc_size = base[1] >> 4;
+	layer->layer_type = base[2] & 0xf;
+	layer->track_path = (base[2] >> 4) & 1;
+	layer->nlayers = (base[2] >> 5) & 3;
+	layer->track_density = base[3] & 0xf;
+	layer->linear_density = base[3] >> 4;
+	layer->start_sector = base[5] << 16 | base[6] << 8 | base[7];
+	layer->end_sector = base[9] << 16 | base[10] << 8 | base[11];
+	layer->end_sector_l0 = base[13] << 16 | base[14] << 8 | base[15];
+	layer->bca = base[16] >> 7;
 
 	return 0;
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/Config.in linux.19p18/drivers/char/Config.in
--- linux.vanilla/drivers/char/Config.in	Mon Dec 11 22:12:40 2000
+++ linux.19p18/drivers/char/Config.in	Thu Feb 15 16:19:20 2001
@@ -60,7 +60,7 @@
 if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
 	int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
 fi
-if [ "$CONFIG_PARPORT" != "n" ]; then
+if [ "$CONFIG_PARPORT" = "y" -o "$CONFIG_PARPORT" = "m" ]; then
   dep_tristate 'Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
   if [ "$CONFIG_PRINTER" != "n" ]; then
     bool '  Support IEEE1284 status readback' CONFIG_PRINTER_READBACK
@@ -99,7 +99,14 @@
   mainmenu_option next_comment
   comment 'Watchdog Cards'
   bool '   Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT
-  tristate '   WDT Watchdog timer' CONFIG_WDT
+  tristate '   Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT
+  tristate '   Advantech SBC Watchdog Timer' CONFIG_ADVANTECH_WDT
+  tristate '   Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG
+  tristate '  Intel i810 TCO timer / Watchdog' CONFIG_I810_TCO
+  tristate '   Mixcom Watchdog' CONFIG_MIXCOMWD 
+  tristate '   SBC-60XX Watchdog Timer' CONFIG_60XX_WDT
+  tristate '   Software Watchdog' CONFIG_SOFT_WATCHDOG
+  tristate '   WDT ISA Watchdog timer' CONFIG_WDT
   if [ "$CONFIG_WDT" != "n" ]; then
      bool '       WDT501 features' CONFIG_WDT_501
      if [ "$CONFIG_WDT_501" = "y" ]; then
@@ -107,11 +114,6 @@
      fi
   fi
   tristate '   WDT PCI Watchdog timer' CONFIG_WDTPCI
-  tristate '   Software Watchdog' CONFIG_SOFT_WATCHDOG
-  tristate '   Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG
-  tristate '   Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT
-  tristate '   SBC-60XX Watchdog Timer' CONFIG_60XX_WDT
-  tristate '   Mixcom Watchdog' CONFIG_MIXCOMWD 
   endmenu
 fi
 
@@ -126,10 +128,10 @@
 fi
 
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-   tristate '/dev/agpgart (AGP Support) (EXPERIMENTAL)' CONFIG_AGP n
+   tristate '/dev/agpgart (AGP Support) (EXPERIMENTAL)' CONFIG_AGP
    if [ "$CONFIG_AGP" != "n" ]; then
-      bool '   Intel 440LX/BX/GX support' CONFIG_AGP_INTEL
-      bool '   Intel I810/I810 DC100/I810e support' CONFIG_AGP_I810
+      bool '   Intel 440LX/BX/GX and I815/820 support' CONFIG_AGP_INTEL
+      bool '   Intel I810/I815 (on-board video) support' CONFIG_AGP_I810
       bool '   VIA VP3/MVP3/Apollo Pro support' CONFIG_AGP_VIA
       bool '   AMD Irongate support' CONFIG_AGP_AMD
       bool '   Generic SiS support' CONFIG_AGP_SIS
@@ -166,24 +168,22 @@
   if [ "$CONFIG_RADIO_TRUST" = "y" ]; then
     hex '  Trust FM Radio I/O port (0x350 or 0x358)' CONFIG_RADIO_TRUST_PORT 350
   fi
-  if [ "$CONFIG_PCI" != "n" ]; then
+  if [ "$CONFIG_PCI" = "y" ]; then
     dep_tristate 'BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV
     if [ "$CONFIG_VIDEO_BT848" != "n" ]; then
       comment '  MSP3400 sound decoder support is in the section "additional'
       comment '  low level sound drivers". You may need to enable it there.'
     fi
   fi
-  if [ "$CONFIG_PARPORT" != "n" ]; then
+  if [ "$CONFIG_PARPORT" = "y" -o "$CONFIG_PARPORT" = "m" ]; then
     dep_tristate 'Quickcam BW Video For Linux' CONFIG_VIDEO_BWQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT
     dep_tristate 'Colour QuickCam Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_CQCAM $CONFIG_VIDEO_DEV $CONFIG_PARPORT
   fi
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
     dep_tristate 'CPiA Video For Linux' CONFIG_VIDEO_CPIA $CONFIG_VIDEO_DEV
     if [ "$CONFIG_VIDEO_CPIA" != "n" ]; then
-      if [ "CONFIG_PARPORT_1284" != "n" ]; then
-        dep_tristate '  CPiA Parallel Port Lowlevel Support' CONFIG_VIDEO_CPIA_PP $CONFIG_VIDEO_CPIA $CONFIG_PARPORT
-      fi
-      if [ "$CONFIG_USB" != "n" ]; then
+      dep_tristate '  CPiA Parallel Port Lowlevel Support' CONFIG_VIDEO_CPIA_PP $CONFIG_VIDEO_CPIA $CONFIG_PARPORT
+      if [ "$CONFIG_USB" = "y" -o "$CONFIG_USB" = "m" ]; then
         dep_tristate '  CPiA USB Lowlevel Support' CONFIG_VIDEO_CPIA_USB $CONFIG_VIDEO_CPIA $CONFIG_USB
       fi
     fi
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/Makefile linux.19p18/drivers/char/Makefile
--- linux.vanilla/drivers/char/Makefile	Mon Dec 11 22:12:40 2000
+++ linux.19p18/drivers/char/Makefile	Sat Mar 10 23:11:05 2001
@@ -200,7 +200,13 @@
   endif
 endif
 
-obj-$(CONFIG_SX) += sx.o generic_serial.o
+ifeq ($(CONFIG_SX),y)
+O_OBJS += sx.o generic_serial.o
+else
+  ifeq ($(CONFIG_SX),m)
+  M_OBJS += sx.o generic_serial.o
+  endif
+endif
 
 ifeq ($(CONFIG_RIO),y)
 O_OBJS += rio/rio.o generic_serial.o
@@ -295,6 +301,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_ADVANTECH_WDT),y)
+O_OBJS += advantechwdt.o
+else
+  ifeq ($(CONFIG_ADVANTECH_WDT),m)
+  M_OBJS += advantechwdt.o
+  endif
+endif
+
 ifeq ($(CONFIG_60XX_WDT),y)
 O_OBJS += sbc60xxwdt.o
 else
@@ -678,6 +692,14 @@
 else
   ifeq ($(CONFIG_TOSHIBA),m)
   M_OBJS += toshiba.o
+  endif
+endif
+
+ifeq ($(CONFIG_I810_TCO),y)
+O_OBJS += i810-tco.o
+else
+  ifeq ($(CONFIG_I810_TCO),m)
+  M_OBJS += i810-tco.o
   endif
 endif
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/advantechwdt.c linux.19p18/drivers/char/advantechwdt.c
--- linux.vanilla/drivers/char/advantechwdt.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/char/advantechwdt.c	Wed Dec 13 22:01:01 2000
@@ -0,0 +1,243 @@
+/*
+ *	Advantech Single Board Computer WDT driver for Linux 2.2.x
+ *
+ *	(c) Copyright 2000 Marek Michalkiewicz <marekm@linux.org.pl>
+ *
+ *	Based on acquirewdt.c which is based on wdt.c.
+ *	Original copyright messages:
+ *
+ *	(c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
+ *				http://www.redhat.com
+ *
+ *	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.
+ *	
+ *	Neither Alan Cox nor CymruNet Ltd. admit liability nor provide 
+ *	warranty for any of this software. This material is provided 
+ *	"AS-IS" and at no charge.	
+ *
+ *	(c) Copyright 1995    Alan Cox <alan@redhat.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+
+static int advwdt_is_open = 0;
+
+/*
+ *	You must set these - there is no sane way to probe for this board.
+ *
+ *	To enable or restart, write the timeout value in seconds (1 to 63)
+ *	to I/O port WDT_START.  To disable, read I/O port WDT_STOP.
+ *	Both are 0x443 for most boards (tested on a PCA-6276VE-00B1), but
+ *	check your manual (at least the PCA-6159 seems to be different -
+ *	the manual says WDT_STOP is 0x43, not 0x443).
+ *	(0x43 is also a write-only control register for the 8254 timer!)
+ *
+ *	TODO: module parameters to set the I/O port addresses and NOWAYOUT
+ *	option at load time.
+ */
+ 
+#define WDT_STOP 0x443
+#define WDT_START 0x443
+
+#define WD_TIMO 60		/* 1 minute */
+
+
+/*
+ *	Kernel methods.
+ */
+ 
+
+static void
+advwdt_ping(void)
+{
+	/* Write a watchdog value */
+	outb_p(WD_TIMO, WDT_START);
+}
+
+static ssize_t
+advwdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+{
+	/*  Can't seek (pwrite) on this device  */
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	if (count) {
+		advwdt_ping();
+		return 1;
+	}
+	return 0;
+}
+
+static ssize_t
+advwdt_read(struct file *file, char *buf, size_t count, loff_t *ppos)
+{
+	return -EINVAL;
+}
+
+static int
+advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	  unsigned long arg)
+{
+	static struct watchdog_info ident = {
+		WDIOF_KEEPALIVEPING, 1, "Advantech WDT"
+	};
+	
+	switch (cmd) {
+	case WDIOC_GETSUPPORT:
+	  if (copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident)))
+	    return -EFAULT;
+	  break;
+	  
+	case WDIOC_GETSTATUS:
+	  if (copy_to_user((int *)arg, &advwdt_is_open,  sizeof(int)))
+	    return -EFAULT;
+	  break;
+
+	case WDIOC_KEEPALIVE:
+	  advwdt_ping();
+	  break;
+
+	default:
+	  return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static int
+advwdt_open(struct inode *inode, struct file *file)
+{
+	switch (MINOR(inode->i_rdev)) {
+		case WATCHDOG_MINOR:
+			if (advwdt_is_open)
+				return -EBUSY;
+			MOD_INC_USE_COUNT;
+			/*
+			 *	Activate 
+			 */
+	 
+			advwdt_is_open = 1;
+			advwdt_ping();
+			return 0;
+		default:
+			return -ENODEV;
+	}
+}
+
+static int
+advwdt_close(struct inode *inode, struct file *file)
+{
+	if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) {
+#ifndef CONFIG_WATCHDOG_NOWAYOUT	
+		inb_p(WDT_STOP);
+#endif		
+		advwdt_is_open = 0;
+	}
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+/*
+ *	Notifier for system down
+ */
+
+static int
+advwdt_notify_sys(struct notifier_block *this, unsigned long code,
+	void *unused)
+{
+	if (code == SYS_DOWN || code == SYS_HALT) {
+		/* Turn the card off */
+		inb_p(WDT_STOP);
+	}
+	return NOTIFY_DONE;
+}
+ 
+/*
+ *	Kernel Interfaces
+ */
+ 
+ 
+static struct file_operations advwdt_fops = {
+	NULL,
+	advwdt_read,
+	advwdt_write,
+	NULL,		/* No Readdir */
+	NULL,		/* No Select */
+	advwdt_ioctl,
+	NULL,		/* No mmap */
+	advwdt_open,
+	NULL,		/* flush */
+	advwdt_close
+};
+
+static struct miscdevice advwdt_miscdev = {
+	WATCHDOG_MINOR,
+	"watchdog",
+	&advwdt_fops
+};
+
+
+/*
+ *	The WDT card needs to learn about soft shutdowns in order to
+ *	turn the timebomb registers off. 
+ */
+ 
+static struct notifier_block advwdt_notifier = {
+	advwdt_notify_sys,
+	NULL,
+	0
+};
+
+#ifdef MODULE
+
+#define advwdt_init init_module
+
+void
+cleanup_module(void)
+{
+	misc_deregister(&advwdt_miscdev);
+	unregister_reboot_notifier(&advwdt_notifier);
+#if WDT_START != WDT_STOP
+	release_region(WDT_STOP,1);
+#endif
+	release_region(WDT_START,1);
+}
+
+#endif
+
+int __init
+advwdt_init(void)
+{
+	printk("WDT driver for Advantech single board computer initialising.\n");
+
+	misc_register(&advwdt_miscdev);
+#if WDT_START != WDT_STOP
+	request_region(WDT_STOP, 1, "Advantech WDT");
+#endif
+	request_region(WDT_START, 1, "Advantech WDT");
+	register_reboot_notifier(&advwdt_notifier);
+	return 0;
+}
+
+/* end of advantechwdt.c */
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/agp/agp_backend.h linux.19p18/drivers/char/agp/agp_backend.h
--- linux.vanilla/drivers/char/agp/agp_backend.h	Mon Dec 11 22:12:40 2000
+++ linux.19p18/drivers/char/agp/agp_backend.h	Wed Dec 13 21:32:45 2000
@@ -45,6 +45,7 @@
 	INTEL_BX,
 	INTEL_GX,
 	INTEL_I810,
+	INTEL_I815,
 	INTEL_I840,
 	VIA_GENERIC,
 	VIA_VP3,
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/agp/agpgart_be.c linux.19p18/drivers/char/agp/agpgart_be.c
--- linux.vanilla/drivers/char/agp/agpgart_be.c	Mon Dec 11 22:12:40 2000
+++ linux.19p18/drivers/char/agp/agpgart_be.c	Wed Dec 13 21:32:45 2000
@@ -2026,6 +2026,13 @@
 		"Intel",
 		"440GX",
 		intel_generic_setup },
+	/* could we add support for PCI_DEVICE_ID_INTEL_815_1 too ? */
+	{ PCI_DEVICE_ID_INTEL_815_0,
+		PCI_VENDOR_ID_INTEL,
+		INTEL_I815,
+		"Intel",
+		"i815",
+		intel_generic_setup },
 	{ PCI_DEVICE_ID_INTEL_840_0,
 		PCI_VENDOR_ID_INTEL,
 		INTEL_I840,
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/console.c linux.19p18/drivers/char/console.c
--- linux.vanilla/drivers/char/console.c	Mon Dec 11 22:12:41 2000
+++ linux.19p18/drivers/char/console.c	Wed Dec 13 22:26:19 2000
@@ -2571,6 +2571,7 @@
 	console_blanked = 0;
 	if (console_blank_hook)
 		console_blank_hook(0);
+	set_palette(currcons);
 	if (sw->con_blank(vc_cons[currcons].d, 0))
 		/* Low-level driver cannot restore -> do it ourselves */
 		update_screen(fg_console);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/cpia.c linux.19p18/drivers/char/cpia.c
--- linux.vanilla/drivers/char/cpia.c	Mon Dec 11 22:12:41 2000
+++ linux.19p18/drivers/char/cpia.c	Sat Mar 10 23:21:27 2001
@@ -3211,7 +3211,7 @@
 		DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm.format, vm.frame,
 		    vm.width, vm.height);
 #endif
-		if (vm.frame<0||vm.frame>FRAME_NUM) {
+		if (vm.frame<0||vm.frame>=FRAME_NUM) {
 			retval = -EINVAL;
 			break;
 		}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/gamma_drv.c linux.19p18/drivers/char/drm/gamma_drv.c
--- linux.vanilla/drivers/char/drm/gamma_drv.c	Mon Dec 11 22:12:42 2000
+++ linux.19p18/drivers/char/drm/gamma_drv.c	Wed Dec 13 22:45:57 2000
@@ -35,11 +35,6 @@
 
 #include <linux/agp_backend.h>
 
-static void __attribute__((unused)) unused(void)
-{
-	agp_enable(0);
-}
-
 #ifndef PCI_DEVICE_ID_3DLABS_GAMMA
 #define PCI_DEVICE_ID_3DLABS_GAMMA 0x0008
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/i810_drv.c linux.19p18/drivers/char/drm/i810_drv.c
--- linux.vanilla/drivers/char/drm/i810_drv.c	Mon Dec 11 22:12:42 2000
+++ linux.19p18/drivers/char/drm/i810_drv.c	Wed Dec 13 22:46:11 2000
@@ -35,11 +35,6 @@
 
 #include <linux/agp_backend.h>
 
-static void __attribute__((unused)) unused(void)
-{
-	agp_enable(0);
-}
-
 #define I810_NAME	 "i810"
 #define I810_DESC	 "Intel I810"
 #define I810_DATE	 "20000719"
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/mga_drv.c linux.19p18/drivers/char/drm/mga_drv.c
--- linux.vanilla/drivers/char/drm/mga_drv.c	Mon Dec 11 22:12:42 2000
+++ linux.19p18/drivers/char/drm/mga_drv.c	Wed Dec 13 22:46:26 2000
@@ -36,11 +36,6 @@
 
 #include <linux/agp_backend.h>
 
-static void __attribute__((unused)) unused(void)
-{
-	agp_enable(0);
-}
-
 #define MGA_NAME	 "mga"
 #define MGA_DESC	 "Matrox G200/G400"
 #define MGA_DATE	 "20000910"
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/r128_drv.c linux.19p18/drivers/char/drm/r128_drv.c
--- linux.vanilla/drivers/char/drm/r128_drv.c	Mon Dec 11 22:12:42 2000
+++ linux.19p18/drivers/char/drm/r128_drv.c	Wed Dec 13 22:52:21 2000
@@ -35,11 +35,6 @@
 
 #include <linux/agp_backend.h>
 
-static void __attribute__((unused)) unused(void)
-{
-	agp_enable(0);
-}
-
 #define R128_NAME	 "r128"
 #define R128_DESC	 "ATI Rage 128"
 #define R128_DATE	 "20000719"
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/drm/tdfx_drv.c linux.19p18/drivers/char/drm/tdfx_drv.c
--- linux.vanilla/drivers/char/drm/tdfx_drv.c	Mon Dec 11 22:12:42 2000
+++ linux.19p18/drivers/char/drm/tdfx_drv.c	Wed Dec 13 22:45:41 2000
@@ -38,13 +38,6 @@
 #include <linux/agp_backend.h>
 #endif
 
-static void __attribute__((unused)) unused(void)
-{
-#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
-	agp_enable(0);
-#endif
-}
-
 #define TDFX_NAME	 "tdfx"
 #define TDFX_DESC	 "3dfx Banshee/Voodoo3+"
 #define TDFX_DATE	 "20000719"
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/i810-tco.c linux.19p18/drivers/char/i810-tco.c
--- linux.vanilla/drivers/char/i810-tco.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/char/i810-tco.c	Thu Dec 21 23:31:09 2000
@@ -0,0 +1,343 @@
+/*
+ *	i810-tco 0.02:	TCO timer driver for i810 chipsets
+ *
+ *	(c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights Reserved.
+ *				http://www.kernelconcepts.de
+ *
+ *	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.
+ *	
+ *	Neither kernel concepts nor Nils Faerber admit liability nor provide 
+ *	warranty for any of this software. This material is provided 
+ *	"AS-IS" and at no charge.	
+ *
+ *	(c) Copyright 2000	kernel concepts <nils@kernelconcepts.de>
+ *				developed for
+ *                              Jentro AG, Haar/Munich (Germany)
+ *
+ *	TCO timer driver for i810/i815 chipsets
+ *	based on softdog.c by Alan Cox <alan@redhat.com>
+ *
+ *	The TCO timer is implemented in the 82801AA (82801AB) chip,
+ *	see intel documentation from http://developer.intel.com,
+ *	order number 290655-003
+ *
+ *  20000710 Nils Faerber
+ *	Initial Version 0.01
+ *  20000728 Nils Faerber
+ *      0.02 Fix for SMI_EN->TCO_EN bit, some cleanups
+ */
+ 
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include "i810-tco.h"
+
+
+/* Just in case that the PCI vendor and device IDs are not yet defined */
+#ifndef PCI_DEVICE_ID_INTEL_82801AA_0
+#define PCI_DEVICE_ID_INTEL_82801AA_0	0x2410
+#endif
+
+/* Default expire timeout */
+#define TIMER_MARGIN	50	/* steps of 0.6sec, 2<n<64. Default is 30 seconds */
+
+static unsigned int ACPIBASE;
+static spinlock_t tco_lock;	/* Guards the hardware */
+
+static int i810_margin = TIMER_MARGIN;	/* steps of 0.6sec */
+
+MODULE_PARM (i810_margin, "i");
+
+/*
+ *	Timer active flag
+ */
+
+static int timer_alive;
+static int boot_status;
+
+/*
+ * Some i810 specific functions
+ */
+
+
+/*
+ * Start the timer countdown
+ */
+static int tco_timer_start (void)
+{
+	unsigned char val;
+
+	spin_lock(&tco_lock);
+	val = inb (TCO1_CNT + 1);
+	val &= 0xf7;
+	outb (val, TCO1_CNT + 1);
+	val = inb (TCO1_CNT + 1);
+	spin_unlock(&tco_lock);
+	
+	if (val & 0x08)
+		return -1;
+	return 0;
+}
+
+/*
+ * Stop the timer countdown
+ */
+static int tco_timer_stop (void)
+{
+	unsigned char val;
+
+	spin_lock(&tco_lock);
+	val = inb (TCO1_CNT + 1);
+	val |= 0x08;
+	outb (val, TCO1_CNT + 1);
+	val = inb (TCO1_CNT + 1);
+	spin_unlock(&tco_lock);
+	
+	if ((val & 0x08) == 0)
+		return -1;
+	return 0;
+}
+
+/*
+ * Set the timer reload value
+ */
+static int tco_timer_settimer (unsigned char tmrval)
+{
+	unsigned char val;
+
+	/* from the specs: */
+	/* "Values of 0h-3h are ignored and should not be attempted" */
+	if (tmrval > 0x3f || tmrval < 0x03)
+		return -1;
+	
+	spin_lock(&tco_lock);
+	val = inb (TCO1_TMR);
+	val &= 0xc0;
+	val |= tmrval;
+	outb (val, TCO1_TMR);
+	val = inb (TCO1_TMR);
+	spin_unlock(&tco_lock);
+	
+	if ((val & 0x3f) != tmrval)
+		return -1;
+
+	return 0;
+}
+
+/*
+ * Reload (trigger) the timer. Lock is needed so we dont reload it during
+ * a reprogramming event
+ */
+ 
+static void tco_timer_reload (void)
+{
+	spin_lock(&tco_lock);
+	outb (0x01, TCO1_RLD);
+	spin_unlock(&tco_lock);
+}
+
+/*
+ * Read the current timer value
+ */
+static unsigned char tco_timer_read (void)
+{
+	return (inb (TCO1_RLD));
+}
+
+
+/*
+ *	Allow only one person to hold it open
+ */
+
+static int i810tco_open (struct inode *inode, struct file *file)
+{
+	if (timer_alive)
+		return -EBUSY;
+
+	/*
+	 *      Reload and activate timer
+	 */
+	tco_timer_reload ();
+	tco_timer_start ();
+	timer_alive = 1;
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static int i810tco_release (struct inode *inode, struct file *file)
+{
+	/*
+	 *      Shut off the timer.
+	 */
+	MOD_INC_USE_COUNT;
+	tco_timer_stop ();
+	timer_alive = 0;
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static ssize_t i810tco_write (struct file *file, const char *data,
+			      size_t len, loff_t * ppos)
+{
+	/*  Can't seek (pwrite) on this device  */
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	/*
+	 *      Refresh the timer.
+	 */
+	if (len) {
+		tco_timer_reload ();
+		return 1;
+	}
+	return 0;
+}
+
+static int i810tco_ioctl (struct inode *inode, struct file *file,
+			  unsigned int cmd, unsigned long arg)
+{
+	static struct watchdog_info ident = {
+		0,
+		0,
+		"i810 TCO timer"
+	};
+	switch (cmd) {
+	default:
+		return -ENOIOCTLCMD;
+	case WDIOC_GETSUPPORT:
+		if (copy_to_user
+		    ((struct watchdog_info *) arg, &ident, sizeof (ident)))
+			return -EFAULT;
+		return 0;
+	case WDIOC_GETSTATUS:
+		return put_user (tco_timer_read (),
+				 (unsigned int *) (int) arg);
+	case WDIOC_GETBOOTSTATUS:
+		return put_user (boot_status, (int *) arg);
+	case WDIOC_KEEPALIVE:
+		tco_timer_reload ();
+		return 0;
+	}
+}
+
+static struct pci_dev *i810tco_pci;
+
+static unsigned char i810tco_getdevice (void)
+{
+	u8 val1, val2;
+	u16 badr;
+	/*
+	 *      Find the PCI device which has vendor id 0x8086
+	 *      and device ID 0x2410
+	 */
+	i810tco_pci = pci_find_device (PCI_VENDOR_ID_INTEL,
+				       PCI_DEVICE_ID_INTEL_82801AA_0, NULL);
+	if (i810tco_pci) {
+		/*
+		 *      Find the ACPI base I/O address which is the base
+		 *      for the TCO registers (TCOBASE=ACPIBASE + 0x60)
+		 *      ACPIBASE is bits [15:7] from 0x40-0x43
+		 */
+		pci_read_config_byte (i810tco_pci, 0x40, &val1);
+		pci_read_config_byte (i810tco_pci, 0x41, &val2);
+		badr = ((val2 << 1) | (val1 >> 7)) << 7;
+		ACPIBASE = badr;
+		/* Something's wrong here, ACPIBASE has to be set */
+		if (badr == 0x0001 || badr == 0x0000) {
+			printk (KERN_ERR "i810tco init: failed to get TCOBASE address\n");
+			return 0;
+		}
+		/*
+		 * Check chipset's NO_REBOOT bit
+		 */
+		pci_read_config_byte (i810tco_pci, 0xd4, &val1);
+		if (val1 & 0x02) {
+			val1 &= 0xfd;
+			pci_write_config_byte (i810tco_pci, 0xd4, val1);
+			pci_read_config_byte (i810tco_pci, 0xd4, &val1);
+			if (val1 & 0x02) {
+				printk (KERN_ERR "i810tco init: failed to reset NO_REBOOT flag\n");
+				return 0;	/* Cannot reset NO_REBOOT bit */
+			}
+		}
+		/* Set the TCO_EN bit in SMI_EN register */
+		val1 = inb (SMI_EN + 1);
+		val1 &= 0xdf;
+		outb (val1, SMI_EN + 1);
+		/* Clear out the (probably old) status */
+		outb (0, TCO1_STS);
+		boot_status = (int) inb (TCO2_STS);
+		outb (3, TCO2_STS);
+		return 1;
+	}
+	return 0;
+}
+
+static struct file_operations i810tco_fops = {
+	write:		i810tco_write,
+	ioctl:		i810tco_ioctl,
+	open:		i810tco_open,
+	release:	i810tco_release,
+};
+
+static struct miscdevice i810tco_miscdev = {
+	WATCHDOG_MINOR,
+	"watchdog",
+	&i810tco_fops
+};
+
+static int __init watchdog_init (void)
+{
+	spin_lock_init(&tco_lock);
+	if (!i810tco_getdevice () || i810tco_pci == NULL)
+		return -ENODEV;
+	if (!check_region (TCOBASE, 0x10)) {
+		printk (KERN_ERR
+			"i810 TCO timer: I/O address 0x%04x already in use\n",
+			TCOBASE);
+		return -EIO;
+	}
+	request_region (TCOBASE, 0x10, "i810 TCO");
+	if (misc_register (&i810tco_miscdev) != 0) {
+		release_region (TCOBASE, 0x10);
+		printk (KERN_ERR "i810 TCO timer: cannot register miscdev\n");
+		return -EIO;
+	}
+	tco_timer_settimer ((unsigned char) i810_margin);
+	tco_timer_reload ();
+
+	printk (KERN_INFO
+		"i810 TCO timer: V0.02, timer margin: %d sec (0x%04x)\n",
+		(int) (i810_margin * 6 / 10), TCOBASE);
+	return 0;
+}
+
+static void watchdog_cleanup (void)
+{
+	u8 val;
+
+	/* Reset the timer before we leave */
+	tco_timer_reload ();
+	/* Set the NO_REBOOT bit to prevent later reboots, just for sure */
+	pci_read_config_byte (i810tco_pci, 0xd4, &val);
+	val |= 0x02;
+	pci_write_config_byte (i810tco_pci, 0xd4, val);
+	release_region (TCOBASE, 0x10);
+	misc_deregister (&i810tco_miscdev);
+}
+
+module_init(watchdog_init);
+module_exit(watchdog_cleanup);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/i810-tco.h linux.19p18/drivers/char/i810-tco.h
--- linux.vanilla/drivers/char/i810-tco.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/char/i810-tco.h	Thu Dec 21 23:29:25 2000
@@ -0,0 +1,45 @@
+/*
+ *	i810-tco 0.02:	TCO timer driver for i810 chipsets
+ *
+ *	(c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights Reserved.
+ *				http://www.kernelconcepts.de
+ *
+ *	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.
+ *	
+ *	Neither kernel concepts nor Nils Faerber admit liability nor provide 
+ *	warranty for any of this software. This material is provided 
+ *	"AS-IS" and at no charge.	
+ *
+ *	(c) Copyright 2000	kernel concepts <nils@kernelconcepts.de>
+ *				developed for
+ *                              Jentro AG, Haar/Munich (Germany)
+ *
+ *	TCO timer driver for i810 chipsets
+ *	based on softdog.c by Alan Cox <alan@redhat.com>
+ *
+ *      The TCO timer is implemented in the 82801AA (82801AB) chip,
+ *	see intel documentation from http://developer.intel.com,
+ *	order number 290655-003
+ *
+ *	For history see i810-tco.c
+ */
+
+
+/*
+ * Some address definitions for the i810 TCO
+ */
+
+#define	TCOBASE		ACPIBASE + 0x60	/* TCO base address		*/
+#define TCO1_RLD	TCOBASE + 0x00	/* TCO Timer Reload and Current Value */
+#define TCO1_TMR	TCOBASE + 0x01	/* TCO Timer Initial Value	*/
+#define	TCO1_DAT_IN	TCOBASE + 0x02	/* TCO Data In Register		*/
+#define	TCO1_DAT_OUT	TCOBASE + 0x03	/* TCO Data Out Register	*/
+#define	TCO1_STS	TCOBASE + 0x04	/* TCO1 Status Register		*/
+#define	TCO2_STS	TCOBASE + 0x06	/* TCO2 Status Register		*/
+#define TCO1_CNT	TCOBASE + 0x08	/* TCO1 Control Register	*/
+#define TCO2_CNT	TCOBASE + 0x0a	/* TCO2 Control Register	*/
+
+#define	SMI_EN		ACPIBASE + 0x30	/* SMI Control and Enable Register */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/lp.c linux.19p18/drivers/char/lp.c
--- linux.vanilla/drivers/char/lp.c	Sun Jun 11 21:44:13 2000
+++ linux.19p18/drivers/char/lp.c	Tue Jan  9 11:58:01 2001
@@ -307,32 +307,11 @@
 		/*
 		 * NOTE: if you run with irqs you _must_ use
 		 * `tunelp /dev/lp? -c 1' to be rasonable efficient!
+		 *
+		 * ..but beware that data corruption can happen that way. -Tim
 		 */
 		if (++count == LP_CHAR(minor))
-		{
-			if (irq_ok)
-			{
-				static int first_time = 1;
-				/*
-				 * The printer is using a buggy handshake, so
-				 * revert to polling to not overload the
-				 * machine and warn the user that its printer
-				 * could get optimized trusting the irq. -arca
-				 */
-				lp_table[minor].irq_missed = 1;
-				if (first_time)
-				{
-					first_time = 0;
-					printk(KERN_WARNING "lp%d: the "
-					       "printing could be optimized "
-					       "using the TRUST_IRQ flag, "
-					       "see the top of "
-					       "linux/drivers/char/lp.c\n",
-					       minor);
-				}
-			}
 			return 0;
-		}
 	}
 
 	w_dtr(minor, lpchar);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/mem.c linux.19p18/drivers/char/mem.c
--- linux.vanilla/drivers/char/mem.c	Mon Dec 11 22:12:43 2000
+++ linux.19p18/drivers/char/mem.c	Sun Feb 25 23:13:50 2001
@@ -34,9 +34,6 @@
 #ifdef CONFIG_SPARCAUDIO
 extern int sparcaudio_init(void);
 #endif
-#ifdef CONFIG_ISDN
-int isdn_init(void);
-#endif
 #ifdef CONFIG_PHONE
 extern int telephony_init(void);
 #endif
@@ -646,9 +643,6 @@
 #endif	
 #if CONFIG_QIC02_TAPE
 	qic02_tape_init();
-#endif
-#if CONFIG_ISDN
-	isdn_init();
 #endif
 #ifdef CONFIG_FTAPE
 	ftape_init();
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/misc.c linux.19p18/drivers/char/misc.c
--- linux.vanilla/drivers/char/misc.c	Mon Dec 11 22:12:43 2000
+++ linux.19p18/drivers/char/misc.c	Sat Mar  3 22:43:20 2001
@@ -139,8 +139,17 @@
 
 int misc_register(struct miscdevice * misc)
 {
+	struct miscdevice *c;
+
 	if (misc->next || misc->prev)
 		return -EBUSY;
+	c = misc_list.next;
+
+	while ((c != &misc_list) && (c->minor != misc->minor))
+		c = c->next;
+	if (c != &misc_list)
+		return -EBUSY;
+
 	if (misc->minor == MISC_DYNAMIC_MINOR) {
 		int i = DYNAMIC_MINORS;
 		while (--i >= 0)
@@ -229,6 +238,9 @@
 #endif
 #ifdef CONFIG_ACQUIRE_WDT
 	acq_init();
+#endif
+#ifdef CONFIG_ADVANTECH_WDT
+	advwdt_init();
 #endif
 #ifdef CONFIG_60XX_WDT
 	sbc60xxwdt_init();
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/n_hdlc.c linux.19p18/drivers/char/n_hdlc.c
--- linux.vanilla/drivers/char/n_hdlc.c	Mon Dec 11 22:12:43 2000
+++ linux.19p18/drivers/char/n_hdlc.c	Tue Dec 19 02:09:06 2000
@@ -9,7 +9,7 @@
  *	Al Longyear <longyear@netcom.com>, Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
  *
  * Original release 01/11/99
- * ==FILEDATE 20000515==
+ * $Id: n_hdlc.c,v 2.2 2000/11/08 17:08:29 paul Exp $
  *
  * This code is released under the GNU General Public License (GPL)
  *
@@ -78,7 +78,7 @@
  */
 
 #define HDLC_MAGIC 0x239e
-#define HDLC_VERSION "1.15"
+#define HDLC_VERSION "2.2"
 
 #include <linux/version.h>
 #include <linux/config.h>
@@ -93,14 +93,7 @@
 #undef VERSION
 #define VERSION(major,minor,patch) (((((major)<<8)+(minor))<<8)+(patch))
 
-#if LINUX_VERSION_CODE < VERSION(2,1,14)
-#include <linux/ioport.h>
-#endif
-
-#if LINUX_VERSION_CODE >= VERSION(2,1,23)
 #include <linux/poll.h>
-#endif
-
 #include <linux/in.h>
 #include <linux/malloc.h>
 #include <linux/tty.h>
@@ -118,79 +111,23 @@
 #include <linux/kerneld.h>
 #endif
 
-#if LINUX_VERSION_CODE >= VERSION(2,1,4)
+#if LINUX_VERSION_CODE < VERSION(2,2,18) 
+typedef struct wait_queue *wait_queue_head_t;
+#define DECLARE_WAITQUEUE(name,task) struct wait_queue (name) = {(task),NULL}
+#define init_waitqueue_head(head) *(head) = NULL
+#define set_current_state(a) current->state = (a)
+#endif
+
 #include <asm/segment.h>
 #define GET_USER(error,value,addr) error = get_user(value,addr)
 #define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0
 #define PUT_USER(error,value,addr) error = put_user(value,addr)
 #define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0
 
-#if LINUX_VERSION_CODE >= VERSION(2,1,5)
 #include <asm/uaccess.h>
-#endif
-
-#else  /* 2.0.x and 2.1.x before 2.1.4 */
-
-#define GET_USER(error,value,addr)					  \
-do {									  \
-	error = verify_area (VERIFY_READ, (void *) addr, sizeof (value)); \
-	if (error == 0)							  \
-		value = get_user(addr);					  \
-} while (0)
-
-#define COPY_FROM_USER(error,dest,src,size)				  \
-do {									  \
-	error = verify_area (VERIFY_READ, (void *) src, size);		  \
-	if (error == 0)							  \
-		memcpy_fromfs (dest, src, size);			  \
-} while (0)
-
-#define PUT_USER(error,value,addr)					   \
-do {									   \
-	error = verify_area (VERIFY_WRITE, (void *) addr, sizeof (value)); \
-	if (error == 0)							   \
-		put_user (value, addr);					   \
-} while (0)
-
-#define COPY_TO_USER(error,dest,src,size)				  \
-do {									  \
-	error = verify_area (VERIFY_WRITE, (void *) dest, size);		  \
-	if (error == 0)							  \
-		memcpy_tofs (dest, src, size);				  \
-} while (0)
 
-#endif
-
-#if LINUX_VERSION_CODE < VERSION(2,1,0)
-#define __init
-typedef int spinlock_t;
-#define spin_lock_init(a)
-#define spin_lock_irqsave(a,b) {save_flags((b));cli();}
-#define spin_unlock_irqrestore(a,b) {restore_flags((b));}
-#define spin_lock(a)
-#define spin_unlock(a)
-#define schedule_timeout(a){current->timeout = jiffies + (a); schedule();}
-#endif
-
-#if LINUX_VERSION_CODE < VERSION(2,1,37)
-#define test_and_set_bit(nr, addr)	set_bit(nr, addr)
-#endif
-
-#if LINUX_VERSION_CODE < VERSION(2,1,57)
-#define signal_pending(p)	((p)->signal & ~(p)->blocked)
-#endif
-
-#if LINUX_VERSION_CODE < VERSION(2,1,25)
-#define net_device_stats	enet_statistics
-#endif
-
-#if LINUX_VERSION_CODE < VERSION(2,1,60)
-typedef int		rw_ret_t;
-typedef unsigned int	rw_count_t;
-#else
 typedef ssize_t		rw_ret_t;
 typedef size_t		rw_count_t;
-#endif
 
 /*
  * Buffers for individual HDLC frames
@@ -254,10 +191,8 @@
 
 static struct n_hdlc *n_hdlc_alloc (void);
 
-#if LINUX_VERSION_CODE >= VERSION(2,1,19) 
 MODULE_PARM(debuglevel, "i");
 MODULE_PARM(maxframe, "i");
-#endif
 
 /* debug level can be set by insmod for debugging purposes */
 #define DEBUG_LEVEL_INFO	1
@@ -274,13 +209,8 @@
 	struct file *, const __u8 *, rw_count_t);
 static int n_hdlc_tty_ioctl(struct tty_struct *,
 	struct file *, unsigned int, unsigned long);
-#if LINUX_VERSION_CODE < VERSION(2,1,23)
-static int n_hdlc_tty_select (struct tty_struct *tty, struct inode *inode,
-		      struct file *filp, int sel_type, select_table * wait);
-#else
 static unsigned int n_hdlc_tty_poll (struct tty_struct *tty, struct file *filp,
 				  poll_table * wait);
-#endif
 static int n_hdlc_tty_open (struct tty_struct *);
 static void n_hdlc_tty_close (struct tty_struct *);
 static int n_hdlc_tty_room (struct tty_struct *tty);
@@ -653,10 +583,10 @@
 	wake_up_interruptible (&n_hdlc->read_wait);
 	wake_up_interruptible (&n_hdlc->poll_wait);
 	if (n_hdlc->tty->fasync != NULL)
-#if LINUX_VERSION_CODE < VERSION(2,3,0) 
-		kill_fasync (n_hdlc->tty->fasync, SIGIO);
-#else
+#if LINUX_VERSION_CODE >= VERSION(2,2,14) && defined(__rh_config_h__)
 		kill_fasync (n_hdlc->tty->fasync, SIGIO, POLL_IN);
+#else
+		kill_fasync (n_hdlc->tty->fasync, SIGIO);
 #endif
 }	/* end of n_hdlc_tty_receive() */
 
@@ -886,73 +816,6 @@
 	
 }	/* end of n_hdlc_tty_ioctl() */
 
-#if LINUX_VERSION_CODE < VERSION(2,1,23)
-/* n_hdlc_tty_select()
- * 
- * 	Device select method. Determine if operation requires
- * 	blocking and if so put appropriate wait queue in select
- * 	table and return 0, otherwise return 1.
- * 	
- * Arguments:
- * 
- * 	tty		pointer to tty device instance data
- * 	inode		pointer to inode for device
- * 	filp		pointer to file object
- * 	sel_type	identified the select type (read/write/exception)
- * 	wait		select table for adding wait queue if appropriate
- * 	
- * Return Value:
- * 
- * 	1 if no need to block on operation
- * 	0 if must block and wait queue added to select table
- */
-static int n_hdlc_tty_select (struct tty_struct *tty, struct inode *inode,
-		struct file *filp, int sel_type, select_table * wait)
-{
-	struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
-	int result = 1;
-	
-	if (debuglevel >= DEBUG_LEVEL_INFO)	
-		printk("%s(%d)n_hdlc_tty_select() called\n",__FILE__,__LINE__);
-		
-	/* Verify the status of the device */
-	if (!n_hdlc)
-		return -EBADF;
-
-	if (n_hdlc->magic != HDLC_MAGIC || tty != n_hdlc->tty)
-		return -EBADF;
-
-	switch (sel_type) {
-	case SEL_IN:
-		if (n_hdlc->rx_buf_list.head)
-			break;
-
-	case SEL_EX:	/* Exceptions or read errors */
-		/* Is this a pty link and the remote disconnected? */
-		if (tty->flags & (1 << TTY_OTHER_CLOSED))
-			break;
-
-		/* Is this a local link and the modem disconnected? */
-		if (tty_hung_up_p (filp))
-			break;
-
-		select_wait (&n_hdlc->read_wait, wait);
-		result = 0;
-		break;
-		
-	/* Write mode. A write is allowed if there is no current transmission */
-	case SEL_OUT:
-		if (!n_hdlc->tx_free_buf_list.head) {
-			select_wait (&n_hdlc->write_wait, wait);
-			result = 0;
-		}
-		break;
-	}
-	return result;
-}	/* end of n_hdlc_tty_select() */
-
-#else	/* 2.1.23 or later */
-
 /* n_hdlc_tty_poll()
  * 
  * 	TTY callback for poll system call. Determine which 
@@ -981,11 +844,8 @@
 	if (n_hdlc && n_hdlc->magic == HDLC_MAGIC && tty == n_hdlc->tty) {
 		/* queue current process into any wait queue that */
 		/* may awaken in the future (read and write) */
-#if LINUX_VERSION_CODE < VERSION(2,1,89)
-		poll_wait(&n_hdlc->poll_wait, wait);
-#else
 		poll_wait(filp, &n_hdlc->poll_wait, wait);
-#endif
+
 		/* set bits for operations that wont block */
 		if(n_hdlc->rx_buf_list.head)
 			mask |= POLLIN | POLLRDNORM;	/* readable */
@@ -999,8 +859,6 @@
 	return mask;
 }	/* end of n_hdlc_tty_poll() */
 
-#endif
-
 /* n_hdlc_alloc()
  * 
  * 	Allocate an n_hdlc instance data structure
@@ -1153,19 +1011,13 @@
 	
 	memset(&n_hdlc_ldisc, 0, sizeof (n_hdlc_ldisc));
 	n_hdlc_ldisc.magic		= TTY_LDISC_MAGIC;
-#if LINUX_VERSION_CODE >= VERSION(2,1,28)
 	n_hdlc_ldisc.name          	= "hdlc";
-#endif
 	n_hdlc_ldisc.open		= n_hdlc_tty_open;
 	n_hdlc_ldisc.close		= n_hdlc_tty_close;
 	n_hdlc_ldisc.read		= n_hdlc_tty_read;
 	n_hdlc_ldisc.write		= n_hdlc_tty_write;
 	n_hdlc_ldisc.ioctl		= n_hdlc_tty_ioctl;
-#if LINUX_VERSION_CODE < VERSION(2,1,23)
-	n_hdlc_ldisc.select		= n_hdlc_tty_select;
-#else
 	n_hdlc_ldisc.poll		= n_hdlc_tty_poll;
-#endif
 	n_hdlc_ldisc.receive_room	= n_hdlc_tty_room;
 	n_hdlc_ldisc.receive_buf	= n_hdlc_tty_receive;
 	n_hdlc_ldisc.write_wakeup	= n_hdlc_tty_wakeup;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/serial.c linux.19p18/drivers/char/serial.c
--- linux.vanilla/drivers/char/serial.c	Sun Jun 11 21:44:13 2000
+++ linux.19p18/drivers/char/serial.c	Thu Feb 15 16:12:00 2001
@@ -150,6 +150,12 @@
 #include <asm/bitops.h>
 #include <asm/serial.h>
 
+#ifdef CONFIG_MAC_SERIAL
+#define SERIAL_DEV_OFFSET	4
+#else
+#define SERIAL_DEV_OFFSET	0
+#endif
+
 #ifdef SERIAL_INLINE
 #define _INLINE_ inline
 #endif
@@ -3130,7 +3136,7 @@
 	serial_driver.driver_name = "serial";
 	serial_driver.name = "ttyS";
 	serial_driver.major = TTY_MAJOR;
-	serial_driver.minor_start = 64;
+	serial_driver.minor_start = 64 + SERIAL_DEV_OFFSET;
 	serial_driver.num = NR_PORTS;
 	serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
 	serial_driver.subtype = SERIAL_TYPE_NORMAL;
@@ -3194,11 +3200,22 @@
 		state->icount.frame = state->icount.parity = 0;
 		state->icount.overrun = state->icount.brk = 0;
 		state->irq = irq_cannonicalize(state->irq);
-		if (check_region(state->port,8))
-			continue;
-		if (state->flags & ASYNC_BOOT_AUTOCONF)
-			autoconfig(state);
+#ifdef CONFIG_PPC
+		/* PowerMacs don't have legacy serial ports on IOs and would machine check */
+		if (_machine != _MACH_Pmac) {
+#endif		
+			if (check_region(state->port,8))
+				continue;
+			if (state->flags & ASYNC_BOOT_AUTOCONF)
+				autoconfig(state);
+#ifdef CONFIG_PPC
+		}
+#endif		
 	}
+#ifdef CONFIG_PPC
+	if (_machine == _MACH_Pmac)
+		return 0;
+#endif
 	/*
 	 * Detect the IRQ only once every port is initialised,
 	 * because some 16450 do not reset to 0 the MCR register.
@@ -3268,22 +3285,22 @@
 		state->irq = detect_uart_irq(state);
 
 	printk(KERN_INFO "tty%02d at 0x%04x (irq = %d) is a %s\n",
-	       state->line, state->port, state->irq,
+	       state->line + SERIAL_DEV_OFFSET, state->port, state->irq,
 	       uart_config[state->type].name);
-	return state->line;
+	return state->line + SERIAL_DEV_OFFSET;
 }
 
 void unregister_serial(int line)
 {
 	unsigned long flags;
-	struct serial_state *state = &rs_table[line];
+	struct serial_state *state = &rs_table[line + SERIAL_DEV_OFFSET];
 
 	save_flags(flags);
 	cli();
 	if (state->info && state->info->tty)
 		tty_hangup(state->info->tty);
 	state->type = PORT_UNKNOWN;
-	printk(KERN_INFO "tty%02d unloaded\n", state->line);
+	printk(KERN_INFO "tty%02d unloaded\n", state->line + SERIAL_DEV_OFFSET);
 	restore_flags(flags);
 }
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/sx.c linux.19p18/drivers/char/sx.c
--- linux.vanilla/drivers/char/sx.c	Mon Dec 11 22:12:45 2000
+++ linux.19p18/drivers/char/sx.c	Sat Mar 10 23:11:05 2001
@@ -1799,6 +1799,20 @@
 }
 
 
+static void sx_break (struct tty_struct * tty, int flag)
+{
+	struct sx_port *port = tty->driver_data;
+	int rv;
+
+	if (flag) 
+		rv = sx_send_command (port, HS_START, -1, HS_IDLE_BREAK);
+	else 
+		rv = sx_send_command (port, HS_STOP, -1, HS_IDLE_OPEN);
+	if (rv != 1) printk (KERN_ERR "sx: couldn't send break (%x).\n",
+			read_sx_byte (port->board, CHAN_OFFSET (port, hi_hstat)));
+}
+
+
 static int sx_ioctl (struct tty_struct * tty, struct file * filp, 
                      unsigned int cmd, unsigned long arg)
 {
@@ -1867,7 +1881,6 @@
 			sx_reconfigure_port(port);
 		}
 		break;
-
 	default:
 		rc = -ENOIOCTLCMD;
 		break;
@@ -2247,6 +2260,7 @@
 	sx_driver.table = sx_table;
 	sx_driver.termios = sx_termios;
 	sx_driver.termios_locked = sx_termios_locked;
+	sx_driver.break_ctl = sx_break;
 
 	sx_driver.open	= sx_open;
 	sx_driver.close = gs_close;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/char/synclink.c linux.19p18/drivers/char/synclink.c
--- linux.vanilla/drivers/char/synclink.c	Mon Dec 11 22:12:45 2000
+++ linux.19p18/drivers/char/synclink.c	Tue Dec 19 02:09:21 2000
@@ -1,7 +1,7 @@
 /*
  * linux/drivers/char/synclink.c
  *
- * ==FILEDATE 20000821==
+ * $Id: synclink.c,v 2.4 2000/12/11 20:08:18 paul Exp $
  *
  * Device driver for Microgate SyncLink ISA and PCI
  * high speed multiprotocol serial adapters.
@@ -79,17 +79,10 @@
 #include <linux/ioport.h>
 #include <linux/mm.h>
 #include <linux/malloc.h>
-
 #include <linux/netdevice.h>
-
-#if LINUX_VERSION_CODE >= VERSION(2,1,0) 
 #include <linux/vmalloc.h>
 #include <linux/init.h>
 #include <asm/serial.h>
-#else
-#include <linux/bios32.h>
-#endif
-
 #include <linux/delay.h>
 #include <linux/ioctl.h>
 
@@ -102,90 +95,34 @@
 #include <linux/termios.h>
 #include <linux/tqueue.h>
 
+#if LINUX_VERSION_CODE < VERSION(2,2,18) 
+typedef struct wait_queue *wait_queue_head_t;
+#define DECLARE_WAITQUEUE(name,task) struct wait_queue (name) = {(task),NULL}
+#define init_waitqueue_head(head) *(head) = NULL
+#define DECLARE_MUTEX(name) struct semaphore (name) = MUTEX
+#define set_current_state(a) current->state = (a)
+#endif
+
 #ifdef CONFIG_SYNCLINK_SYNCPPP_MODULE
 #define CONFIG_SYNCLINK_SYNCPPP 1
 #endif
 
 #ifdef CONFIG_SYNCLINK_SYNCPPP
-#if LINUX_VERSION_CODE < VERSION(2,3,43) 
 #include "../net/syncppp.h"
 #define net_device device
 #define netif_stop_queue(a) (a)->tbusy = 1
 #define netif_start_queue(a) (a)->tbusy = 0
 #define netif_wake_queue(a) (a)->tbusy = 0; mark_bh(NET_BH)
 #define netif_queue_stopped(a) ((a)->tbusy)
-#else
-#include "../net/wan/syncppp.h"
-#endif
 #endif
 
-#if LINUX_VERSION_CODE >= VERSION(2,1,4)
 #include <asm/segment.h>
 #define GET_USER(error,value,addr) error = get_user(value,addr)
 #define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0
 #define PUT_USER(error,value,addr) error = put_user(value,addr)
 #define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0
 
-#if LINUX_VERSION_CODE >= VERSION(2,1,5)
 #include <asm/uaccess.h>
-#endif
-
-#else  /* 2.0.x and 2.1.x before 2.1.4 */
-
-#define GET_USER(error,value,addr)					  \
-do {									  \
-	error = verify_area (VERIFY_READ, (void *) addr, sizeof (value)); \
-	if (error == 0)							  \
-		value = get_user(addr);					  \
-} while (0)
-
-#define COPY_FROM_USER(error,dest,src,size)				  \
-do {									  \
-	error = verify_area (VERIFY_READ, (void *) src, size);		  \
-	if (error == 0)							  \
-		memcpy_fromfs (dest, src, size);			  \
-} while (0)
-
-#define PUT_USER(error,value,addr)					   \
-do {									   \
-	error = verify_area (VERIFY_WRITE, (void *) addr, sizeof (value)); \
-	if (error == 0)							   \
-		put_user (value, addr);					   \
-} while (0)
-
-#define COPY_TO_USER(error,dest,src,size)				  \
-do {									  \
-	error = verify_area (VERIFY_WRITE, (void *) dest, size);		  \
-	if (error == 0)							  \
-		memcpy_tofs (dest, src, size);				  \
-} while (0)
-
-#endif
-
-#if LINUX_VERSION_CODE < VERSION(2,1,0)
-/*
- * This is used to figure out the divisor speeds and the timeouts
- */
-static int baud_table[] = {
-	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
-	9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 };
-
-#define __init
-#define ioremap(a,b) vremap((a),(b))
-#define iounmap(a) vfree((a))
-#define SERIAL_TYPE_NORMAL	1
-#define SERIAL_TYPE_CALLOUT	2
-typedef int spinlock_t;
-#define spin_lock_init(a)
-#define spin_lock_irqsave(a,b) {save_flags((b));cli();}
-#define spin_unlock_irqrestore(a,b) {restore_flags((b));}
-#define spin_lock(a)
-#define spin_unlock(a)
-#define schedule_timeout(a){current->timeout = jiffies + (a); schedule();}
-#define signal_pending(a) ((a)->signal & ~(a)->blocked)
-#endif
-
-
 
 #include "linux/synclink.h"
 
@@ -944,7 +881,6 @@
 static int maxframe[MAX_TOTAL_DEVICES] = {0,};
 static int dosyncppp[MAX_TOTAL_DEVICES] = {0,};
 	
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
 MODULE_PARM(break_on_load,"i");
 MODULE_PARM(ttymajor,"i");
 MODULE_PARM(cuamajor,"i");
@@ -954,10 +890,9 @@
 MODULE_PARM(debug_level,"i");
 MODULE_PARM(maxframe,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i");
 MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i");
-#endif
 
 static char *driver_name = "SyncLink serial driver";
-static char *driver_version = "1.22";
+static char *driver_version = "2.3";
 
 static struct tty_driver serial_driver, callout_driver;
 static int serial_refcount;
@@ -969,9 +904,9 @@
 static void mgsl_change_params(struct mgsl_struct *info);
 static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout);
 
-static struct tty_struct **serial_table = NULL;
-static struct termios **serial_termios = NULL;
-static struct termios **serial_termios_locked = NULL;
+static struct tty_struct *serial_table[MAX_TOTAL_DEVICES];
+static struct termios *serial_termios[MAX_TOTAL_DEVICES];
+static struct termios *serial_termios_locked[MAX_TOTAL_DEVICES];
 
 #ifndef MIN
 #define MIN(a,b)	((a) < (b) ? (a) : (b))
@@ -1372,11 +1307,6 @@
 #endif
 			} else
 				info->input_signal_events.dcd_down++;
-#ifdef CONFIG_HARD_PPS
-			if ((info->flags & ASYNC_HARDPPS_CD) &&
-			    (status & MISCSTATUS_DCD_LATCHED))
-				hardpps();
-#endif
 		}
 		if (status & MISCSTATUS_CTS_LATCHED)
 		{
@@ -1583,14 +1513,8 @@
 			icount->parity,icount->frame,icount->overrun);
 	}
 			
-	if ( tty->flip.count ) {
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
+	if ( tty->flip.count )
 		tty_flip_buffer_push(tty);
-#else		
-		queue_task(&tty->flip.tqueue, &tq_timer); 
-#endif		
-	}
-	
 
 }	/* end of mgsl_isr_receive_data() */
 
@@ -1787,11 +1711,7 @@
 		retval = mgsl_adapter_test(info);
 		
 	if ( retval ) {
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
   		if (capable(CAP_SYS_ADMIN) && info->tty)
-#else
-  		if (suser() && info->tty)
-#endif		
 			set_bit(TTY_IO_ERROR, &info->tty->flags);
 		mgsl_release_resources(info);
   		return retval;
@@ -1967,19 +1887,7 @@
 	 * current data rate.
 	 */
 	if (info->params.data_rate <= 460800) {
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
 		info->params.data_rate = tty_get_baud_rate(info->tty);
-#else
-		int i = cflag & CBAUD;
-		if (i & CBAUDEX) {
-			i &= ~CBAUDEX;
-			if (i < 1 || i > 4) 
-				info->tty->termios->c_cflag &= ~CBAUDEX;
-			else
-				i += 15;
-		}
-		info->params.data_rate = baud_table[i];
-#endif	
 	}
 	
 	if ( info->params.data_rate ) {
@@ -2942,7 +2850,6 @@
 	
 }	/* end of set_modem_info() */
 
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
 /* mgsl_break()		Set or clear transmit break condition
  *
  * Arguments:		tty		pointer to tty instance data
@@ -2969,7 +2876,6 @@
 	spin_unlock_irqrestore(&info->irq_spinlock,flags);
 	
 }	/* end of mgsl_break() */
-#endif
 
 /* mgsl_ioctl()	Service an IOCTL request
  * 	
@@ -3092,7 +2998,6 @@
 			if (error) return error;
 			PUT_USER(error,cnow.dcd, &p_cuser->dcd);
 			if (error) return error;
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
 			PUT_USER(error,cnow.rx, &p_cuser->rx);
 			if (error) return error;
 			PUT_USER(error,cnow.tx, &p_cuser->tx);
@@ -3107,7 +3012,6 @@
 			if (error) return error;
 			PUT_USER(error,cnow.buf_overrun, &p_cuser->buf_overrun);
 			if (error) return error;
-#endif			
 			return 0;
 		default:
 			return -ENOIOCTLCMD;
@@ -3346,7 +3250,6 @@
 		}
 	}
       
-	set_current_state(TASK_RUNNING);
 exit:
 	if (debug_level >= DEBUG_LEVEL_INFO)
 		printk("%s(%d):mgsl_wait_until_sent(%s) exit\n",
@@ -3589,9 +3492,7 @@
 			tmp_buf = (unsigned char *) page;
 	}
 	
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
 	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
-#endif
 
 	spin_lock_irqsave(&info->netlock, flags);
 	if (info->netcount) {
@@ -3978,27 +3879,19 @@
 
 }	/* end of mgsl_alloc_buffer_list_memory() */
 
-/*
- * mgsl_free_buffer_list_memory()
- * 
- * 	Free the common DMA buffer allocated for use as the
- * 	receive and transmit buffer lists. The associated Memory
- * 	Descriptor List (MDL) is also freed.
- * 
+/* Free DMA buffers allocated for use as the
+ * receive and transmit buffer lists.
  * Warning:
  * 
  * 	The data transfer buffers associated with the buffer list
  * 	MUST be freed before freeing the buffer list itself because
  * 	the buffer list contains the information necessary to free
  * 	the individual buffers!
- * 
- * Arguments:		info	pointer to device extension
- * Return Value:	None
  */
 void mgsl_free_buffer_list_memory( struct mgsl_struct *info )
 {
 	if ( info->buffer_list && info->bus_type != MGSL_BUS_TYPE_PCI )
-		kfree_s(info->buffer_list, BUFFERLISTSIZE);
+		kfree(info->buffer_list);
 		
 	info->buffer_list = NULL;
 	info->rx_buffer_list = NULL;
@@ -4072,7 +3965,7 @@
 		for ( i = 0 ; i < Buffercount ; i++ ) {
 			if ( BufferList[i].virt_addr ) {
 				if ( info->bus_type != MGSL_BUS_TYPE_PCI )
-					kfree_s(BufferList[i].virt_addr, DMABUFFERSIZE);
+					kfree(BufferList[i].virt_addr);
 				BufferList[i].virt_addr = NULL;
 			}
 		}
@@ -4131,19 +4024,12 @@
 void mgsl_free_intermediate_rxbuffer_memory(struct mgsl_struct *info)
 {
 	if ( info->intermediate_rxbuffer )
-		kfree_s( info->intermediate_rxbuffer, info->max_frame_size);
+		kfree(info->intermediate_rxbuffer);
 
 	info->intermediate_rxbuffer = NULL;
 
 }	/* end of mgsl_free_intermediate_rxbuffer_memory() */
 
-/* mgsl_claim_resources()
- * 
- * 	Claim all resources used by a device
- * 	
- * Arguments:		info	pointer to device instance data
- * Return Value:	0 if success, otherwise -ENODEV
- */
 int mgsl_claim_resources(struct mgsl_struct *info)
 {
 	/* claim 16C32 I/O base address */
@@ -4168,7 +4054,7 @@
 	info->irq_requested = 1;
 	
 	if ( info->bus_type == MGSL_BUS_TYPE_PCI ) {
-		/* claim shared memory range */
+
 		info->memory_base = ioremap(info->phys_memory_base,0x40000);
 		if (!info->memory_base) {
 			printk( "%s(%d):Cant map shared memory on device %s MemAddr=%08X\n",
@@ -4177,7 +4063,6 @@
 			return -ENODEV;
 		}
 		
-		/* test the shared memory range */
 		if ( !mgsl_memory_test(info) ) {
 			printk( "%s(%d):Failed shared memory test %s MemAddr=%08X\n",
 				__FILE__,__LINE__,info->device_name, info->phys_memory_base );
@@ -4185,7 +4070,6 @@
 			return -ENODEV;
 		}
 		
-		/* claim LCR memory range */
 		info->lcr_base = ioremap(info->phys_lcr_base,PAGE_SIZE) + info->lcr_offset;
 		if (!info->lcr_base) {
 			printk( "%s(%d):Cant map LCR memory on device %s MemAddr=%08X\n",
@@ -4221,13 +4105,6 @@
 		
 }	/* end of mgsl_claim_resources() */
 
-/* mgsl_release_resources()
- * 
- * 	Release all resources used by a device
- * 	
- * Arguments:		info	pointer to device instance data
- * Return Value:	None
- */
 void mgsl_release_resources(struct mgsl_struct *info)
 {
 	if ( debug_level >= DEBUG_LEVEL_INFO )
@@ -4380,9 +4257,7 @@
 			printk("ISA device specified io=%04X,irq=%d,dma=%d\n",
 				io[i], irq[i], dma[i] );
 		
-		info = mgsl_allocate_device();
-		if ( !info ) {
-			/* error allocating device instance data */
+		if (!(info = mgsl_allocate_device())) {
 			if ( debug_level >= DEBUG_LEVEL_ERROR )
 				printk( "can't allocate device instance data.\n");
 			continue;
@@ -4391,12 +4266,7 @@
 		/* Copy user configuration info to device instance data */
 		info->io_base = (unsigned int)io[i];
 		info->irq_level = (unsigned int)irq[i];
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
 		info->irq_level = irq_cannonicalize(info->irq_level);
-#else		
-		if (info->irq_level == 2)
-			info->irq_level = 9;
-#endif			
 		info->dma_level = (unsigned int)dma[i];
 		info->bus_type = MGSL_BUS_TYPE_ISA;
 		info->io_addr_size = 16;
@@ -4412,73 +4282,29 @@
 	if ( pcibios_present() ) {
 		unsigned char bus;
 		unsigned char func;
-		unsigned int  shared_mem_base;
-		unsigned int  lcr_mem_base;
-		unsigned int  io_base;
-		unsigned char irq_line;
 		
 		for(i=0;;i++){
 			if ( PCIBIOS_SUCCESSFUL == pcibios_find_device(
 				MICROGATE_VENDOR_ID, SYNCLINK_DEVICE_ID, i, &bus, &func) ) {
 				
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
 				struct pci_dev *pdev = pci_find_slot(bus,func);
-				irq_line = pdev->irq;				
-#else												
-				if (pcibios_read_config_byte(bus,func,
-					PCI_INTERRUPT_LINE,&irq_line) ) {
-					printk( "%s(%d):USC I/O addr not set.\n",
-						__FILE__,__LINE__);
-					continue;
-				}
-#endif
-
-				if (pcibios_read_config_dword(bus,func,
-					PCI_BASE_ADDRESS_3,&shared_mem_base) ) {
-					printk( "%s(%d):Shared mem addr not set.\n",
-						__FILE__,__LINE__);
-					continue;
-				}
-							
-				if (pcibios_read_config_dword(bus,func,
-					PCI_BASE_ADDRESS_0,&lcr_mem_base) ) {
-					printk( "%s(%d):LCR mem addr not set.\n",
-						__FILE__,__LINE__);
-					continue;
-				}
 				
-				if (pcibios_read_config_dword(bus,func,
-					PCI_BASE_ADDRESS_2,&io_base) ) {
-					printk( "%s(%d):USC I/O addr not set.\n",
-						__FILE__,__LINE__);
-					continue;
-				}
-				
-				info = mgsl_allocate_device();
-				if ( !info ) {
-					/* error allocating device instance data */
+				if (!(info = mgsl_allocate_device())) {
 					if ( debug_level >= DEBUG_LEVEL_ERROR )
 						printk( "can't allocate device instance data.\n");
 					continue;
 				}
 		
 				/* Copy user configuration info to device instance data */
+				info->irq_level = pdev->irq;				
+				info->phys_lcr_base = pdev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK;
+				info->io_base = pdev->base_address[2] & PCI_BASE_ADDRESS_IO_MASK;
+				info->phys_memory_base = pdev->base_address[3] & PCI_BASE_ADDRESS_MEM_MASK;
 		
-				info->io_base = io_base & PCI_BASE_ADDRESS_IO_MASK;
-				info->irq_level = (unsigned int)irq_line;
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
-				info->irq_level = irq_cannonicalize(info->irq_level);
-#else		
-				if (info->irq_level == 2)
-					info->irq_level = 9;
-#endif			
-				info->phys_memory_base = shared_mem_base & PCI_BASE_ADDRESS_MEM_MASK;
-				
 				/* Because veremap only works on page boundaries we must map
 				 * a larger area than is actually implemented for the LCR
 				 * memory range. We map a full page starting at the page boundary.
 				 */
-				info->phys_lcr_base = lcr_mem_base & PCI_BASE_ADDRESS_MEM_MASK;
 				info->lcr_offset    = info->phys_lcr_base & (PAGE_SIZE-1);
 				info->phys_lcr_base &= ~(PAGE_SIZE-1);
 				
@@ -4508,30 +4334,9 @@
 	}
 #endif
 
-	/*
-	 * Allocate memory to hold the following tty/termios arrays
-	 * with an element for each enumerated device.
-	 */	
-	
-	serial_table = (struct tty_struct**)kmalloc(sizeof(struct tty_struct*)*mgsl_device_count, GFP_KERNEL);
-	serial_termios = (struct termios**)kmalloc(sizeof(struct termios*)*mgsl_device_count, GFP_KERNEL);
-	serial_termios_locked = (struct termios**)kmalloc(sizeof(struct termios*)*mgsl_device_count, GFP_KERNEL);
-	
-	if (!serial_table || !serial_termios || !serial_termios_locked){
-		printk("%s(%d):Can't allocate tty/termios arrays.\n",
-			__FILE__,__LINE__);
-		if (serial_table)
-			kfree(serial_table);
-		if (serial_termios)
-			kfree(serial_termios);
-		if (serial_termios_locked)
-			kfree(serial_termios_locked);
-		return -ENOMEM;
-	}
-	
-	memset(serial_table,0,sizeof(struct tty_struct*)*mgsl_device_count);
-	memset(serial_termios,0,sizeof(struct termios*)*mgsl_device_count);
-	memset(serial_termios_locked,0,sizeof(struct termios*)*mgsl_device_count);
+	memset(serial_table,0,sizeof(struct tty_struct*)*MAX_TOTAL_DEVICES);
+	memset(serial_termios,0,sizeof(struct termios*)*MAX_TOTAL_DEVICES);
+	memset(serial_termios_locked,0,sizeof(struct termios*)*MAX_TOTAL_DEVICES);
 
 	return 0;
 	
@@ -4548,11 +4353,7 @@
 {
 	struct mgsl_struct *info;
 
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
 	EXPORT_NO_SYMBOLS;
-#else
-	register_symtab(NULL);
-#endif		
 	
  	printk("%s version %s\n", driver_name, driver_version);
 	
@@ -4567,9 +4368,7 @@
 	
 	memset(&serial_driver, 0, sizeof(struct tty_driver));
 	serial_driver.magic = TTY_DRIVER_MAGIC;
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
 	serial_driver.driver_name = "synclink";
-#endif	
 	serial_driver.name = "ttySL";
 	serial_driver.major = ttymajor;
 	serial_driver.minor_start = 64;
@@ -4596,12 +4395,10 @@
 	serial_driver.ioctl = mgsl_ioctl;
 	serial_driver.throttle = mgsl_throttle;
 	serial_driver.unthrottle = mgsl_unthrottle;
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
 	serial_driver.send_xchar = mgsl_send_xchar;
 	serial_driver.break_ctl = mgsl_break;
 	serial_driver.wait_until_sent = mgsl_wait_until_sent;
  	serial_driver.read_proc = mgsl_read_proc;
-#endif	
 	serial_driver.set_termios = mgsl_set_termios;
 	serial_driver.stop = mgsl_stop;
 	serial_driver.start = mgsl_start;
@@ -4615,10 +4412,8 @@
 	callout_driver.name = "cuaSL";
 	callout_driver.major = cuamajor;
 	callout_driver.subtype = SERIAL_TYPE_CALLOUT;
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
 	callout_driver.read_proc = 0;
 	callout_driver.proc_entry = 0;
-#endif	
 
 	if (tty_register_driver(&serial_driver) < 0)
 		printk("%s(%d):Couldn't register serial driver\n",
@@ -4645,8 +4440,7 @@
 	
 }	/* end of mgsl_init() */
 
-#ifdef MODULE
-int init_module(void)
+int __init init_module(void)
 {
 /* Uncomment this to kernel debug module.
  * mgsl_get_text_ptr() leaves the .text address in eax
@@ -4692,20 +4486,8 @@
 		tmp_buf = NULL;
 	}
 	
-	if (serial_table)
-		kfree_s(serial_table,sizeof(struct tty_struct*)*mgsl_device_count);
-		
-	if (serial_termios)
-		kfree_s(serial_termios,sizeof(struct termios*)*mgsl_device_count);
-		
-	if (serial_termios_locked)
-		kfree_s(serial_termios_locked,sizeof(struct termios*)*mgsl_device_count);
-	
 }	/* end of cleanup_module() */
 
-#endif /* MODULE */
-
-
 /*
  * usc_RTCmd()
  *
@@ -6952,7 +6734,6 @@
 	while( EndTime-- && !info->irq_occurred ) {
 		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout(jiffies_from_ms(10));
-		set_current_state(TASK_RUNNING);
 	}
 	
 	spin_lock_irqsave(&info->irq_spinlock,flags);
@@ -7575,7 +7356,7 @@
 	sppp_attach(&info->pppdev);
 
 	d = info->netdev;
-	strcpy(d->name, info->netname);
+	d->name = info->netname;
 	d->base_addr = info->io_base;
 	d->irq = info->irq_level;
 	d->dma = info->dma_level;
@@ -7586,10 +7367,6 @@
 	d->hard_start_xmit = mgsl_sppp_tx;
 	d->do_ioctl = mgsl_sppp_ioctl;
 	d->get_stats = mgsl_net_stats;
-#if LINUX_VERSION_CODE >= VERSION(2,3,43) 
-	d->tx_timeout = mgsl_sppp_tx_timeout;
-	d->watchdog_timeo = 10*HZ;
-#endif
 	dev_init_buffers(d);
 
 	if (register_netdev(d) == -1) {
@@ -7679,7 +7456,6 @@
 	if (debug_level >= DEBUG_LEVEL_INFO)
 		printk("mgsl_sppp_tx(%s)\n",info->netname);	
 
-#if LINUX_VERSION_CODE < VERSION(2,3,43) 
 	if (dev->tbusy) { 
 		if (time_before(jiffies, dev->trans_start+10*HZ))
 			return -EBUSY;	/* 10 seconds timeout */
@@ -7687,9 +7463,6 @@
 	}
 	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
 		return -EBUSY;
-#else
-	netif_stop_queue(dev);
-#endif
 
 	info->xmit_cnt = skb->len;
 	mgsl_load_tx_dma_buffer(info, skb->data, skb->len);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/i2o/i2o_block.c linux.19p18/drivers/i2o/i2o_block.c
--- linux.vanilla/drivers/i2o/i2o_block.c	Sat Sep  9 18:42:37 2000
+++ linux.19p18/drivers/i2o/i2o_block.c	Thu Feb  1 14:58:37 2001
@@ -22,6 +22,14 @@
  *				Removed queue walk, fixed for 64bitness.
  *		Boji T Kannanthanam:
  *				Support for dynamic device creation/deletion
+ *				Set the I2O Block devices to be detected in 
+ *				increasing order of TIDs during boot.
+ *				Search and set the I2O block device that we 
+ *				boot off from  as the first device to be 
+ *				claimed (as /dev/i2o/hda)
+ *				Properly attach/detach I2O gendisk structure 
+ *				from the system gendisk list. The I2O block
+ *				devices now appear in /proc/partitions.
  *	To do:
  *		Multiple majors
  *		Serial number scanning to find duplicates for FC multipathing
@@ -1538,14 +1546,14 @@
 static struct gendisk i2ob_gendisk = 
 {
 	MAJOR_NR,
-	"i2ohd",
+	"i2o/hd",
 	4,
 	1<<4,
 	MAX_I2OB,
 	i2ob_geninit,
 	i2ob,
 	i2ob_sizes,
-	0,
+	MAX_I2OB,
 	NULL,
 	NULL
 };
@@ -1654,6 +1662,13 @@
 	 */
 	i2ob_probe();
 
+	/*
+ 	 *      Adding i2ob_gendisk into the gendisk list.
+	 */
+
+	i2ob_gendisk.next = gendisk_head;
+	gendisk_head = &i2ob_gendisk;
+
 	return 0;
 }
 
@@ -1665,7 +1680,7 @@
 
 void cleanup_module(void)
 {
-	struct gendisk **gdp;
+	struct gendisk *gdp;
 	int i;
 	
 	 /*
@@ -1713,9 +1728,17 @@
 	 *	Why isnt register/unregister gendisk in the kernel ???
 	 */
 
-	for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next))
-		if (*gdp == &i2ob_gendisk)
-			break;
+	if (gendisk_head == &i2ob_gendisk) {
+		gendisk_head = i2ob_gendisk.next;
+		}
+	else {
+		for (gdp = gendisk_head; gdp; gdp = gdp->next)
+			if (gdp->next == &i2ob_gendisk)
+			{
+				gdp->next = i2ob_gendisk.next;
+				break;
+			}
+	}
 
 }
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/Config.in linux.19p18/drivers/isdn/Config.in
--- linux.vanilla/drivers/isdn/Config.in	Fri Apr 21 12:46:08 2000
+++ linux.19p18/drivers/isdn/Config.in	Sun Feb 25 23:06:22 2001
@@ -1,25 +1,31 @@
 #
 # ISDN device configuration
 #
+
+# only included if CONFIG_ISDN != n
+
 if [ "$CONFIG_INET" != "n" ]; then
    bool '  Support synchronous PPP' CONFIG_ISDN_PPP
    if [ "$CONFIG_ISDN_PPP" != "n" ]; then
-      bool '    Use VJ-compression with synchronous PPP' CONFIG_ISDN_PPP_VJ
-      bool '    Support generic MP (RFC 1717)' CONFIG_ISDN_MPP
+      bool         '    Use VJ-compression with synchronous PPP' CONFIG_ISDN_PPP_VJ
+      bool         '    Support generic MP (RFC 1717)' CONFIG_ISDN_MPP
+      dep_tristate '    Support BSD compression' CONFIG_ISDN_PPP_BSDCOMP $CONFIG_ISDN
    fi
 fi
 bool '  Support audio via ISDN' CONFIG_ISDN_AUDIO
 if [ "$CONFIG_ISDN_AUDIO" != "n" ]; then
-   bool '    Support AT-Fax Class 2 commands' CONFIG_ISDN_TTY_FAX
+   bool '    Support AT-Fax Class 1 and 2 commands' CONFIG_ISDN_TTY_FAX
 fi
-if [ "$CONFIG_X25" != "n" ]; then
+
+#  CONFIG_X25 is defined only when CONFIG_EXPERIMENTAL=y
+if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_X25" != "n" ]; then
    bool '  X.25 PLP on top of ISDN' CONFIG_ISDN_X25
 fi
 
 mainmenu_option next_comment
 comment 'ISDN feature submodules'
    dep_tristate 'isdnloop support' CONFIG_ISDN_DRV_LOOP $CONFIG_ISDN
-   bool 'Support isdn diversion services' CONFIG_ISDN_DIVERSION
+   dep_tristate 'Support isdn diversion services' CONFIG_ISDN_DIVERSION $CONFIG_ISDN
 endmenu
 
 comment 'low-level hardware drivers'
@@ -37,6 +43,7 @@
       bool '    Disable keypad protocol option' CONFIG_HISAX_NO_KEYPAD
    fi
    bool '  HiSax Support for german 1TR6' CONFIG_HISAX_1TR6
+   bool '  HiSax Support for US NI1' CONFIG_HISAX_NI1
    comment '  HiSax supported cards'
    bool '  Teles 16.0/8.0' CONFIG_HISAX_16_0
    bool '  Teles 16.3 or PNP or PCMCIA' CONFIG_HISAX_16_3
@@ -55,6 +62,7 @@
    bool '  USR Sportster internal TA' CONFIG_HISAX_SPORTSTER
    bool '  MIC card' CONFIG_HISAX_MIC
    bool '  NETjet card' CONFIG_HISAX_NETJET
+   bool '  NETspider U card' CONFIG_HISAX_NETJET_U
    bool '  Niccy PnP/PCI card' CONFIG_HISAX_NICCY
    bool '  Siemens I-Surf card' CONFIG_HISAX_ISURF
    bool '  HST Saphir card' CONFIG_HISAX_HSTSAPHIR
@@ -73,33 +81,62 @@
 fi
 endmenu
 
+### Active ISDN cards
+
 mainmenu_option next_comment
 comment 'Active ISDN cards'
-dep_tristate 'ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN
-dep_tristate 'PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN
-if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
-   dep_tristate 'Spellcaster support (EXPERIMENTAL)' CONFIG_ISDN_DRV_SC $CONFIG_ISDN
-   dep_tristate 'IBM Active 2000 support (EXPERIMENTAL)' CONFIG_ISDN_DRV_ACT2000 $CONFIG_ISDN
-fi
-dep_tristate 'Eicon active card support' CONFIG_ISDN_DRV_EICON $CONFIG_ISDN
+
+dep_tristate       'ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN
+dep_tristate       'PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN
+dep_tristate       'Spellcaster support' CONFIG_ISDN_DRV_SC $CONFIG_ISDN
+dep_tristate       'IBM Active 2000 support' CONFIG_ISDN_DRV_ACT2000 $CONFIG_ISDN
+
+bool               'Eicon active card support' CONFIG_ISDN_DRV_EICON
 if [ "$CONFIG_ISDN_DRV_EICON" != "n" ]; then
-   bool '  Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA
-fi
-dep_tristate 'AVM CAPI2.0 support' CONFIG_ISDN_DRV_AVMB1 $CONFIG_ISDN
-if [ "$CONFIG_ISDN_DRV_AVMB1" != "n" ]; then
-   bool '  AVM B1 ISA support' CONFIG_ISDN_DRV_AVMB1_B1ISA
-   bool '  AVM B1 PCI support' CONFIG_ISDN_DRV_AVMB1_B1PCI
-   if [ "$CONFIG_ISDN_DRV_AVMB1_B1PCI" != "n" ]; then
-      if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
-         bool '  AVM B1 PCI V4 support' CONFIG_ISDN_DRV_AVMB1_B1PCIV4
+   if [ "$CONFIG_ISDN_DRV_EICON_OLD" != "y" ]; then
+      dep_tristate '  Build Eicon driver type standalone' CONFIG_ISDN_DRV_EICON_DIVAS $CONFIG_ISDN
+   fi
+   if [ "$CONFIG_ISDN_DRV_EICON_DIVAS" != "y" ]; then
+      dep_tristate '  Legacy Eicon driver' CONFIG_ISDN_DRV_EICON_OLD $CONFIG_ISDN
+      if [ "$CONFIG_ISDN_DRV_EICON_OLD" != "n" ]; then
+         dep_bool  '    Eicon PCI DIVA Server BRI/PRI/4BRI support' CONFIG_ISDN_DRV_EICON_PCI $CONFIG_PCI
+         bool      '    Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA
       fi
    fi
-   bool '  AVM T1/T1-B ISA support' CONFIG_ISDN_DRV_AVMB1_T1ISA
-   bool '  AVM B1/M1/M2 PCMCIA support' CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
-   bool '  AVM T1/T1-B PCI support' CONFIG_ISDN_DRV_AVMB1_T1PCI
-   if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
-      bool '  AVM C4 support' CONFIG_ISDN_DRV_AVMB1_C4
+fi
+
+# CAPI subsystem
+
+tristate           'CAPI2.0 support' CONFIG_ISDN_CAPI
+if [ "$CONFIG_ISDN_CAPI" != "n" ]; then
+   bool            '  Verbose reason code reporting (kernel size +=7K)' CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
+   dep_bool        '  CAPI2.0 Middleware support (EXPERIMENTAL)' CONFIG_ISDN_CAPI_MIDDLEWARE $CONFIG_EXPERIMENTAL
+   dep_tristate    '  CAPI2.0 /dev/capi support' CONFIG_ISDN_CAPI_CAPI20 $CONFIG_ISDN_CAPI
+   if [ "$CONFIG_ISDN_CAPI_MIDDLEWARE" = "y" ]; then
+      dep_mbool    '    CAPI2.0 filesystem support' CONFIG_ISDN_CAPI_CAPIFS_BOOL $CONFIG_ISDN_CAPI_CAPI20
+      if [ "$CONFIG_ISDN_CAPI_CAPIFS_BOOL" = "y" ]; then
+	 define_tristate CONFIG_ISDN_CAPI_CAPIFS $CONFIG_ISDN_CAPI_CAPI20
+      else
+	 define_tristate CONFIG_ISDN_CAPI_CAPIFS n
+      fi
    fi
-   bool '  Verbose reason code reporting (kernel size +=7K)' CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
+   dep_tristate    '  CAPI2.0 capidrv interface support' CONFIG_ISDN_CAPI_CAPIDRV $CONFIG_ISDN_CAPI $CONFIG_ISDN
 fi
+
+# CAPI drivers
+
+if [ "$CONFIG_ISDN_CAPI" != "n" ]; then
+   dep_tristate '  AVM B1 ISA support' CONFIG_ISDN_DRV_AVMB1_B1ISA $CONFIG_ISDN_CAPI
+   dep_tristate '  AVM B1 PCI support' CONFIG_ISDN_DRV_AVMB1_B1PCI $CONFIG_ISDN_CAPI $CONFIG_PCI
+   dep_mbool    '    AVM B1 PCI V4 support' CONFIG_ISDN_DRV_AVMB1_B1PCIV4 $CONFIG_ISDN_DRV_AVMB1_B1PCI
+   dep_tristate '  AVM T1/T1-B ISA support' CONFIG_ISDN_DRV_AVMB1_T1ISA $CONFIG_ISDN_CAPI
+   dep_tristate '  AVM B1/M1/M2 PCMCIA support' CONFIG_ISDN_DRV_AVMB1_B1PCMCIA $CONFIG_ISDN_CAPI $CONFIG_PCMCIA
+   dep_tristate '  AVM T1/T1-B PCI support' CONFIG_ISDN_DRV_AVMB1_T1PCI $CONFIG_ISDN_CAPI $CONFIG_PCI
+   dep_tristate '  AVM C4 support' CONFIG_ISDN_DRV_AVMB1_C4 $CONFIG_ISDN_CAPI $CONFIG_PCI
+fi
+
+# HYSDN
+
+dep_tristate '  Hypercope HYSDN cards (Champ, Ergo, Metro) support (module only)' CONFIG_HYSDN m $CONFIG_PROC_FS
+dep_mbool    '    HYSDN CAPI 2.0 support' CONFIG_HYSDN_CAPI $CONFIG_HYSDN $CONFIG_ISDN_CAPI
 endmenu
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/Makefile linux.19p18/drivers/isdn/Makefile
--- linux.vanilla/drivers/isdn/Makefile	Fri Apr 21 12:46:12 2000
+++ linux.19p18/drivers/isdn/Makefile	Mon Feb 19 18:28:19 2001
@@ -1,141 +1,56 @@
-SUB_DIRS     :=
-MOD_SUB_DIRS :=
-ALL_SUB_DIRS := icn pcbit hisax avmb1 act2000 eicon divert
-
-L_OBJS :=
-LX_OBJS :=
-M_OBJS :=
-MX_OBJS :=
-O_OBJS :=
-OX_OBJS :=
-L_TARGET :=
-O_TARGET :=
-
-ifeq ($(CONFIG_ISDN),y)
-  L_TARGET := isdn.a
-  L_OBJS += isdn_net.o isdn_tty.o isdn_cards.o isdn_v110.o
-  LX_OBJS += isdn_common.o 
-  ifdef CONFIG_ISDN_PPP
-    L_OBJS += isdn_ppp.o
-  endif
-  ifdef CONFIG_ISDN_X25
-    L_OBJS += isdn_x25iface.o
-    L_OBJS += isdn_concap.o
-  endif
-  ifdef CONFIG_ISDN_AUDIO
-    L_OBJS += isdn_audio.o
-    ifdef CONFIG_ISDN_TTY_FAX
-      L_OBJS += isdn_ttyfax.o
-    endif
-  endif
-else
-  ifeq ($(CONFIG_ISDN),m)
-    M_OBJS += isdn.o
-    O_TARGET += isdn.o
-    O_OBJS += isdn_net.o isdn_tty.o isdn_v110.o
-    OX_OBJS += isdn_common.o
-    ifdef CONFIG_ISDN_PPP
-      O_OBJS += isdn_ppp.o
-      M_OBJS += isdn_bsdcomp.o
-    endif
-    ifdef CONFIG_ISDN_X25
-      O_OBJS += isdn_x25iface.o
-      O_OBJS += isdn_concap.o
-    endif  
-    ifdef CONFIG_ISDN_AUDIO
-      O_OBJS += isdn_audio.o
-      ifdef CONFIG_ISDN_TTY_FAX
-        O_OBJS += isdn_ttyfax.o
-      endif
-    endif
-  endif
-endif
-
-ifeq ($(CONFIG_ISDN_DIVERSION),y)
- ifeq ($(CONFIG_MODULES),y)
-    MOD_SUB_DIRS += divert
- endif
-endif
-
-ifeq ($(CONFIG_ISDN_DRV_HISAX),y)
-  L_OBJS += hisax/hisax.o
-  SUB_DIRS += hisax
-  MOD_SUB_DIRS += hisax
-else
-  ifeq ($(CONFIG_ISDN_DRV_HISAX),m)
-    MOD_SUB_DIRS += hisax
-  endif
-endif
-
-ifeq ($(CONFIG_ISDN_DRV_ICN),y)
-  L_OBJS += icn/icn_obj.o
-  SUB_DIRS += icn
-  MOD_SUB_DIRS += icn
-else
-  ifeq ($(CONFIG_ISDN_DRV_ICN),m)
-    MOD_SUB_DIRS += icn
-  endif
-endif
-
-ifeq ($(CONFIG_ISDN_DRV_PCBIT),y)
-  L_OBJS += pcbit/pcbit.o
-  SUB_DIRS += pcbit
-  MOD_SUB_DIRS += pcbit
-else
-  ifeq ($(CONFIG_ISDN_DRV_PCBIT),m)
-    MOD_SUB_DIRS += pcbit
-  endif
-endif
-
-ifeq ($(CONFIG_ISDN_DRV_SC),y)
-  L_OBJS += sc/sc.o
-  SUB_DIRS += sc
-  MOD_SUB_DIRS += sc
-else
-  ifeq ($(CONFIG_ISDN_DRV_SC),m)
-    MOD_SUB_DIRS += sc
-  endif
-endif
-
-ifeq ($(CONFIG_ISDN_DRV_AVMB1),y)
-  L_OBJS += avmb1/avmb1.o
-  SUB_DIRS += avmb1
-  MOD_SUB_DIRS += avmb1
-else
-  ifeq ($(CONFIG_ISDN_DRV_AVMB1),m)
-    MOD_SUB_DIRS += avmb1
-  endif
-endif
-
-ifeq ($(CONFIG_ISDN_DRV_LOOP),y)
-  L_OBJS += isdnloop/isdnloop.o
-  SUB_DIRS += isdnloop
-  MOD_SUB_DIRS += isdnloop
-else
-  ifeq ($(CONFIG_ISDN_DRV_LOOP),m)
-    MOD_SUB_DIRS += isdnloop
-  endif
-endif
-
-ifeq ($(CONFIG_ISDN_DRV_ACT2000),y)
-  L_OBJS += act2000/act2000.o
-  SUB_DIRS += act2000
-  MOD_SUB_DIRS += act2000
-else
-  ifeq ($(CONFIG_ISDN_DRV_ACT2000),m)
-    MOD_SUB_DIRS += act2000
-  endif
-endif
-
-ifeq ($(CONFIG_ISDN_DRV_EICON),y)
-  L_OBJS += eicon/eicon.o
-  SUB_DIRS += eicon
-  MOD_SUB_DIRS += eicon
-else
-  ifeq ($(CONFIG_ISDN_DRV_EICON),m)
-    MOD_SUB_DIRS += eicon
-  endif
-endif
+# Makefile for the kernel ISDN subsystem and device drivers.
 
-include $(TOPDIR)/Rules.make
+# The target object and module list name.
 
+O_TARGET	:= isdn.a
+
+# Objects that export symbols.
+
+export-objs	:= isdn_common.o
+
+# Multipart objects.
+
+list-multi	:= isdn.o
+isdn-objs	:= isdn_net.o isdn_tty.o isdn_v110.o isdn_common.o
+
+# Optional parts of multipart objects.
+
+isdn-objs-$(CONFIG_ISDN_PPP)		+= isdn_ppp.o
+isdn-objs-$(CONFIG_ISDN_X25)		+= isdn_concap.o isdn_x25iface.o
+isdn-objs-$(CONFIG_ISDN_AUDIO)		+= isdn_audio.o
+isdn-objs-$(CONFIG_ISDN_TTY_FAX)	+= isdn_ttyfax.o
+isdn-objs-$(CONFIG_ISDN_WITH_ABC)	+= isdn_dwabc.o
+
+isdn-objs				+= $(isdn-objs-y)
+
+# Ordering constraints: isdn.o first, rest doesn't matter
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_ISDN)			+= isdn.o
+obj-$(CONFIG_ISDN_PPP_BSDCOMP)		+= isdn_bsdcomp.o
+
+# Object files in subdirectories
+
+mod-subdirs				:= avmb1 eicon
+subdir-$(CONFIG_ISDN_DIVERSION)		+= divert
+subdir-$(CONFIG_ISDN_DRV_HISAX)		+= hisax
+subdir-$(CONFIG_ISDN_DRV_ICN)		+= icn
+subdir-$(CONFIG_ISDN_DRV_PCBIT)		+= pcbit
+subdir-$(CONFIG_ISDN_DRV_SC)		+= sc
+subdir-$(CONFIG_ISDN_CAPI)		+= avmb1
+subdir-$(CONFIG_ISDN_DRV_LOOP)		+= isdnloop
+subdir-$(CONFIG_ISDN_DRV_ACT2000)	+= act2000
+subdir-$(CONFIG_ISDN_DRV_EICON)		+= eicon
+subdir-$(CONFIG_HYSDN)			+= hysdn
+
+obj-y += $(addsuffix /vmlinux-obj.o, $(subdir-y))
+
+# The global Rules.make.
+
+include $(TOPDIR)/drivers/isdn/Rules.make
+
+# Link rules for multi-part drivers.
+
+isdn.o: $(isdn-objs)
+	$(LD) -r -o $@ $(isdn-objs)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/Rules.make linux.19p18/drivers/isdn/Rules.make
--- linux.vanilla/drivers/isdn/Rules.make	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/Rules.make	Tue Feb 13 18:38:13 2001
@@ -0,0 +1,32 @@
+# Extract lists of the multi-part drivers.
+# The 'int-*' lists are the intermediate files used to build the multi's.
+
+multi-y		:= $(filter $(list-multi), $(obj-y))
+multi-m		:= $(filter $(list-multi), $(obj-m))
+int-y		:= $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
+int-m		:= $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
+
+# Files that are both resident and modular: remove from modular.
+
+obj-m		:= $(filter-out $(obj-y), $(obj-m))
+int-m		:= $(filter-out $(int-y), $(int-m))
+
+# Take multi-part drivers out of obj-y and put components in.
+
+obj-y		:= $(filter-out $(list-multi), $(obj-y)) $(int-y)
+
+# Translate to Rules.make lists.
+
+O_OBJS		:= $(sort $(filter-out $(export-objs), $(obj-y)))
+OX_OBJS		:= $(sort $(filter     $(export-objs), $(obj-y)))
+M_OBJS		:= $(sort $(filter-out $(export-objs), $(obj-m)))
+MX_OBJS		:= $(sort $(filter     $(export-objs), $(obj-m)))
+MI_OBJS		:= $(sort $(filter-out $(export-objs), $(int-m)))
+MIX_OBJS	:= $(sort $(filter     $(export-objs), $(int-m)))
+
+both-m		:= $(filter $(mod-subdirs), $(subdir-y))
+SUB_DIRS	:= $(subdir-y)
+MOD_SUB_DIRS	:= $(sort $(subdir-m) $(both-m))
+ALL_SUB_DIRS	:= $(sort $(subdir-y) $(subdir-m) $(subdir-n) $(subdir-))
+
+include $(TOPDIR)/Rules.make
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/act2000/Makefile linux.19p18/drivers/isdn/act2000/Makefile
--- linux.vanilla/drivers/isdn/act2000/Makefile	Fri Apr 21 12:46:07 2000
+++ linux.19p18/drivers/isdn/act2000/Makefile	Tue Feb 13 18:38:13 2001
@@ -1,15 +1,21 @@
-L_OBJS :=
-M_OBJS :=
-O_OBJS := module.o capi.o act2000_isa.o
-
-O_TARGET :=
-ifeq ($(CONFIG_ISDN_DRV_ACT2000),y)
-  O_TARGET += act2000.o
-else
-  ifeq ($(CONFIG_ISDN_DRV_ACT2000),m)
-  	O_TARGET += act2000.o
-	M_OBJS = act2000.o
-  endif
-endif
+# Makefile for the act2000 ISDN device driver
 
-include $(TOPDIR)/Rules.make
+# The target object and module list name.
+
+O_TARGET	:= vmlinux-obj.o
+
+# Multipart objects.
+
+list-multi	:= act2000.o
+act2000-objs	:= module.o capi.o act2000_isa.o
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_ISDN_DRV_ACT2000)	+= act2000.o
+
+include $(TOPDIR)/drivers/isdn/Rules.make
+
+# Link rules for multi-part drivers.
+
+act2000.o: $(act2000-objs)
+	$(LD) -r -o $@ $(act2000-objs)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/act2000/act2000.h linux.19p18/drivers/isdn/act2000/act2000.h
--- linux.vanilla/drivers/isdn/act2000/act2000.h	Wed May  3 22:34:32 2000
+++ linux.19p18/drivers/isdn/act2000/act2000.h	Sun Mar 11 13:12:22 2001
@@ -1,4 +1,4 @@
-/* $Id: act2000.h,v 1.7 1999/04/12 13:13:54 fritz Exp $
+/* $Id: act2000.h,v 1.8.6.1 2001/02/10 14:41:20 kai Exp $
  *
  * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
  *
@@ -19,31 +19,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
- * $Log: act2000.h,v $
- * Revision 1.7  1999/04/12 13:13:54  fritz
- * Made cards pointer static to avoid name-clash.
- *
- * Revision 1.6  1998/11/05 22:12:38  fritz
- * Changed mail-address.
- *
- * Revision 1.5  1997/10/09 22:22:59  fritz
- * New HL<->LL interface:
- *   New BSENT callback with nr. of bytes included.
- *   Sending without ACK.
- *
- * Revision 1.4  1997/09/25 17:25:37  fritz
- * Support for adding cards at runtime.
- * Support for new Firmware.
- *
- * Revision 1.3  1997/09/24 23:11:43  fritz
- * Optimized IRQ load and polling-mode.
- *
- * Revision 1.2  1997/09/24 19:44:12  fritz
- * Added MSN mapping support, some cleanup.
- *
- * Revision 1.1  1997/09/23 18:00:05  fritz
- * New driver for IBM Active 2000.
- *
  */
 
 #ifndef act2000_h
@@ -113,7 +88,7 @@
 #include <asm/io.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
 #include <linux/ioport.h>
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/act2000/act2000_isa.c linux.19p18/drivers/isdn/act2000/act2000_isa.c
--- linux.vanilla/drivers/isdn/act2000/act2000_isa.c	Fri Apr 21 12:46:07 2000
+++ linux.19p18/drivers/isdn/act2000/act2000_isa.c	Wed Dec 13 22:06:07 2000
@@ -1,4 +1,4 @@
-/* $Id: act2000_isa.c,v 1.10 1999/10/24 18:46:05 fritz Exp $
+/* $Id: act2000_isa.c,v 1.11 2000/11/12 16:32:06 kai Exp $
  *
  * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version).
  *
@@ -19,43 +19,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
- * $Log: act2000_isa.c,v $
- * Revision 1.10  1999/10/24 18:46:05  fritz
- * Changed isa_ prefix to act2000_isa_ to prevent name-clash in latest
- * kernels.
- *
- * Revision 1.9  1999/09/04 06:20:04  keil
- * Changes from kernel set_current_state()
- *
- * Revision 1.8  1999/01/05 18:29:25  he
- * merged remaining schedule_timeout() changes from 2.1.127
- *
- * Revision 1.7  1998/11/05 22:12:41  fritz
- * Changed mail-address.
- *
- * Revision 1.6  1998/06/17 19:51:09  he
- * merged with 2.1.10[34] (cosmetics and udelay() -> mdelay())
- * brute force fix to avoid Ugh's in isdn_tty_write()
- * cleaned up some dead code
- *
- * Revision 1.5  1998/02/12 23:06:47  keil
- * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
- *
- * Revision 1.4  1997/10/09 22:23:00  fritz
- * New HL<->LL interface:
- *   New BSENT callback with nr. of bytes included.
- *   Sending without ACK.
- *
- * Revision 1.3  1997/09/25 17:25:38  fritz
- * Support for adding cards at runtime.
- * Support for new Firmware.
- *
- * Revision 1.2  1997/09/24 23:11:44  fritz
- * Optimized IRQ load and polling-mode.
- *
- * Revision 1.1  1997/09/23 18:00:05  fritz
- * New driver for IBM Active 2000.
- *
  */
 
 #define __NO_VERSION__
@@ -78,7 +41,7 @@
 act2000_isa_delay(long t)
 {
         sti();
-        current->state = TASK_INTERRUPTIBLE;
+        set_current_state(TASK_INTERRUPTIBLE);
         schedule_timeout(t);
         sti();
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/act2000/act2000_isa.h linux.19p18/drivers/isdn/act2000/act2000_isa.h
--- linux.vanilla/drivers/isdn/act2000/act2000_isa.h	Fri Apr 21 12:46:07 2000
+++ linux.19p18/drivers/isdn/act2000/act2000_isa.h	Wed Dec 13 22:06:13 2000
@@ -1,4 +1,4 @@
-/* $Id: act2000_isa.h,v 1.3 1999/10/24 18:46:05 fritz Exp $
+/* $Id: act2000_isa.h,v 1.4 2000/11/12 16:32:06 kai Exp $
  *
  * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version).
  *
@@ -18,17 +18,6 @@
  * 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. 
- *
- * $Log: act2000_isa.h,v $
- * Revision 1.3  1999/10/24 18:46:05  fritz
- * Changed isa_ prefix to act2000_isa_ to prevent name-clash in latest
- * kernels.
- *
- * Revision 1.2  1998/11/05 22:12:43  fritz
- * Changed mail-address.
- *
- * Revision 1.1  1997/09/23 18:00:07  fritz
- * New driver for IBM Active 2000.
  *
  */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/act2000/capi.c linux.19p18/drivers/isdn/act2000/capi.c
--- linux.vanilla/drivers/isdn/act2000/capi.c	Fri Apr 21 12:46:07 2000
+++ linux.19p18/drivers/isdn/act2000/capi.c	Wed Dec 13 22:06:13 2000
@@ -1,4 +1,4 @@
-/* $Id: capi.c,v 1.8 1998/11/05 22:12:46 fritz Exp $
+/* $Id: capi.c,v 1.9 2000/11/12 16:32:06 kai Exp $
  *
  * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
  *        CAPI encoder/decoder
@@ -19,34 +19,6 @@
  * 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. 
- *
- * $Log: capi.c,v $
- * Revision 1.8  1998/11/05 22:12:46  fritz
- * Changed mail-address.
- *
- * Revision 1.7  1998/02/23 23:35:41  fritz
- * Eliminated some compiler warnings.
- *
- * Revision 1.6  1998/02/12 23:06:50  keil
- * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
- *
- * Revision 1.5  1997/10/09 22:23:02  fritz
- * New HL<->LL interface:
- *   New BSENT callback with nr. of bytes included.
- *   Sending without ACK.
- *
- * Revision 1.4  1997/09/25 17:25:39  fritz
- * Support for adding cards at runtime.
- * Support for new Firmware.
- *
- * Revision 1.3  1997/09/24 19:44:14  fritz
- * Added MSN mapping support, some cleanup.
- *
- * Revision 1.2  1997/09/23 19:41:24  fritz
- * Disabled Logging of DATA_B3_IND/RESP/REQ/CONF Messages.
- *
- * Revision 1.1  1997/09/23 18:00:08  fritz
- * New driver for IBM Active 2000.
  *
  */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/act2000/capi.h linux.19p18/drivers/isdn/act2000/capi.h
--- linux.vanilla/drivers/isdn/act2000/capi.h	Fri Apr 21 12:46:07 2000
+++ linux.19p18/drivers/isdn/act2000/capi.h	Wed Dec 13 22:06:13 2000
@@ -1,4 +1,4 @@
-/* $Id: capi.h,v 1.5 1998/11/05 22:12:48 fritz Exp $
+/* $Id: capi.h,v 1.6 2000/11/12 16:32:06 kai Exp $
  *
  * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
  *
@@ -18,25 +18,6 @@
  * 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. 
- *
- * $Log: capi.h,v $
- * Revision 1.5  1998/11/05 22:12:48  fritz
- * Changed mail-address.
- *
- * Revision 1.4  1997/10/01 09:21:04  fritz
- * Removed old compatibility stuff for 2.0.X kernels.
- * From now on, this code is for 2.1.X ONLY!
- * Old stuff is still in the separate branch.
- *
- * Revision 1.3  1997/09/25 17:25:41  fritz
- * Support for adding cards at runtime.
- * Support for new Firmware.
- *
- * Revision 1.2  1997/09/24 19:44:15  fritz
- * Added MSN mapping support, some cleanup.
- *
- * Revision 1.1  1997/09/23 18:00:10  fritz
- * New driver for IBM Active 2000.
  *
  */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/act2000/module.c linux.19p18/drivers/isdn/act2000/module.c
--- linux.vanilla/drivers/isdn/act2000/module.c	Mon Dec 11 22:12:45 2000
+++ linux.19p18/drivers/isdn/act2000/module.c	Tue Feb 13 18:50:48 2001
@@ -1,4 +1,4 @@
-/* $Id: module.c,v 1.11 1999/10/30 09:48:04 keil Exp $
+/* $Id: module.c,v 1.14.6.2 2000/12/18 22:14:10 kai Exp $
  *
  * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
  *
@@ -19,49 +19,12 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
- * $Log: module.c,v $
- * Revision 1.11  1999/10/30 09:48:04  keil
- * miss one prefix act2000
- *
- * Revision 1.10  1999/10/24 18:46:05  fritz
- * Changed isa_ prefix to act2000_isa_ to prevent name-clash in latest
- * kernels.
- *
- * Revision 1.9  1999/04/12 13:13:56  fritz
- * Made cards pointer static to avoid name-clash.
- *
- * Revision 1.8  1998/11/05 22:12:51  fritz
- * Changed mail-address.
- *
- * Revision 1.7  1998/02/12 23:06:52  keil
- * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
- *
- * Revision 1.6  1998/01/31 22:10:42  keil
- * changes for 2.1.82
- *
- * Revision 1.5  1997/10/09 22:23:04  fritz
- * New HL<->LL interface:
- *   New BSENT callback with nr. of bytes included.
- *   Sending without ACK.
- *
- * Revision 1.4  1997/09/25 17:25:43  fritz
- * Support for adding cards at runtime.
- * Support for new Firmware.
- *
- * Revision 1.3  1997/09/24 23:11:45  fritz
- * Optimized IRQ load and polling-mode.
- *
- * Revision 1.2  1997/09/24 19:44:17  fritz
- * Added MSN mapping support, some cleanup.
- *
- * Revision 1.1  1997/09/23 18:00:13  fritz
- * New driver for IBM Active 2000.
- *
  */
 
 #include "act2000.h"
 #include "act2000_isa.h"
 #include "capi.h"
+#include <linux/init.h>
 
 static unsigned short act2000_isa_ports[] =
 {
@@ -563,37 +526,6 @@
         return count;
 }
 
-static void
-act2000_putmsg(act2000_card *card, char c)
-{
-        ulong flags;
-
-        save_flags(flags);
-        cli();
-        *card->status_buf_write++ = c;
-        if (card->status_buf_write == card->status_buf_read) {
-                if (++card->status_buf_read > card->status_buf_end)
-                card->status_buf_read = card->status_buf;
-        }
-        if (card->status_buf_write > card->status_buf_end)
-                card->status_buf_write = card->status_buf;
-        restore_flags(flags);
-}
-
-static void
-act2000_logstat(struct act2000_card *card, char *str)
-{
-        char *p = str;
-        isdn_ctrl c;
-
-	while (*p)
-		act2000_putmsg(card, *p++);
-        c.command = ISDN_STAT_STAVAIL;
-        c.driver = card->myid;
-        c.arg = strlen(str);
-        card->interface.statcallb(&c);
-}
-
 /*
  * Find card with given driverId
  */
@@ -889,12 +821,7 @@
 
 #define DRIVERNAME "IBM Active 2000 ISDN driver"
 
-#ifdef MODULE
-#define act2000_init init_module
-#endif
-
-int
-act2000_init(void)
+static int __init act2000_init(void)
 {
         printk(KERN_INFO "%s\n", DRIVERNAME);
         if (!cards)
@@ -906,9 +833,7 @@
         return 0;
 }
 
-#ifdef MODULE
-void
-cleanup_module(void)
+static void  act2000_exit(void)
 {
         act2000_card *card = cards;
         act2000_card *last;
@@ -927,34 +852,5 @@
         printk(KERN_INFO "%s unloaded\n", DRIVERNAME);
 }
 
-#else
-void
-act2000_setup(char *str, int *ints)
-{
-        int i, j, argc, port, irq, bus;
-	
-        argc = ints[0];
-        i = 1;
-        if (argc)
-                while (argc) {
-                        port = irq = -1;
-			bus = 0;
-                        if (argc) {
-                                bus = ints[i];
-                                i++;
-                                argc--;
-                        }
-                        if (argc) {
-                                port = ints[i];
-                                i++;
-                                argc--;
-                        }
-                        if (argc) {
-                                irq = ints[i];
-                                i++;
-                                argc--;
-                        }
-			act2000_addcard(bus, port, irq, act_id);
-		}
-}
-#endif
+module_init(act2000_init);
+module_exit(act2000_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/avmb1/Makefile linux.19p18/drivers/isdn/avmb1/Makefile
--- linux.vanilla/drivers/isdn/avmb1/Makefile	Fri Apr 21 12:46:08 2000
+++ linux.19p18/drivers/isdn/avmb1/Makefile	Tue Feb 13 18:38:13 2001
@@ -1,135 +1,40 @@
-#
-# $Id: Makefile,v 1.8 2000/01/25 14:33:38 calle Exp $
-#
-# Makefile for the CAPI and AVM-B1 device drivers.
-#
-# 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..
-#
-# $Log: Makefile,v $
-# Revision 1.8  2000/01/25 14:33:38  calle
-# - Added Support AVM B1 PCI V4.0 (tested with prototype)
-#   - splitted up t1pci.c into b1dma.c for common function with b1pciv4
-#   - support for revision register
-#
-# Revision 1.7  1999/09/15 08:16:03  calle
-# Implementation of 64Bit extention complete.
-#
-# Revision 1.6  1999/07/20 06:41:44  calle
-# Bugfix: After the redesign of the AVM B1 driver, the driver didn't even
-#         compile, if not selected as modules.
-#
-# Revision 1.5  1999/07/01 15:26:20  calle
-# complete new version (I love it):
-# + new hardware independed "capi_driver" interface that will make it easy to:
-#   - support other controllers with CAPI-2.0 (i.e. USB Controller)
-#   - write a CAPI-2.0 for the passive cards
-#   - support serial link CAPI-2.0 boxes.
-# + wrote "capi_driver" for all supported cards.
-# + "capi_driver" (supported cards) now have to be configured with
-#   make menuconfig, in the past all supported cards where included
-#   at once.
-# + new and better informations in /proc/capi/
-# + new ioctl to switch trace of capi messages per controller
-#   using "avmcapictrl trace [contr] on|off|...."
-# + complete testcircle with all supported cards and also the
-#   PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
-#
-# Revision 1.4  1997/03/30 17:10:40  calle
-# added support for AVM-B1-PCI card.
-#
-# Revision 1.3  1997/03/22 02:00:57  fritz
-# -Reworked toplevel Makefile. From now on, no different Makefiles
-#  for standalone- and in-kernel-compilation are needed any more.
-# -Added local Rules.make for above reason.
-# -Experimental changes in teles3.c for enhanced IRQ-checking with
-#  2.1.X and SMP kernels.
-# -Removed diffstd-script, same functionality is in stddiff -r.
-# -Enhanced scripts std2kern and stddiff.
-#
-# Revision 1.1  1997/03/05 21:26:14  fritz
-# Renamed, according naming conventions in CVS tree.
-#
-# Revision 1.1  1997/03/04 21:50:26  calle
-# Frirst version in isdn4linux
-#
-# Revision 2.2  1997/02/12 09:31:39  calle
-#
-# Revision 1.1  1997/01/31 10:32:20  calle
-# Initial revision
-#
-#
-
-#
-# Objects that don't export a symtab
-#
-L_OBJS := # used as component of an L_TARGET
-O_OBJS := # used as component of an O_TARGET
-M_OBJS := # used as module
-#
-# Objects that do export a symtab
-#
-LX_OBJS := # used as component of an L_TARGET
-OX_OBJS := # used as component of an O_TARGET
-MX_OBJS := # used as module
-#
-# Targets, created by linking others
-#
-O_TARGET := # used for .o targets (from O and OX objects)
-L_TARGET := # used for .a targets (from L and LX objects)
-
-ifeq ($(CONFIG_ISDN_DRV_AVMB1),y)
-  O_TARGET += avmb1.o
-  OX_OBJS  += kcapi.o
-  O_OBJS   += capi.o
-  ifdef CONFIG_ISDN_DRV_AVMB1_B1ISA
-  O_OBJS   += b1isa.o
-  endif
-  ifdef CONFIG_ISDN_DRV_AVMB1_B1PCI
-  O_OBJS  += b1pci.o
-  endif
-  ifdef CONFIG_ISDN_DRV_AVMB1_T1ISA
-  O_OBJS   += t1isa.o
-  endif
-  ifdef CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
-  OX_OBJS   += b1pcmcia.o
-  endif
-  ifdef CONFIG_ISDN_DRV_AVMB1_T1PCI
-  O_OBJS   += t1pci.o
-  endif
-  ifdef CONFIG_ISDN_DRV_AVMB1_C4
-  O_OBJS   += c4.o
-  endif
-  OX_OBJS  += capiutil.o capidrv.o b1.o b1dma.o
-else
-  ifeq ($(CONFIG_ISDN_DRV_AVMB1),m)
-  O_TARGET += kernelcapi.o
-  OX_OBJS  += kcapi.o
-  M_OBJS   += capi.o kernelcapi.o
-  ifdef CONFIG_ISDN_DRV_AVMB1_B1ISA
-  M_OBJS   += b1isa.o
-  endif
-  ifdef CONFIG_ISDN_DRV_AVMB1_B1PCI
-  M_OBJS  += b1pci.o
-  endif
-  ifdef CONFIG_ISDN_DRV_AVMB1_T1ISA
-  M_OBJS   += t1isa.o
-  endif
-  ifdef CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
-  MX_OBJS  += b1pcmcia.o
-  endif
-  ifdef CONFIG_ISDN_DRV_AVMB1_T1PCI
-  M_OBJS   += t1pci.o
-  endif
-  ifdef CONFIG_ISDN_DRV_AVMB1_C4
-  M_OBJS   += c4.o
-  endif
-  MX_OBJS  += capiutil.o capidrv.o b1.o b1dma.o
-  endif
-endif
+# Makefile for the AVM ISDN device drivers and CAPI subsystem.
+
+# The target object and module list name.
+
+O_TARGET	:= vmlinux-obj.o
+
+# Objects that export symbols.
+
+export-objs	:= kcapi.o capiutil.o b1dma.o b1pcmcia.o b1.o capifs.o
+
+# Multipart objects.
+
+list-multi	:= kernelcapi.o
+kernelcapi-objs	:= kcapi.o
+
+# Ordering constraints: kernelcapi.o first
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_ISDN_CAPI)			+= kernelcapi.o capiutil.o
+obj-$(CONFIG_ISDN_CAPI_CAPI20)		+= capi.o 
+obj-$(CONFIG_ISDN_CAPI_CAPIDRV)		+= capidrv.o
+obj-$(CONFIG_ISDN_CAPI_CAPIFS)		+= capifs.o
+obj-$(CONFIG_ISDN_DRV_AVMB1_B1ISA)	+= b1isa.o b1.o
+obj-$(CONFIG_ISDN_DRV_AVMB1_B1PCI)	+= b1pci.o b1.o b1dma.o
+obj-$(CONFIG_ISDN_DRV_AVMB1_B1PCMCIA)	+= b1pcmcia.o b1.o
+obj-$(CONFIG_ISDN_DRV_AVMB1_AVM_CS)	+= avm_cs.o
+obj-$(CONFIG_ISDN_DRV_AVMB1_T1ISA)	+= t1isa.o b1.o
+obj-$(CONFIG_ISDN_DRV_AVMB1_T1PCI)	+= t1pci.o b1.o b1dma.o
+obj-$(CONFIG_ISDN_DRV_AVMB1_C4)		+= c4.o b1.o
+
+# The global Rules.make.
+
+include $(TOPDIR)/drivers/isdn/Rules.make
+
+# Link rules for multi-part drivers.
+
+kernelcapi.o: $(kernelcapi-objs)
+	$(LD) -r -o $@ $(kernelcapi-objs)
 
-include $(TOPDIR)/Rules.make
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/avmb1/avmcard.h linux.19p18/drivers/isdn/avmb1/avmcard.h
--- linux.vanilla/drivers/isdn/avmb1/avmcard.h	Mon Dec 11 22:12:45 2000
+++ linux.19p18/drivers/isdn/avmb1/avmcard.h	Sat Dec 30 19:33:51 2000
@@ -1,9 +1,12 @@
 /*
- * $Id: avmcard.h,v 1.7 2000/01/25 14:33:38 calle Exp $
+ * $Id: avmcard.h,v 1.8 2000/10/10 17:44:19 kai Exp $
  *
  * Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  *
  * $Log: avmcard.h,v $
+ * Revision 1.8  2000/10/10 17:44:19  kai
+ * changes from/for 2.2.18
+ *
  * Revision 1.7  2000/01/25 14:33:38  calle
  * - Added Support AVM B1 PCI V4.0 (tested with prototype)
  *   - splitted up t1pci.c into b1dma.c for common function with b1pciv4
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/avmb1/b1.c linux.19p18/drivers/isdn/avmb1/b1.c
--- linux.vanilla/drivers/isdn/avmb1/b1.c	Sat Sep  9 18:42:38 2000
+++ linux.19p18/drivers/isdn/avmb1/b1.c	Wed Feb 14 14:28:52 2001
@@ -1,11 +1,38 @@
 /*
- * $Id: b1.c,v 1.13 2000/01/25 14:33:38 calle Exp $
+ * $Id: b1.c,v 1.20.6.1 2001/02/13 11:43:29 kai Exp $
  * 
  * Common module for AVM B1 cards.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: b1.c,v $
+ * Revision 1.20.6.1  2001/02/13 11:43:29  kai
+ * more compatility changes for 2.2.19
+ *
+ * Revision 1.20  2000/11/23 20:45:14  kai
+ * fixed module_init/exit stuff
+ * Note: compiled-in kernel doesn't work pre 2.2.18 anymore.
+ *
+ * Revision 1.19  2000/11/19 17:02:47  kai
+ * compatibility cleanup - part 3
+ *
+ * Revision 1.18  2000/11/19 17:01:53  kai
+ * compatibility cleanup - part 2
+ *
+ * Revision 1.17  2000/11/01 14:05:02  calle
+ * - use module_init/module_exit from linux/init.h.
+ * - all static struct variables are initialized with "membername:" now.
+ * - avm_cs.c, let it work with newer pcmcia-cs.
+ *
+ * Revision 1.16  2000/08/04 15:36:31  calle
+ * copied wrong from file to file :-(
+ *
+ * Revision 1.15  2000/08/04 12:20:08  calle
+ * - Fix unsigned/signed warning in the right way ...
+ *
+ * Revision 1.14  2000/06/19 16:51:53  keil
+ * don't free skb in irq context
+ *
  * Revision 1.13  2000/01/25 14:33:38  calle
  * - Added Support AVM B1 PCI V4.0 (tested with prototype)
  *   - splitted up t1pci.c into b1dma.c for common function with b1pciv4
@@ -85,13 +112,14 @@
 #include <linux/ioport.h>
 #include <linux/capi.h>
 #include <asm/io.h>
+#include <linux/init.h>
 #include <asm/uaccess.h>
 #include "capilli.h"
 #include "avmcard.h"
 #include "capicmd.h"
 #include "capiutil.h"
 
-static char *revision = "$Revision: 1.13 $";
+static char *revision = "$Revision: 1.20.6.1 $";
 
 /* ------------------------------------------------------------- */
 
@@ -507,7 +535,7 @@
 	struct sk_buff *skb;
 
 	unsigned ApplId;
-	signed MsgLen;
+	unsigned MsgLen;
 	unsigned DataB3Len;
 	unsigned NCCI;
 	unsigned WindowSize;
@@ -593,25 +621,29 @@
 		ctrl->ready(ctrl);
 		break;
 
-        case RECEIVE_TASK_READY:
+	case RECEIVE_TASK_READY:
 		ApplId = (unsigned) b1_get_word(card->port);
 		MsgLen = b1_get_slice(card->port, card->msgbuf);
-		card->msgbuf[MsgLen--] = 0;
-		while (    MsgLen >= 0
-		       && (   card->msgbuf[MsgLen] == '\n'
-			   || card->msgbuf[MsgLen] == '\r'))
-			card->msgbuf[MsgLen--] = 0;
+		card->msgbuf[MsgLen] = 0;
+		while (    MsgLen > 0
+		       && (   card->msgbuf[MsgLen-1] == '\n'
+			   || card->msgbuf[MsgLen-1] == '\r')) {
+			card->msgbuf[MsgLen-1] = 0;
+			MsgLen--;
+		}
 		printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
 				card->name, ApplId, card->msgbuf);
 		break;
 
-        case RECEIVE_DEBUGMSG:
+	case RECEIVE_DEBUGMSG:
 		MsgLen = b1_get_slice(card->port, card->msgbuf);
-		card->msgbuf[MsgLen--] = 0;
-		while (    MsgLen >= 0
-		       && (   card->msgbuf[MsgLen] == '\n'
-			   || card->msgbuf[MsgLen] == '\r'))
-			card->msgbuf[MsgLen--] = 0;
+		card->msgbuf[MsgLen] = 0;
+		while (    MsgLen > 0
+		       && (   card->msgbuf[MsgLen-1] == '\n'
+			   || card->msgbuf[MsgLen-1] == '\r')) {
+			card->msgbuf[MsgLen-1] = 0;
+			MsgLen--;
+		}
 		printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
 		break;
 
@@ -714,12 +746,7 @@
 
 EXPORT_SYMBOL(b1ctl_read_proc);
 
-#ifdef MODULE
-#define b1_init init_module
-void cleanup_module(void);
-#endif
-
-int b1_init(void)
+static int __init b1_init(void)
 {
 	char *p;
 	char rev[10];
@@ -736,8 +763,9 @@
 	return 0;
 }
 
-#ifdef MODULE
-void cleanup_module(void)
+static void  b1_exit(void)
 {
 }
-#endif
+
+module_init(b1_init);
+module_exit(b1_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/avmb1/b1dma.c linux.19p18/drivers/isdn/avmb1/b1dma.c
--- linux.vanilla/drivers/isdn/avmb1/b1dma.c	Mon Dec 11 22:12:45 2000
+++ linux.19p18/drivers/isdn/avmb1/b1dma.c	Wed Feb 14 14:28:52 2001
@@ -1,11 +1,40 @@
 /*
- * $Id: b1dma.c,v 1.3 2000/02/26 01:00:53 keil Exp $
+ * $Id: b1dma.c,v 1.11.6.1 2001/02/13 11:43:29 kai Exp $
  * 
  * Common module for AVM B1 cards that support dma with AMCC
  * 
  * (c) Copyright 2000 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: b1dma.c,v $
+ * Revision 1.11.6.1  2001/02/13 11:43:29  kai
+ * more compatility changes for 2.2.19
+ *
+ * Revision 1.11  2000/11/19 17:02:47  kai
+ * compatibility cleanup - part 3
+ *
+ * Revision 1.10  2000/11/19 17:01:53  kai
+ * compatibility cleanup - part 2
+ *
+ * Revision 1.9  2000/11/01 14:05:02  calle
+ * - use module_init/module_exit from linux/init.h.
+ * - all static struct variables are initialized with "membername:" now.
+ * - avm_cs.c, let it work with newer pcmcia-cs.
+ *
+ * Revision 1.8  2000/10/10 17:44:19  kai
+ * changes from/for 2.2.18
+ *
+ * Revision 1.7  2000/08/04 12:20:08  calle
+ * - Fix unsigned/signed warning in the right way ...
+ *
+ * Revision 1.6  2000/06/29 13:59:06  calle
+ * Bugfix: reinit txdma without interrupt will confuse some AMCC chips.
+ *
+ * Revision 1.5  2000/06/19 16:51:53  keil
+ * don't free skb in irq context
+ *
+ * Revision 1.4  2000/04/03 16:38:05  calle
+ * made suppress_pollack static.
+ *
  * Revision 1.3  2000/02/26 01:00:53  keil
  * changes from 2.3.47
  *
@@ -28,13 +57,14 @@
 #include <linux/ioport.h>
 #include <linux/capi.h>
 #include <asm/io.h>
+#include <linux/init.h>
 #include <asm/uaccess.h>
 #include "capilli.h"
 #include "avmcard.h"
 #include "capicmd.h"
 #include "capiutil.h"
 
-static char *revision = "$Revision: 1.3 $";
+static char *revision = "$Revision: 1.11.6.1 $";
 
 /* ------------------------------------------------------------- */
 
@@ -462,8 +492,7 @@
 	struct capi_ctr *ctrl = cinfo->capi_ctrl;
 	struct sk_buff *skb;
 	void *p = dma->recvbuf+4;
-	__u32 ApplId, DataB3Len, NCCI, WindowSize;
-	__s32 MsgLen;
+	__u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize;
 	__u8 b1cmd =  _get_byte(&p);
 
 #ifdef CONFIG_B1DMA_DEBUG
@@ -552,22 +581,26 @@
 	case RECEIVE_TASK_READY:
 		ApplId = (unsigned) _get_word(&p);
 		MsgLen = _get_slice(&p, card->msgbuf);
-		card->msgbuf[MsgLen--] = 0;
-		while (    MsgLen >= 0
-		       && (   card->msgbuf[MsgLen] == '\n'
-			   || card->msgbuf[MsgLen] == '\r'))
-			card->msgbuf[MsgLen--] = 0;
+		card->msgbuf[MsgLen] = 0;
+		while (    MsgLen > 0
+		       && (   card->msgbuf[MsgLen-1] == '\n'
+			   || card->msgbuf[MsgLen-1] == '\r')) {
+			card->msgbuf[MsgLen-1] = 0;
+			MsgLen--;
+		}
 		printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
 				card->name, ApplId, card->msgbuf);
 		break;
 
 	case RECEIVE_DEBUGMSG:
 		MsgLen = _get_slice(&p, card->msgbuf);
-		card->msgbuf[MsgLen--] = 0;
-		while (    MsgLen >= 0
-		       && (   card->msgbuf[MsgLen] == '\n'
-			   || card->msgbuf[MsgLen] == '\r'))
-			card->msgbuf[MsgLen--] = 0;
+		card->msgbuf[MsgLen] = 0;
+		while (    MsgLen > 0
+		       && (   card->msgbuf[MsgLen-1] == '\n'
+			   || card->msgbuf[MsgLen-1] == '\r')) {
+			card->msgbuf[MsgLen-1] = 0;
+			MsgLen--;
+		}
 		printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
 		break;
 
@@ -613,11 +646,6 @@
 	if ((status & TX_TC_INT) != 0) {
 		card->csr &= ~EN_TX_TC_INT;
 	        b1dma_dispatch_tx(card);
-	} else if (card->csr & EN_TX_TC_INT) {
-		if (b1dmainmeml(card->mbase+AMCC_TXLEN) == 0) {
-			card->csr &= ~EN_TX_TC_INT;
-			b1dma_dispatch_tx(card);
-		}
 	}
 	b1dmaoutmeml(card->mbase+AMCC_INTCSR, card->csr);
 }
@@ -959,11 +987,6 @@
 EXPORT_SYMBOL(b1dma_send_message);
 EXPORT_SYMBOL(b1dmactl_read_proc);
 
-#ifdef MODULE
-#define b1dma_init init_module
-void cleanup_module(void);
-#endif
-
 int b1dma_init(void)
 {
 	char *p;
@@ -981,8 +1004,9 @@
 	return 0;
 }
 
-#ifdef MODULE
-void cleanup_module(void)
+void b1dma_exit(void)
 {
 }
-#endif
+
+module_init(b1dma_init);
+module_exit(b1dma_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/avmb1/b1isa.c linux.19p18/drivers/isdn/avmb1/b1isa.c
--- linux.vanilla/drivers/isdn/avmb1/b1isa.c	Fri Apr 21 12:46:07 2000
+++ linux.19p18/drivers/isdn/avmb1/b1isa.c	Wed Feb 14 14:28:52 2001
@@ -1,11 +1,27 @@
 /*
- * $Id: b1isa.c,v 1.7 2000/02/02 18:36:03 calle Exp $
+ * $Id: b1isa.c,v 1.10.6.1 2001/02/13 11:43:29 kai Exp $
  * 
  * Module for AVM B1 ISA-card.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: b1isa.c,v $
+ * Revision 1.10.6.1  2001/02/13 11:43:29  kai
+ * more compatility changes for 2.2.19
+ *
+ * Revision 1.10  2000/11/23 20:45:14  kai
+ * fixed module_init/exit stuff
+ * Note: compiled-in kernel doesn't work pre 2.2.18 anymore.
+ *
+ * Revision 1.9  2000/11/01 14:05:02  calle
+ * - use module_init/module_exit from linux/init.h.
+ * - all static struct variables are initialized with "membername:" now.
+ * - avm_cs.c, let it work with newer pcmcia-cs.
+ *
+ * Revision 1.8  2000/04/03 13:29:24  calle
+ * make Tim Waugh happy (module unload races in 2.3.99-pre3).
+ * no real problem there, but now it is much cleaner ...
+ *
  * Revision 1.7  2000/02/02 18:36:03  calle
  * - Modules are now locked while init_module is running
  * - fixed problem with memory mapping if address is not aligned
@@ -63,13 +79,14 @@
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/capi.h>
+#include <linux/init.h>
 #include <asm/io.h>
 #include "capicmd.h"
 #include "capiutil.h"
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.7 $";
+static char *revision = "$Revision: 1.10.6.1 $";
 
 /* ------------------------------------------------------------- */
 
@@ -240,31 +257,29 @@
 /* ------------------------------------------------------------- */
 
 static struct capi_driver b1isa_driver = {
-    "b1isa",
-    "0.0",
-    b1_load_firmware,
-    b1_reset_ctr,
-    b1isa_remove_ctr,
-    b1_register_appl,
-    b1_release_appl,
-    b1_send_message,
-
-    b1isa_procinfo,
-    b1ctl_read_proc,
-    0,	/* use standard driver_read_proc */
+    name: "b1isa",
+    revision: "0.0",
+    load_firmware: b1_load_firmware,
+    reset_ctr: b1_reset_ctr,
+    remove_ctr: b1isa_remove_ctr,
+    register_appl: b1_register_appl,
+    release_appl: b1_release_appl,
+    send_message: b1_send_message,
+
+    procinfo: b1isa_procinfo,
+    ctr_read_proc: b1ctl_read_proc,
+    driver_read_proc: 0,	/* use standard driver_read_proc */
 
-    b1isa_add_card,
+    add_card: b1isa_add_card,
 };
 
-#ifdef MODULE
-#define b1isa_init init_module
-void cleanup_module(void);
-#endif
-
-int b1isa_init(void)
+static int __init b1isa_init(void)
 {
 	struct capi_driver *driver = &b1isa_driver;
 	char *p;
+	int retval = 0;
+
+	MOD_INC_USE_COUNT;
 
 	if ((p = strchr(revision, ':'))) {
 		strncpy(driver->revision, p + 1, sizeof(driver->revision));
@@ -279,14 +294,16 @@
 	if (!di) {
 		printk(KERN_ERR "%s: failed to attach capi_driver\n",
 				driver->name);
-		return -EIO;
+		retval = -EIO;
 	}
-	return 0;
+	MOD_DEC_USE_COUNT;
+	return retval;
 }
 
-#ifdef MODULE
-void cleanup_module(void)
+static void  b1isa_exit(void)
 {
     detach_capi_driver(&b1isa_driver);
 }
-#endif
+
+module_init(b1isa_init);
+module_exit(b1isa_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/avmb1/b1pci.c linux.19p18/drivers/isdn/avmb1/b1pci.c
--- linux.vanilla/drivers/isdn/avmb1/b1pci.c	Fri Apr 21 12:46:07 2000
+++ linux.19p18/drivers/isdn/avmb1/b1pci.c	Wed Feb 14 14:28:52 2001
@@ -1,11 +1,54 @@
 /*
- * $Id: b1pci.c,v 1.20 2000/02/02 18:36:03 calle Exp $
+ * $Id: b1pci.c,v 1.29.6.1 2000/11/28 12:02:45 kai Exp $
  * 
  * Module for AVM B1 PCI-card.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: b1pci.c,v $
+ * Revision 1.29.6.1  2000/11/28 12:02:45  kai
+ * MODULE_DEVICE_TABLE for 2.4
+ *
+ * Revision 1.29.2.2  2000/11/26 17:47:53  kai
+ * added PCI_DEV_TABLE for 2.4
+ *
+ * Revision 1.29.2.1  2000/11/26 17:14:19  kai
+ * fix device ids
+ * also needs patches to include/linux/pci_ids.h
+ *
+ * Revision 1.29  2000/11/23 20:45:14  kai
+ * fixed module_init/exit stuff
+ * Note: compiled-in kernel doesn't work pre 2.2.18 anymore.
+ *
+ * Revision 1.28  2000/11/01 14:05:02  calle
+ * - use module_init/module_exit from linux/init.h.
+ * - all static struct variables are initialized with "membername:" now.
+ * - avm_cs.c, let it work with newer pcmcia-cs.
+ *
+ * Revision 1.27  2000/08/08 09:24:19  calle
+ * calls to pci_enable_device surounded by #ifndef COMPAT_HAS_2_2_PCI
+ *
+ * Revision 1.26  2000/07/20 10:21:21  calle
+ * Bugfix: driver will not be unregistered, if not cards were detected.
+ *         this result in an oops in kcapi.c
+ *
+ * Revision 1.25  2000/05/29 12:29:18  keil
+ * make pci_enable_dev compatible to 2.2 kernel versions
+ *
+ * Revision 1.24  2000/05/19 15:43:22  calle
+ * added calls to pci_device_start().
+ *
+ * Revision 1.23  2000/05/06 00:52:36  kai
+ * merged changes from kernel tree
+ * fixed timer and net_device->name breakage
+ *
+ * Revision 1.22  2000/04/21 13:01:33  calle
+ * Revision in b1pciv4 driver was missing.
+ *
+ * Revision 1.21  2000/04/03 13:29:24  calle
+ * make Tim Waugh happy (module unload races in 2.3.99-pre3).
+ * no real problem there, but now it is much cleaner ...
+ *
  * Revision 1.20  2000/02/02 18:36:03  calle
  * - Modules are now locked while init_module is running
  * - fixed problem with memory mapping if address is not aligned
@@ -70,22 +113,14 @@
 #include <linux/pci.h>
 #include <linux/capi.h>
 #include <asm/io.h>
+#include <linux/init.h>
+#include <linux/isdn_compat.h>
 #include "capicmd.h"
 #include "capiutil.h"
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.20 $";
-
-/* ------------------------------------------------------------- */
-
-#ifndef PCI_VENDOR_ID_AVM
-#define PCI_VENDOR_ID_AVM	0x1244
-#endif
-
-#ifndef PCI_DEVICE_ID_AVM_B1
-#define PCI_DEVICE_ID_AVM_B1	0x700
-#endif
+static char *revision = "$Revision: 1.29.6.1 $";
 
 /* ------------------------------------------------------------- */
 
@@ -252,20 +287,20 @@
 /* ------------------------------------------------------------- */
 
 static struct capi_driver b1pci_driver = {
-    "b1pci",
-    "0.0",
-    b1_load_firmware,
-    b1_reset_ctr,
-    b1pci_remove_ctr,
-    b1_register_appl,
-    b1_release_appl,
-    b1_send_message,
-
-    b1pci_procinfo,
-    b1ctl_read_proc,
-    0,	/* use standard driver_read_proc */
+    name: "b1pci",
+    revision: "0.0",
+    load_firmware: b1_load_firmware,
+    reset_ctr: b1_reset_ctr,
+    remove_ctr: b1pci_remove_ctr,
+    register_appl: b1_register_appl,
+    release_appl: b1_release_appl,
+    send_message: b1_send_message,
+
+    procinfo: b1pci_procinfo,
+    ctr_read_proc: b1ctl_read_proc,
+    driver_read_proc: 0,	/* use standard driver_read_proc */
 
-    0, /* no add_card function */
+    add_card: 0, /* no add_card function */
 };
 
 #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
@@ -320,10 +355,13 @@
 	avmctrl_info *cinfo;
 	int retval;
 
+	MOD_INC_USE_COUNT;
+
 	card = (avmcard *) kmalloc(sizeof(avmcard), GFP_ATOMIC);
 
 	if (!card) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
+	        MOD_DEC_USE_COUNT;
 		return -ENOMEM;
 	}
 	memset(card, 0, sizeof(avmcard));
@@ -331,6 +369,7 @@
 	if (!card->dma) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
 		kfree(card);
+	        MOD_DEC_USE_COUNT;
 		return -ENOMEM;
 	}
 	memset(card->dma, 0, sizeof(avmcard_dmainfo));
@@ -339,6 +378,7 @@
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
 		kfree(card->dma);
 		kfree(card);
+	        MOD_DEC_USE_COUNT;
 		return -ENOMEM;
 	}
 	memset(cinfo, 0, sizeof(avmctrl_info));
@@ -357,6 +397,7 @@
 	        kfree(card->ctrlinfo);
 		kfree(card->dma);
 		kfree(card);
+	        MOD_DEC_USE_COUNT;
 		return -EBUSY;
 	}
 
@@ -371,6 +412,7 @@
 	        kfree(card->ctrlinfo);
 		kfree(card->dma);
 		kfree(card);
+	        MOD_DEC_USE_COUNT;
 		return -EIO;
 	}
 
@@ -383,6 +425,7 @@
 	        kfree(card->ctrlinfo);
 		kfree(card->dma);
 		kfree(card);
+	        MOD_DEC_USE_COUNT;
 		return -EIO;
 	}
 	b1dma_reset(card);
@@ -399,6 +442,7 @@
 	        kfree(card->ctrlinfo);
 		kfree(card->dma);
 		kfree(card);
+	        MOD_DEC_USE_COUNT;
 		return -EBUSY;
 	}
 
@@ -411,6 +455,7 @@
 	        kfree(card->ctrlinfo);
 		kfree(card->dma);
 		kfree(card);
+	        MOD_DEC_USE_COUNT;
 		return -EBUSY;
 	}
 	card->cardnr = cinfo->capi_ctrl->cnr;
@@ -422,8 +467,6 @@
 		driver->name, card->port, card->irq,
 		card->membase, card->revision);
 
-	MOD_INC_USE_COUNT;
-
 	return 0;
 }
 
@@ -431,29 +474,24 @@
 
 
 static struct capi_driver b1pciv4_driver = {
-    "b1pciv4",
-    "0.0",
-    b1dma_load_firmware,
-    b1dma_reset_ctr,
-    b1pciv4_remove_ctr,
-    b1dma_register_appl,
-    b1dma_release_appl,
-    b1dma_send_message,
-
-    b1pciv4_procinfo,
-    b1dmactl_read_proc,
-    0,	/* use standard driver_read_proc */
+    name: "b1pciv4",
+    revision: "0.0",
+    load_firmware: b1dma_load_firmware,
+    reset_ctr: b1dma_reset_ctr,
+    remove_ctr: b1pciv4_remove_ctr,
+    register_appl: b1dma_register_appl,
+    release_appl: b1dma_release_appl,
+    send_message: b1dma_send_message,
+
+    procinfo: b1pciv4_procinfo,
+    ctr_read_proc: b1dmactl_read_proc,
+    driver_read_proc: 0,	/* use standard driver_read_proc */
 
-    0, /* no add_card function */
+    add_card: 0, /* no add_card function */
 };
 
 #endif /* CONFIG_ISDN_DRV_AVMB1_B1PCIV4 */
 
-#ifdef MODULE
-#define b1pci_init init_module
-void cleanup_module(void);
-#endif
-
 static int ncards = 0;
 
 static int add_card(struct pci_dev *dev)
@@ -469,6 +507,8 @@
 		param.membase = dev->base_address[ 0] & PCI_BASE_ADDRESS_MEM_MASK;
 		param.port = dev->base_address[ 2] & PCI_BASE_ADDRESS_IO_MASK;
 		param.irq = dev->irq;
+
+
 		printk(KERN_INFO
 		"%s: PCI BIOS reports AVM-B1 V4 at i/o %#x, irq %d, mem %#x\n",
 		driver->name, param.port, param.irq, param.membase);
@@ -486,6 +526,7 @@
 		param.membase = 0;
 		param.port = dev->base_address[ 1] & PCI_BASE_ADDRESS_IO_MASK;
 		param.irq = dev->irq;
+
 		printk(KERN_INFO
 		"%s: PCI BIOS reports AVM-B1 at i/o %#x, irq %d\n",
 		driver->name, param.port, param.irq);
@@ -499,7 +540,7 @@
 	return retval;
 }
 
-int b1pci_init(void)
+static int __init b1pci_init(void)
 {
 	struct capi_driver *driver = &b1pci_driver;
 #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
@@ -509,10 +550,18 @@
 	char *p;
 	int retval;
 
+	MOD_INC_USE_COUNT;
+
 	if ((p = strchr(revision, ':'))) {
 		strncpy(driver->revision, p + 1, sizeof(driver->revision));
 		p = strchr(driver->revision, '$');
 		*p = 0;
+#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
+	        p = strchr(revision, ':');
+		strncpy(driverv4->revision, p + 1, sizeof(driverv4->revision));
+		p = strchr(driverv4->revision, '$');
+		*p = 0;
+#endif
 	}
 
 	printk(KERN_INFO "%s: revision %s\n", driver->name, driver->revision);
@@ -522,6 +571,7 @@
 	if (!di) {
 		printk(KERN_ERR "%s: failed to attach capi_driver\n",
 				driver->name);
+		MOD_DEC_USE_COUNT;
 		return -EIO;
 	}
 
@@ -534,6 +584,7 @@
     		detach_capi_driver(driver);
 		printk(KERN_ERR "%s: failed to attach capi_driver\n",
 				driverv4->name);
+		MOD_DEC_USE_COUNT;
 		return -EIO;
 	}
 #endif
@@ -545,15 +596,18 @@
 #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
     		detach_capi_driver(driverv4);
 #endif
+		MOD_DEC_USE_COUNT;
 		return -EIO;
 	}
 
 	while ((dev = pci_find_device(PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_B1, dev))) {
 		retval = add_card(dev);
 		if (retval != 0) {
-#ifdef MODULE
-			cleanup_module();
+    			detach_capi_driver(driver);
+#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
+    			detach_capi_driver(driverv4);
 #endif
+			MOD_DEC_USE_COUNT;
 			return retval;
 		}
 		ncards++;
@@ -561,22 +615,30 @@
 	if (ncards) {
 		printk(KERN_INFO "%s: %d B1-PCI card(s) detected\n",
 				driver->name, ncards);
+		MOD_DEC_USE_COUNT;
 		return 0;
 	}
 	printk(KERN_ERR "%s: NO B1-PCI card detected\n", driver->name);
+	detach_capi_driver(driver);
+#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
+	detach_capi_driver(driverv4);
+#endif
+	MOD_DEC_USE_COUNT;
 	return -ESRCH;
 #else
 	printk(KERN_ERR "%s: kernel not compiled with PCI.\n", driver->name);
+	MOD_DEC_USE_COUNT;
 	return -EIO;
 #endif
 }
 
-#ifdef MODULE
-void cleanup_module(void)
+static void  b1pci_exit(void)
 {
     detach_capi_driver(&b1pci_driver);
 #ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4
     detach_capi_driver(&b1pciv4_driver);
 #endif
 }
-#endif
+
+module_init(b1pci_init);
+module_exit(b1pci_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/avmb1/b1pcmcia.c linux.19p18/drivers/isdn/avmb1/b1pcmcia.c
--- linux.vanilla/drivers/isdn/avmb1/b1pcmcia.c	Fri Apr 21 12:46:07 2000
+++ linux.19p18/drivers/isdn/avmb1/b1pcmcia.c	Wed Feb 14 14:28:52 2001
@@ -1,11 +1,36 @@
 /*
- * $Id: b1pcmcia.c,v 1.7 2000/02/02 18:36:03 calle Exp $
+ * $Id: b1pcmcia.c,v 1.12.6.1 2001/02/13 11:43:29 kai Exp $
  * 
  * Module for AVM B1/M1/M2 PCMCIA-card.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: b1pcmcia.c,v $
+ * Revision 1.12.6.1  2001/02/13 11:43:29  kai
+ * more compatility changes for 2.2.19
+ *
+ * Revision 1.12  2000/11/23 20:45:14  kai
+ * fixed module_init/exit stuff
+ * Note: compiled-in kernel doesn't work pre 2.2.18 anymore.
+ *
+ * Revision 1.11  2000/11/01 14:05:02  calle
+ * - use module_init/module_exit from linux/init.h.
+ * - all static struct variables are initialized with "membername:" now.
+ * - avm_cs.c, let it work with newer pcmcia-cs.
+ *
+ * Revision 1.10  2000/05/06 00:52:36  kai
+ * merged changes from kernel tree
+ * fixed timer and net_device->name breakage
+ *
+ * Revision 1.9  2000/04/03 13:29:24  calle
+ * make Tim Waugh happy (module unload races in 2.3.99-pre3).
+ * no real problem there, but now it is much cleaner ...
+ *
+ * Revision 1.8  2000/03/06 18:00:23  calle
+ * - Middleware extention now working with 2.3.49 (capifs).
+ * - Fixed typos in debug section of capi.c
+ * - Bugfix: Makefile corrected for b1pcmcia.c
+ *
  * Revision 1.7  2000/02/02 18:36:03  calle
  * - Modules are now locked while init_module is running
  * - fixed problem with memory mapping if address is not aligned
@@ -62,6 +87,7 @@
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
+#include <linux/init.h>
 #include <asm/io.h>
 #include <linux/capi.h>
 #include <linux/b1pcmcia.h>
@@ -70,7 +96,7 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.7 $";
+static char *revision = "$Revision: 1.12.6.1 $";
 
 /* ------------------------------------------------------------- */
 
@@ -232,20 +258,20 @@
 /* ------------------------------------------------------------- */
 
 static struct capi_driver b1pcmcia_driver = {
-    "b1pcmcia",
-    "0.0",
-    b1_load_firmware,
-    b1_reset_ctr,
-    b1pcmcia_remove_ctr,
-    b1_register_appl,
-    b1_release_appl,
-    b1_send_message,
-
-    b1pcmcia_procinfo,
-    b1ctl_read_proc,
-    0,	/* use standard driver_read_proc */
+    name: "b1pcmcia",
+    revision: "0.0",
+    load_firmware: b1_load_firmware,
+    reset_ctr: b1_reset_ctr,
+    remove_ctr: b1pcmcia_remove_ctr,
+    register_appl: b1_register_appl,
+    release_appl: b1_release_appl,
+    send_message: b1_send_message,
+
+    procinfo: b1pcmcia_procinfo,
+    ctr_read_proc: b1ctl_read_proc,
+    driver_read_proc: 0,	/* use standard driver_read_proc */
 
-    0,
+    add_card: 0,
 };
 
 /* ------------------------------------------------------------- */
@@ -287,15 +313,13 @@
 
 /* ------------------------------------------------------------- */
 
-#ifdef MODULE
-#define b1pcmcia_init init_module
-void cleanup_module(void);
-#endif
-
-int b1pcmcia_init(void)
+static int __init b1pcmcia_init(void)
 {
 	struct capi_driver *driver = &b1pcmcia_driver;
 	char *p;
+	int retval = 0;
+
+	MOD_INC_USE_COUNT;
 
 	if ((p = strchr(revision, ':'))) {
 		strncpy(driver->revision, p + 1, sizeof(driver->revision));
@@ -310,14 +334,16 @@
 	if (!di) {
 		printk(KERN_ERR "%s: failed to attach capi_driver\n",
 				driver->name);
-		return -EIO;
+		retval = -EIO;
 	}
-	return 0;
+	MOD_DEC_USE_COUNT;
+	return retval;
 }
 
-#ifdef MODULE
-void cleanup_module(void)
+static void  b1pcmcia_exit(void)
 {
     detach_capi_driver(&b1pcmcia_driver);
 }
-#endif
+
+module_init(b1pcmcia_init);
+module_exit(b1pcmcia_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/avmb1/c4.c linux.19p18/drivers/isdn/avmb1/c4.c
--- linux.vanilla/drivers/isdn/avmb1/c4.c	Mon Dec 11 22:12:45 2000
+++ linux.19p18/drivers/isdn/avmb1/c4.c	Wed Feb 14 14:28:52 2001
@@ -1,11 +1,75 @@
 /*
- * $Id: c4.c,v 1.5 2000/03/16 15:21:03 calle Exp $
+ * $Id: c4.c,v 1.20.6.2 2001/02/13 11:43:29 kai Exp $
  * 
  * Module for AVM C4 card.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: c4.c,v $
+ * Revision 1.20.6.2  2001/02/13 11:43:29  kai
+ * more compatility changes for 2.2.19
+ *
+ * Revision 1.20.6.1  2000/11/28 12:02:45  kai
+ * MODULE_DEVICE_TABLE for 2.4
+ *
+ * Revision 1.20.2.2  2000/11/26 17:47:53  kai
+ * added PCI_DEV_TABLE for 2.4
+ *
+ * Revision 1.20.2.1  2000/11/26 17:14:19  kai
+ * fix device ids
+ * also needs patches to include/linux/pci_ids.h
+ *
+ * Revision 1.20  2000/11/23 20:45:14  kai
+ * fixed module_init/exit stuff
+ * Note: compiled-in kernel doesn't work pre 2.2.18 anymore.
+ *
+ * Revision 1.19  2000/11/19 17:02:47  kai
+ * compatibility cleanup - part 3
+ *
+ * Revision 1.18  2000/11/01 14:05:02  calle
+ * - use module_init/module_exit from linux/init.h.
+ * - all static struct variables are initialized with "membername:" now.
+ * - avm_cs.c, let it work with newer pcmcia-cs.
+ *
+ * Revision 1.17  2000/10/10 17:44:19  kai
+ * changes from/for 2.2.18
+ *
+ * Revision 1.16  2000/08/20 07:30:13  keil
+ * changes for 2.4
+ *
+ * Revision 1.15  2000/08/08 09:24:19  calle
+ * calls to pci_enable_device surounded by #ifndef COMPAT_HAS_2_2_PCI
+ *
+ * Revision 1.14  2000/08/04 12:20:08  calle
+ * - Fix unsigned/signed warning in the right way ...
+ *
+ * Revision 1.13  2000/07/20 10:21:21  calle
+ * Bugfix: driver will not be unregistered, if not cards were detected.
+ *         this result in an oops in kcapi.c
+ *
+ * Revision 1.12  2000/06/19 16:51:53  keil
+ * don't free skb in irq context
+ *
+ * Revision 1.11  2000/06/19 15:11:24  keil
+ * avoid use of freed structs
+ * changes from 2.4.0-ac21
+ *
+ * Revision 1.10  2000/05/29 12:29:18  keil
+ * make pci_enable_dev compatible to 2.2 kernel versions
+ *
+ * Revision 1.9  2000/05/19 15:43:22  calle
+ * added calls to pci_device_start().
+ *
+ * Revision 1.8  2000/04/03 16:38:05  calle
+ * made suppress_pollack static.
+ *
+ * Revision 1.7  2000/04/03 13:29:24  calle
+ * make Tim Waugh happy (module unload races in 2.3.99-pre3).
+ * no real problem there, but now it is much cleaner ...
+ *
+ * Revision 1.6  2000/03/17 12:21:08  calle
+ * send patchvalues now working.
+ *
  * Revision 1.5  2000/03/16 15:21:03  calle
  * Bugfix in c4_remove: loop 5 times instead of 4 :-(
  *
@@ -35,7 +99,9 @@
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/pci.h>
+#include <linux/isdn_compat.h>
 #include <linux/capi.h>
+#include <linux/init.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include "capicmd.h"
@@ -43,35 +109,16 @@
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.5 $";
+static char *revision = "$Revision: 1.20.6.2 $";
 
 #undef CONFIG_C4_DEBUG
 #undef CONFIG_C4_POLLDEBUG
 
 /* ------------------------------------------------------------- */
 
-#ifndef PCI_VENDOR_ID_DEC
-#define PCI_VENDOR_ID_DEC	0x1011
-#endif
-
-#ifndef PCI_DEVICE_ID_DEC_21285
-#define PCI_DEVICE_ID_DEC_21285	0x1065
-#endif
-
-#ifndef PCI_VENDOR_ID_AVM
-#define PCI_VENDOR_ID_AVM	0x1244
-#endif
-
-#ifndef PCI_DEVICE_ID_AVM_C4
-#define PCI_DEVICE_ID_AVM_C4	0x0800
-#endif
-
-/* ------------------------------------------------------------- */
-
-static int suppress_pollack = 0;
+static int suppress_pollack;
 
 MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
-
 MODULE_PARM(suppress_pollack, "0-1i");
 
 /* ------------------------------------------------------------- */
@@ -535,8 +582,7 @@
 	avmctrl_info *cinfo;
 	struct sk_buff *skb;
 	void *p = dma->recvbuf;
-	__u32 ApplId, DataB3Len, NCCI, WindowSize;
-	__s32 MsgLen;
+	__u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize;
 	__u8 b1cmd =  _get_byte(&p);
 	__u32 cidx;
 
@@ -655,22 +701,26 @@
 	case RECEIVE_TASK_READY:
 		ApplId = (unsigned) _get_word(&p);
 		MsgLen = _get_slice(&p, card->msgbuf);
-		card->msgbuf[MsgLen--] = 0;
-		while (    MsgLen >= 0
-		       && (   card->msgbuf[MsgLen] == '\n'
-			   || card->msgbuf[MsgLen] == '\r'))
-			card->msgbuf[MsgLen--] = 0;
+		card->msgbuf[MsgLen] = 0;
+		while (    MsgLen > 0
+		       && (   card->msgbuf[MsgLen-1] == '\n'
+			   || card->msgbuf[MsgLen-1] == '\r')) {
+			card->msgbuf[MsgLen-1] = 0;
+			MsgLen--;
+		}
 		printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
 				card->name, ApplId, card->msgbuf);
 		break;
 
 	case RECEIVE_DEBUGMSG:
 		MsgLen = _get_slice(&p, card->msgbuf);
-		card->msgbuf[MsgLen--] = 0;
-		while (    MsgLen >= 0
-		       && (   card->msgbuf[MsgLen] == '\n'
-			   || card->msgbuf[MsgLen] == '\r'))
-			card->msgbuf[MsgLen--] = 0;
+		card->msgbuf[MsgLen] = 0;
+		while (    MsgLen > 0
+		       && (   card->msgbuf[MsgLen-1] == '\n'
+			   || card->msgbuf[MsgLen-1] == '\r')) {
+			card->msgbuf[MsgLen-1] = 0;
+			MsgLen--;
+		}
 		printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
 		break;
 
@@ -774,45 +824,78 @@
 	c4_dispatch_tx(card);
 }
 
-static int c4_send_config(avmcard *card, capiloaddatapart * config)
+static int queue_sendconfigword(avmcard *card, __u32 val)
 {
 	struct sk_buff *skb;
-	__u8 val[sizeof(__u32)];
 	void *p;
-	unsigned char *dp;
-	int left, retval;
-	
-	skb = alloc_skb(12 + ((config->len+3)/4)*5, GFP_ATOMIC);
+
+	skb = alloc_skb(3+4, GFP_ATOMIC);
 	if (!skb) {
-		printk(KERN_CRIT "%s: no memory, can't send config.\n",
+		printk(KERN_CRIT "%s: no memory, send config\n",
 					card->name);
-		return	-ENOMEM;
+		return -ENOMEM;
 	}
 	p = skb->data;
 	_put_byte(&p, 0);
 	_put_byte(&p, 0);
 	_put_byte(&p, SEND_CONFIG);
-	_put_word(&p, 1);
+	_put_word(&p, val);
+	skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+
+	skb_queue_tail(&card->dma->send_queue, skb);
+	c4_dispatch_tx(card);
+	return 0;
+}
+
+static int queue_sendconfig(avmcard *card, char cval[4])
+{
+	struct sk_buff *skb;
+	void *p;
+
+	skb = alloc_skb(3+4, GFP_ATOMIC);
+	if (!skb) {
+		printk(KERN_CRIT "%s: no memory, send config\n",
+					card->name);
+		return -ENOMEM;
+	}
+	p = skb->data;
+	_put_byte(&p, 0);
+	_put_byte(&p, 0);
 	_put_byte(&p, SEND_CONFIG);
-	_put_word(&p, config->len);	/* 12 */
+	_put_byte(&p, cval[0]);
+	_put_byte(&p, cval[1]);
+	_put_byte(&p, cval[2]);
+	_put_byte(&p, cval[3]);
+	skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
+
+	skb_queue_tail(&card->dma->send_queue, skb);
+	c4_dispatch_tx(card);
+	return 0;
+}
+
+static int c4_send_config(avmcard *card, capiloaddatapart * config)
+{
+	__u8 val[4];
+	unsigned char *dp;
+	int left, retval;
+	
+	if ((retval = queue_sendconfigword(card, 1)) != 0)
+		return retval;
+	if ((retval = queue_sendconfigword(card, config->len)) != 0)
+		return retval;
 
 	dp = config->data;
 	left = config->len;
 	while (left >= sizeof(__u32)) {
 	        if (config->user) {
 			retval = copy_from_user(val, dp, sizeof(val));
-			if (retval) {
-				dev_kfree_skb(skb);
+			if (retval)
 				return -EFAULT;
-			}
 		} else {
 			memcpy(val, dp, sizeof(val));
 		}
-		_put_byte(&p, SEND_CONFIG);
-		_put_byte(&p, val[0]);
-		_put_byte(&p, val[1]);
-		_put_byte(&p, val[2]);
-		_put_byte(&p, val[3]);
+		if ((retval = queue_sendconfig(card, val)) != 0)
+			return retval;
 		left -= sizeof(val);
 		dp += sizeof(val);
 	}
@@ -820,25 +903,15 @@
 		memset(val, 0, sizeof(val));
 		if (config->user) {
 			retval = copy_from_user(&val, dp, left);
-			if (retval) {
-				dev_kfree_skb(skb);
+			if (retval)
 				return -EFAULT;
-			}
 		} else {
 			memcpy(&val, dp, left);
 		}
-		_put_byte(&p, SEND_CONFIG);
-		_put_byte(&p, val[0]);
-		_put_byte(&p, val[1]);
-		_put_byte(&p, val[2]);
-		_put_byte(&p, val[3]);
+		if ((retval = queue_sendconfig(card, val)) != 0)
+			return retval;
 	}
 
-	skb_put(skb, (__u8 *)p - (__u8 *)skb->data);
-
-	skb_queue_tail(&card->dma->send_queue, skb);
-	c4_dispatch_tx(card);
-
 	return 0;
 }
 
@@ -875,8 +948,15 @@
 	c4outmeml(card->mbase+DOORBELL, DBELL_UP_ARM);
 	restore_flags(flags);
 
-	if (data->configuration.len > 0 && data->configuration.data)
-		c4_send_config(card, &data->configuration);
+	if (data->configuration.len > 0 && data->configuration.data) {
+		retval = c4_send_config(card, &data->configuration);
+		if (retval) {
+			printk(KERN_ERR "%s: failed to set config!!\n",
+					card->name);
+			c4_reset(card);
+			return retval;
+		}
+	}
 
         c4_send_init(card);
 
@@ -910,8 +990,10 @@
 
         for (i=0; i < 4; i++) {
 		cinfo = &card->ctrlinfo[i];
-		if (cinfo->capi_ctrl)
+		if (cinfo->capi_ctrl) {
 			di->detach_ctr(cinfo->capi_ctrl);
+			cinfo->capi_ctrl = NULL;
+		}
 	}
 
 	free_irq(card->irq, card);
@@ -1124,7 +1206,6 @@
         cinfo = (avmctrl_info *) kmalloc(sizeof(avmctrl_info)*4, GFP_ATOMIC);
 	if (!cinfo) {
 		printk(KERN_WARNING "%s: no memory.\n", driver->name);
-	        kfree(card->ctrlinfo);
 		kfree(card->dma);
 		kfree(card);
 	        MOD_DEC_USE_COUNT;
@@ -1231,57 +1312,33 @@
 /* ------------------------------------------------------------- */
 
 static struct capi_driver c4_driver = {
-    "c4",
-    "0.0",
-    c4_load_firmware,
-    c4_reset_ctr,
-    c4_remove_ctr,
-    c4_register_appl,
-    c4_release_appl,
-    c4_send_message,
-
-    c4_procinfo,
-    c4_read_proc,
-    0,	/* use standard driver_read_proc */
+    name: "c4",
+    revision: "0.0",
+    load_firmware: c4_load_firmware,
+    reset_ctr: c4_reset_ctr,
+    remove_ctr: c4_remove_ctr,
+    register_appl: c4_register_appl,
+    release_appl: c4_release_appl,
+    send_message: c4_send_message,
+
+    procinfo: c4_procinfo,
+    ctr_read_proc: c4_read_proc,
+    driver_read_proc: 0,	/* use standard driver_read_proc */
 
-    0, /* no add_card function */
+    add_card: 0, /* no add_card function */
 };
 
-#ifdef MODULE
-#define c4_init init_module
-void cleanup_module(void);
-#endif
-
-#ifndef PCI_ANY_ID
-#define PCI_ANY_ID (~0)
-#endif
-
-static struct pci_dev *
-pci_find_subsys(unsigned int vendor, unsigned int device,
-		unsigned int ss_vendor, unsigned int ss_device,
-		struct pci_dev *from)
-{
-	unsigned short subsystem_vendor, subsystem_device;
-
-	while ((from = pci_find_device(vendor, device, from))) {
-		pci_read_config_word(from, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor);
-		pci_read_config_word(from, PCI_SUBSYSTEM_ID, &subsystem_device);
-		if ((ss_vendor == PCI_ANY_ID || subsystem_vendor == ss_vendor) &&
-		    (ss_device == PCI_ANY_ID || subsystem_device == ss_device))
-			return from;
-	}
-	return NULL;
-}
-
 static int ncards = 0;
 
-int c4_init(void)
+static int __init c4_init(void)
 {
 	struct capi_driver *driver = &c4_driver;
 	struct pci_dev *dev = NULL;
 	char *p;
 	int retval;
 
+	MOD_INC_USE_COUNT;
+
 	if ((p = strchr(revision, ':'))) {
 		strncpy(driver->revision, p + 1, sizeof(driver->revision));
 		p = strchr(driver->revision, '$');
@@ -1295,6 +1352,7 @@
 	if (!di) {
 		printk(KERN_ERR "%s: failed to attach capi_driver\n",
 				driver->name);
+		MOD_DEC_USE_COUNT;
 		return -EIO;
 	}
 
@@ -1302,6 +1360,7 @@
 	if (!pci_present()) {
 		printk(KERN_ERR "%s: no PCI bus present\n", driver->name);
     		detach_capi_driver(driver);
+		MOD_DEC_USE_COUNT;
 		return -EIO;
 	}
 
@@ -1314,6 +1373,7 @@
 		param.irq = dev->irq;
 		param.membase = dev->base_address[ 0] & PCI_BASE_ADDRESS_MEM_MASK;
 
+
 		printk(KERN_INFO
 			"%s: PCI BIOS reports AVM-C4 at i/o %#x, irq %d, mem %#x\n",
 			driver->name, param.port, param.irq, param.membase);
@@ -1322,9 +1382,8 @@
 		        printk(KERN_ERR
 			"%s: no AVM-C4 at i/o %#x, irq %d detected, mem %#x\n",
 			driver->name, param.port, param.irq, param.membase);
-#ifdef MODULE
-			cleanup_module();
-#endif
+    			detach_capi_driver(driver);
+			MOD_DEC_USE_COUNT;
 			return retval;
 		}
 		ncards++;
@@ -1332,19 +1391,24 @@
 	if (ncards) {
 		printk(KERN_INFO "%s: %d C4 card(s) detected\n",
 				driver->name, ncards);
+		MOD_DEC_USE_COUNT;
 		return 0;
 	}
 	printk(KERN_ERR "%s: NO C4 card detected\n", driver->name);
+	detach_capi_driver(driver);
+	MOD_DEC_USE_COUNT;
 	return -ESRCH;
 #else
 	printk(KERN_ERR "%s: kernel not compiled with PCI.\n", driver->name);
+	MOD_DEC_USE_COUNT;
 	return -EIO;
 #endif
 }
 
-#ifdef MODULE
-void cleanup_module(void)
+static void  c4_exit(void)
 {
     detach_capi_driver(&c4_driver);
 }
-#endif
+
+module_init(c4_init);
+module_exit(c4_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/avmb1/capi.c linux.19p18/drivers/isdn/avmb1/capi.c
--- linux.vanilla/drivers/isdn/avmb1/capi.c	Sun Jun 11 21:44:13 2000
+++ linux.19p18/drivers/isdn/avmb1/capi.c	Wed Feb 14 14:28:52 2001
@@ -1,11 +1,120 @@
 /*
- * $Id: capi.c,v 1.23 2000/02/26 01:00:53 keil Exp $
+ * $Id: capi.c,v 1.44.6.5 2001/02/13 11:43:29 kai Exp $
  *
  * CAPI 2.0 Interface for Linux
  *
  * Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
  *
  * $Log: capi.c,v $
+ * Revision 1.44.6.5  2001/02/13 11:43:29  kai
+ * more compatility changes for 2.2.19
+ *
+ * Revision 1.44.6.4  2001/02/10 14:41:20  kai
+ * Changes from kernel tree
+ *
+ * Revision 1.44.6.3  2000/12/17 22:45:08  kai
+ * That's hopefully it for test13-4
+ *
+ * Revision 1.44.6.2  2000/12/14 23:04:12  kai
+ * Makefile changes and the like for 2.4.0-test13-pre1
+ * No compatiblity code for older kernels yet, but note the branch
+ *
+ * Revision 1.45  2000/12/02 19:47:29  kai
+ * Change the Makefiles to new style.
+ * There may be problems there that I missed, so this shouldn't go into
+ * an offical kernel any time soon.
+ * However, if I didn't commit it, we wouldn't find the bugs...
+ *
+ * Revision 1.44  2000/11/25 17:00:59  kai
+ * compatibility cleanup - final part for the time being
+ *
+ * Revision 1.43  2000/11/23 20:45:14  kai
+ * fixed module_init/exit stuff
+ * Note: compiled-in kernel doesn't work pre 2.2.18 anymore.
+ *
+ * Revision 1.42  2000/11/19 17:03:55  kai
+ * compatibility cleanup - part 5
+ *
+ * Revision 1.41  2000/11/01 14:05:02  calle
+ * - use module_init/module_exit from linux/init.h.
+ * - all static struct variables are initialized with "membername:" now.
+ * - avm_cs.c, let it work with newer pcmcia-cs.
+ *
+ * Revision 1.40  2000/10/24 15:15:04  calle
+ * Workaround: pppd calls restoretty before reseting the ldisc and
+ *   ldisc "ppp_sync" didn't support this. So we call n_tty_ioctl
+ *   in the driver ioctl function. (remember: driver ioctl function is
+ *   only called if ldisc ioctl function did not handle the call)
+ *
+ * Revision 1.39  2000/07/24 13:42:50  calle
+ * - lock_kernel/unlock_kernel for _release functions. (from 2.4)
+ *
+ * Revision 1.38  2000/07/24 08:49:09  calle
+ * - Bugfix: capiminor_del_all_ack completely wrong :-(
+ *
+ * Revision 1.37  2000/07/20 10:22:27  calle
+ * - Made procfs function cleaner and removed variable "begin".
+ *
+ * Revision 1.36  2000/06/29 13:59:35  calle
+ * - call to devfs_register was wrong
+ *
+ * Revision 1.35  2000/06/19 15:11:24  keil
+ * avoid use of freed structs
+ * changes from 2.4.0-ac21
+ *
+ * Revision 1.34  2000/06/18 16:09:54  keil
+ * more changes for 2.4
+ *
+ * Revision 1.33  2000/05/18 16:35:43  calle
+ * Uaaahh. Bad memory leak fixed.
+ *
+ * Revision 1.32  2000/04/21 12:38:42  calle
+ * Bugfix: error in proc_ functions, begin-off => off-begin
+ *
+ * Revision 1.31  2000/04/03 13:29:24  calle
+ * make Tim Waugh happy (module unload races in 2.3.99-pre3).
+ * no real problem there, but now it is much cleaner ...
+ *
+ * Revision 1.30  2000/03/19 12:31:36  calle
+ * PPP over CAPI raw driver disabled for now, ppp_generic has been changed.
+ *
+ * Revision 1.29  2000/03/13 17:48:13  calle
+ * removed unused variable.
+ *
+ * Revision 1.28  2000/03/08 17:06:33  calle
+ * - changes for devfs and 2.3.49
+ * - capifs now configurable (no need with devfs)
+ * - New Middleware ioctl CAPI_NCCI_GETUNIT
+ * - Middleware again tested with 2.2.14 and 2.3.49 (with and without devfs)
+ *
+ * Revision 1.27  2000/03/06 18:00:23  calle
+ * - Middleware extention now working with 2.3.49 (capifs).
+ * - Fixed typos in debug section of capi.c
+ * - Bugfix: Makefile corrected for b1pcmcia.c
+ *
+ * Revision 1.26  2000/03/03 16:48:38  calle
+ * - Added CAPI2.0 Middleware support (CONFIG_ISDN_CAPI)
+ *   It is now possible to create a connection with a CAPI2.0 applikation
+ *   and than to handle the data connection from /dev/capi/ (capifs) and also
+ *   using async or sync PPP on this connection.
+ *   The two major device number 190 and 191 are not confirmed yet,
+ *   but I want to save the code in cvs, before I go on.
+ *
+ * Revision 1.25  2000/03/03 16:37:11  kai
+ * incorporated some cosmetic changes from the official kernel tree back
+ * into CVS
+ *
+ * Revision 1.24  2000/03/03 15:50:42  calle
+ * - kernel CAPI:
+ *   - Changed parameter "param" in capi_signal from __u32 to void *.
+ *   - rewrote notifier handling in kcapi.c
+ *   - new notifier NCCI_UP and NCCI_DOWN
+ * - User CAPI:
+ *   - /dev/capi20 is now a cloning device.
+ *   - middleware extentions prepared.
+ * - capidrv.c
+ *   - locking of list operations and module count updates.
+ *
  * Revision 1.23  2000/02/26 01:00:53  keil
  * changes from 2.3.47
  *
@@ -114,96 +223,724 @@
  *
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/sched.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/fcntl.h>
 #include <linux/fs.h>
 #include <linux/signal.h>
 #include <linux/mm.h>
+#include <linux/smp_lock.h>
 #include <linux/timer.h>
 #include <linux/wait.h>
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+#include <linux/tty.h>
+#ifdef CONFIG_PPP
+#include <linux/netdevice.h>
+#include <linux/ppp_defs.h>
+#include <linux/if_ppp.h>
+#undef CAPI_PPP_ON_RAW_DEVICE
+#endif /* CONFIG_PPP */
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
 #include <linux/skbuff.h>
 #include <linux/proc_fs.h>
 #include <linux/poll.h>
 #include <linux/capi.h>
 #include <linux/kernelcapi.h>
-
+#include <linux/init.h>
 #include "capiutil.h"
 #include "capicmd.h"
-#include "capidev.h"
+#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)
+#include "capifs.h"
+#endif
+
+static char *revision = "$Revision: 1.44.6.5 $";
 
 MODULE_AUTHOR("Carsten Paeth (calle@calle.in-berlin.de)");
 
+#undef _DEBUG_REFCOUNT		/* alloc/free and open/close debug */
+#undef _DEBUG_TTYFUNCS		/* call to tty_driver */
+#undef _DEBUG_DATAFLOW		/* data flow */
+
 /* -------- driver information -------------------------------------- */
 
 int capi_major = 68;		/* allocated */
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+int capi_rawmajor = 190;
+int capi_ttymajor = 191;
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
 
 MODULE_PARM(capi_major, "i");
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+MODULE_PARM(capi_rawmajor, "i");
+MODULE_PARM(capi_ttymajor, "i");
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+
+/* -------- defines ------------------------------------------------- */
+
+#define CAPINC_MAX_RECVQUEUE	10
+#define CAPINC_MAX_SENDQUEUE	10
+#define CAPI_MAX_BLKSIZE	2048
+
+/* -------- data structures ----------------------------------------- */
+
+struct capidev;
+struct capincci;
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+struct capiminor;
+
+struct capiminor {
+	struct capiminor *next;
+	struct capincci  *nccip;
+	unsigned int      minor;
+
+	__u16		 applid;
+	__u32		 ncci;
+	__u16		 datahandle;
+	__u16		 msgid;
+
+	struct file      *file;
+	struct tty_struct *tty;
+	int                ttyinstop;
+	int                ttyoutstop;
+	struct sk_buff    *ttyskb;
+	atomic_t           ttyopencount;
+
+	struct sk_buff_head inqueue;
+	int                 inbytes;
+	struct sk_buff_head outqueue;
+	int                 outbytes;
+
+	/* for raw device */
+	struct sk_buff_head recvqueue;
+	wait_queue_head_t recvwait;
+	wait_queue_head_t sendwait;
+	
+	/* transmit path */
+	struct datahandle_queue {
+		    struct datahandle_queue *next;
+		    __u16                    datahandle;
+	} *ackqueue;
+	int nack;
+
+};
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+
+struct capincci {
+	struct capincci *next;
+	__u32		 ncci;
+	struct capidev	*cdev;
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+	struct capiminor *minorp;
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+};
+
+struct capidev {
+	struct capidev *next;
+	struct file    *file;
+	__u16		applid;
+	__u16		errcode;
+	unsigned int    minor;
+	unsigned        userflags;
+
+	struct sk_buff_head recvqueue;
+	wait_queue_head_t recvwait;
+
+	/* Statistic */
+	unsigned long	nrecvctlpkt;
+	unsigned long	nrecvdatapkt;
+	unsigned long	nsentctlpkt;
+	unsigned long	nsentdatapkt;
+	
+	struct capincci *nccis;
+};
 
 /* -------- global variables ---------------------------------------- */
 
-static struct capidev capidevs[CAPI_MAXMINOR + 1];
-struct capi_interface *capifuncs;
+static struct capi_interface *capifuncs = 0;
+static struct capidev *capidev_openlist = 0;
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+static struct capiminor *minors = 0;
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
 
-/* -------- function called by lower level -------------------------- */
 
-static void capi_signal(__u16 applid, __u32 minor)
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+/* -------- datahandles --------------------------------------------- */
+
+int capincci_add_ack(struct capiminor *mp, __u16 datahandle)
+{
+	struct datahandle_queue *n, **pp;
+
+	n = (struct datahandle_queue *)
+	kmalloc(sizeof(struct datahandle_queue), GFP_ATOMIC);
+	if (!n) {
+	   printk(KERN_ERR "capi: alloc datahandle failed\n");
+	   return -1;
+	}
+	n->next = 0;
+	n->datahandle = datahandle;
+	for (pp = &mp->ackqueue; *pp; pp = &(*pp)->next) ;
+	*pp = n;
+	mp->nack++;
+	return 0;
+}
+
+int capiminor_del_ack(struct capiminor *mp, __u16 datahandle)
+{
+	struct datahandle_queue **pp, *p;
+
+	for (pp = &mp->ackqueue; *pp; pp = &(*pp)->next) {
+ 		if ((*pp)->datahandle == datahandle) {
+			p = *pp;
+			*pp = (*pp)->next;
+		        kfree(p);
+			mp->nack--;
+			return 0;
+		}
+	}
+	return -1;
+}
+
+void capiminor_del_all_ack(struct capiminor *mp)
+{
+	struct datahandle_queue **pp, *p;
+
+	pp = &mp->ackqueue;
+	while (*pp) {
+		p = *pp;
+		*pp = (*pp)->next;
+		kfree(p);
+		mp->nack--;
+	}
+}
+
+
+/* -------- struct capiminor ---------------------------------------- */
+
+struct capiminor *capiminor_alloc(__u16 applid, __u32 ncci)
+{
+	struct capiminor *mp, **pp;
+        unsigned int minor = 0;
+
+	MOD_INC_USE_COUNT;
+	mp = (struct capiminor *)kmalloc(sizeof(struct capiminor), GFP_ATOMIC);
+	if (!mp) {
+		MOD_DEC_USE_COUNT;
+		printk(KERN_ERR "capi: can't alloc capiminor\n");
+		return 0;
+	}
+#ifdef _DEBUG_REFCOUNT
+	printk(KERN_DEBUG "capiminor_alloc %d\n", GET_USE_COUNT(&__this_module));
+#endif
+	memset(mp, 0, sizeof(struct capiminor));
+	mp->applid = applid;
+	mp->ncci = ncci;
+	mp->msgid = 0;
+	atomic_set(&mp->ttyopencount,0);
+
+	skb_queue_head_init(&mp->inqueue);
+	skb_queue_head_init(&mp->outqueue);
+
+	skb_queue_head_init(&mp->recvqueue);
+	init_waitqueue_head(&mp->recvwait);
+	init_waitqueue_head(&mp->sendwait);
+
+	for (pp = &minors; *pp; pp = &(*pp)->next) {
+		if ((*pp)->minor < minor)
+			continue;
+		if ((*pp)->minor > minor)
+			break;
+		minor++;
+	}
+	mp->minor = minor;
+	mp->next = *pp;
+	*pp = mp;
+	return mp;
+}
+
+void capiminor_free(struct capiminor *mp)
+{
+	struct capiminor **pp;
+	struct sk_buff *skb;
+
+	pp = &minors;
+	while (*pp) {
+		if (*pp == mp) {
+			*pp = (*pp)->next;
+			if (mp->ttyskb) kfree_skb(mp->ttyskb);
+			mp->ttyskb = 0;
+			while ((skb = skb_dequeue(&mp->recvqueue)) != 0)
+				kfree_skb(skb);
+			while ((skb = skb_dequeue(&mp->inqueue)) != 0)
+				kfree_skb(skb);
+			while ((skb = skb_dequeue(&mp->outqueue)) != 0)
+				kfree_skb(skb);
+			capiminor_del_all_ack(mp);
+			kfree(mp);
+			MOD_DEC_USE_COUNT;
+#ifdef _DEBUG_REFCOUNT
+			printk(KERN_DEBUG "capiminor_free %d\n", GET_USE_COUNT(&__this_module));
+#endif
+			return;
+		} else {
+			pp = &(*pp)->next;
+		}
+	}
+}
+
+struct capiminor *capiminor_find(unsigned int minor)
+{
+	struct capiminor *p;
+	for (p = minors; p && p->minor != minor; p = p->next)
+		;
+	return p;
+}
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+
+/* -------- struct capincci ----------------------------------------- */
+
+static struct capincci *capincci_alloc(struct capidev *cdev, __u32 ncci)
+{
+	struct capincci *np, **pp;
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+	struct capiminor *mp = 0;
+	kdev_t kdev;
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+
+	np = (struct capincci *)kmalloc(sizeof(struct capincci), GFP_ATOMIC);
+	if (!np)
+		return 0;
+	memset(np, 0, sizeof(struct capincci));
+	np->ncci = ncci;
+	np->cdev = cdev;
+	for (pp=&cdev->nccis; *pp; pp = &(*pp)->next)
+		;
+	*pp = np;
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+	mp = 0;
+	if (cdev->userflags & CAPIFLAG_HIGHJACKING)
+		mp = np->minorp = capiminor_alloc(cdev->applid, ncci);
+	if (mp) {
+		mp->nccip = np;
+#ifdef _DEBUG_REFCOUNT
+		printk(KERN_DEBUG "set mp->nccip\n");
+#endif
+#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)
+		kdev = MKDEV(capi_rawmajor, mp->minor);
+		capifs_new_ncci('r', mp->minor, kdev);
+		kdev = MKDEV(capi_ttymajor, mp->minor);
+		capifs_new_ncci(0, mp->minor, kdev);
+#endif
+	}
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+        return np;
+}
+
+static void capincci_free(struct capidev *cdev, __u32 ncci)
+{
+	struct capincci *np, **pp;
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+	struct capiminor *mp;
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+
+	pp=&cdev->nccis;
+	while (*pp) {
+		np = *pp;
+		if (ncci == 0xffffffff || np->ncci == ncci) {
+			*pp = (*pp)->next;
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+			if ((mp = np->minorp) != 0) {
+#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)
+				capifs_free_ncci('r', mp->minor);
+				capifs_free_ncci(0, mp->minor);
+#endif
+				if (mp->tty) {
+					mp->nccip = 0;
+#ifdef _DEBUG_REFCOUNT
+					printk(KERN_DEBUG "reset mp->nccip\n");
+#endif
+					tty_hangup(mp->tty);
+				} else if (mp->file) {
+					mp->nccip = 0;
+#ifdef _DEBUG_REFCOUNT
+					printk(KERN_DEBUG "reset mp->nccip\n");
+#endif
+					wake_up_interruptible(&mp->recvwait);
+					wake_up_interruptible(&mp->sendwait);
+				} else {
+					capiminor_free(mp);
+				}
+			}
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+			kfree(np);
+			if (*pp == 0) return;
+		} else {
+			pp = &(*pp)->next;
+		}
+	}
+}
+
+struct capincci *capincci_find(struct capidev *cdev, __u32 ncci)
+{
+	struct capincci *p;
+
+	for (p=cdev->nccis; p ; p = p->next) {
+		if (p->ncci == ncci)
+			break;
+	}
+	return p;
+}
+
+/* -------- struct capidev ------------------------------------------ */
+
+static struct capidev *capidev_alloc(struct file *file)
 {
 	struct capidev *cdev;
+	struct capidev **pp;
+
+	cdev = (struct capidev *)kmalloc(sizeof(struct capidev), GFP_KERNEL);
+	if (!cdev)
+		return 0;
+	memset(cdev, 0, sizeof(struct capidev));
+	cdev->file = file;
+	cdev->minor = MINOR(file->f_dentry->d_inode->i_rdev);
+
+	skb_queue_head_init(&cdev->recvqueue);
+	init_waitqueue_head(&cdev->recvwait);
+	pp=&capidev_openlist;
+	while (*pp) pp = &(*pp)->next;
+	*pp = cdev;
+        return cdev;
+}
+
+static void capidev_free(struct capidev *cdev)
+{
+	struct capidev **pp;
+	struct sk_buff *skb;
+
+	if (cdev->applid)
+		(*capifuncs->capi_release) (cdev->applid);
+	cdev->applid = 0;
+
+	while ((skb = skb_dequeue(&cdev->recvqueue)) != 0) {
+		kfree_skb(skb);
+	}
+	
+	pp=&capidev_openlist;
+	while (*pp && *pp != cdev) pp = &(*pp)->next;
+	if (*pp)
+		*pp = cdev->next;
+
+	kfree(cdev);
+}
+
+static struct capidev *capidev_find(__u16 applid)
+{
+	struct capidev *p;
+	for (p=capidev_openlist; p; p = p->next) {
+		if (p->applid == applid)
+			break;
+	}
+	return p;
+}
+
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+/* -------- handle data queue --------------------------------------- */
+
+struct sk_buff *
+gen_data_b3_resp_for(struct capiminor *mp, struct sk_buff *skb)
+{
+	struct sk_buff *nskb;
+	nskb = alloc_skb(CAPI_DATA_B3_RESP_LEN, GFP_ATOMIC);
+	if (nskb) {
+		__u16 datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4+4+2);
+		unsigned char *s = skb_put(nskb, CAPI_DATA_B3_RESP_LEN);
+		capimsg_setu16(s, 0, CAPI_DATA_B3_RESP_LEN);
+		capimsg_setu16(s, 2, mp->applid);
+		capimsg_setu8 (s, 4, CAPI_DATA_B3);
+		capimsg_setu8 (s, 5, CAPI_RESP);
+		capimsg_setu16(s, 6, mp->msgid++);
+		capimsg_setu32(s, 8, mp->ncci);
+		capimsg_setu16(s, 12, datahandle);
+	}
+	return nskb;
+}
+
+int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb)
+{
+	struct sk_buff *nskb;
+	unsigned int datalen;
+	__u16 errcode, datahandle;
+
+	datalen = skb->len - CAPIMSG_LEN(skb->data);
+	if (mp->tty) {
+		if (mp->tty->ldisc.receive_buf == 0) {
+			printk(KERN_ERR "capi: ldisc has no receive_buf function\n");
+			return -1;
+		}
+		if (mp->ttyinstop) {
+#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
+			printk(KERN_DEBUG "capi: recv tty throttled\n");
+#endif
+			return -1;
+		}
+		if (mp->tty->ldisc.receive_room &&
+		    mp->tty->ldisc.receive_room(mp->tty) < datalen) {
+#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
+			printk(KERN_DEBUG "capi: no room in tty\n");
+#endif
+			return -1;
+		}
+		if ((nskb = gen_data_b3_resp_for(mp, skb)) == 0) {
+			printk(KERN_ERR "capi: gen_data_b3_resp failed\n");
+			return -1;
+		}
+		datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4);
+		errcode = (*capifuncs->capi_put_message)(mp->applid, nskb);
+		if (errcode != CAPI_NOERROR) {
+			printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n",
+					errcode);
+			kfree_skb(nskb);
+			return -1;
+		}
+		(void)skb_pull(skb, CAPIMSG_LEN(skb->data));
+#ifdef _DEBUG_DATAFLOW
+		printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n",
+					datahandle, skb->len);
+#endif
+		mp->tty->ldisc.receive_buf(mp->tty, skb->data, 0, skb->len);
+		kfree_skb(skb);
+		return 0;
+
+	} else if (mp->file) {
+		if (skb_queue_len(&mp->recvqueue) > CAPINC_MAX_RECVQUEUE) {
+#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
+			printk(KERN_DEBUG "capi: no room in raw queue\n");
+#endif
+			return -1;
+		}
+		if ((nskb = gen_data_b3_resp_for(mp, skb)) == 0) {
+			printk(KERN_ERR "capi: gen_data_b3_resp failed\n");
+			return -1;
+		}
+		datahandle = CAPIMSG_U16(skb->data,CAPIMSG_BASELEN+4);
+		errcode = (*capifuncs->capi_put_message)(mp->applid, nskb);
+		if (errcode != CAPI_NOERROR) {
+			printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n",
+					errcode);
+			kfree_skb(nskb);
+			return -1;
+		}
+		(void)skb_pull(skb, CAPIMSG_LEN(skb->data));
+#ifdef _DEBUG_DATAFLOW
+		printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => raw\n",
+					datahandle, skb->len);
+#endif
+		skb_queue_tail(&mp->recvqueue, skb);
+		wake_up_interruptible(&mp->recvwait);
+		return 0;
+	}
+#ifdef _DEBUG_DATAFLOW
+	printk(KERN_DEBUG "capi: currently no receiver\n");
+#endif
+	return -1;
+}
+
+void handle_minor_recv(struct capiminor *mp)
+{
+	struct sk_buff *skb;
+	while ((skb = skb_dequeue(&mp->inqueue)) != 0) {
+		unsigned int len = skb->len;
+		mp->inbytes -= len;
+		if (handle_recv_skb(mp, skb) < 0) {
+			skb_queue_head(&mp->inqueue, skb);
+			mp->inbytes += len;
+			return;
+		}
+	}
+}
+
+int handle_minor_send(struct capiminor *mp)
+{
+	struct sk_buff *skb;
+	__u16 len;
+	int count = 0;
+	__u16 errcode;
+	__u16 datahandle;
+
+	if (mp->tty && mp->ttyoutstop) {
+#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
+		printk(KERN_DEBUG "capi: send: tty stopped\n");
+#endif
+		return 0;
+	}
+
+	while ((skb = skb_dequeue(&mp->outqueue)) != 0) {
+		datahandle = mp->datahandle;
+		len = (__u16)skb->len;
+		skb_push(skb, CAPI_DATA_B3_REQ_LEN);
+		memset(skb->data, 0, CAPI_DATA_B3_REQ_LEN);
+		capimsg_setu16(skb->data, 0, CAPI_DATA_B3_REQ_LEN);
+		capimsg_setu16(skb->data, 2, mp->applid);
+		capimsg_setu8 (skb->data, 4, CAPI_DATA_B3);
+		capimsg_setu8 (skb->data, 5, CAPI_REQ);
+		capimsg_setu16(skb->data, 6, mp->msgid++);
+		capimsg_setu32(skb->data, 8, mp->ncci);	/* NCCI */
+		capimsg_setu32(skb->data, 12, (__u32) skb->data); /* Data32 */
+		capimsg_setu16(skb->data, 16, len);	/* Data length */
+		capimsg_setu16(skb->data, 18, datahandle);
+		capimsg_setu16(skb->data, 20, 0);	/* Flags */
+
+		if (capincci_add_ack(mp, datahandle) < 0) {
+			skb_pull(skb, CAPI_DATA_B3_REQ_LEN);
+			skb_queue_head(&mp->outqueue, skb);
+			return count;
+		}
+		errcode = (*capifuncs->capi_put_message) (mp->applid, skb);
+		if (errcode == CAPI_NOERROR) {
+			mp->datahandle++;
+			count++;
+			mp->outbytes -= len;
+#ifdef _DEBUG_DATAFLOW
+			printk(KERN_DEBUG "capi: DATA_B3_REQ %u len=%u\n",
+							datahandle, len);
+#endif
+			continue;
+		}
+		capiminor_del_ack(mp, datahandle);
+
+		if (errcode == CAPI_SENDQUEUEFULL) {
+			skb_pull(skb, CAPI_DATA_B3_REQ_LEN);
+			skb_queue_head(&mp->outqueue, skb);
+			break;
+		}
+
+		/* ups, drop packet */
+		printk(KERN_ERR "capi: put_message = %x\n", errcode);
+		mp->outbytes -= len;
+		kfree_skb(skb);
+	}
+	if (count)
+		wake_up_interruptible(&mp->sendwait);
+	return count;
+}
+
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+/* -------- function called by lower level -------------------------- */
+
+static void capi_signal(__u16 applid, void *param)
+{
+	struct capidev *cdev = (struct capidev *)param;
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+	struct capiminor *mp;
+	__u16 datahandle;
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+	struct capincci *np;
 	struct sk_buff *skb = 0;
+	__u32 ncci;
 
-	if (minor > CAPI_MAXMINOR || !capidevs[minor].is_registered) {
-		printk(KERN_ERR "BUG: capi_signal: illegal minor %d\n", minor);
+	(void) (*capifuncs->capi_get_message) (applid, &skb);
+	if (!skb) {
+		printk(KERN_ERR "BUG: capi_signal: no skb\n");
 		return;
 	}
-	cdev = &capidevs[minor];
-	(void) (*capifuncs->capi_get_message) (applid, &skb);
-	if (skb) {
-		skb_queue_tail(&cdev->recv_queue, skb);
-		wake_up_interruptible(&cdev->recv_wait);
+
+	if (CAPIMSG_COMMAND(skb->data) != CAPI_DATA_B3) {
+		skb_queue_tail(&cdev->recvqueue, skb);
+		wake_up_interruptible(&cdev->recvwait);
+		return;
+	}
+	ncci = CAPIMSG_CONTROL(skb->data);
+	for (np = cdev->nccis; np && np->ncci != ncci; np = np->next)
+		;
+	if (!np) {
+		printk(KERN_ERR "BUG: capi_signal: ncci not found\n");
+		skb_queue_tail(&cdev->recvqueue, skb);
+		wake_up_interruptible(&cdev->recvwait);
+		return;
+	}
+#ifndef CONFIG_ISDN_CAPI_MIDDLEWARE
+	skb_queue_tail(&cdev->recvqueue, skb);
+	wake_up_interruptible(&cdev->recvwait);
+#else /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+	mp = np->minorp;
+	if (!mp) {
+		skb_queue_tail(&cdev->recvqueue, skb);
+		wake_up_interruptible(&cdev->recvwait);
+		return;
+	}
+
+
+	if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) {
+		datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+4+2);
+#ifdef _DEBUG_DATAFLOW
+		printk(KERN_DEBUG "capi_signal: DATA_B3_IND %u len=%d\n",
+				datahandle, skb->len-CAPIMSG_LEN(skb->data));
+#endif
+		skb_queue_tail(&mp->inqueue, skb);
+		mp->inbytes += skb->len;
+		handle_minor_recv(mp);
+
+	} else if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_CONF) {
+
+		datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4);
+#ifdef _DEBUG_DATAFLOW
+		printk(KERN_DEBUG "capi_signal: DATA_B3_CONF %u 0x%x\n",
+				datahandle,
+				CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+2));
+#endif
+		kfree_skb(skb);
+		(void)capiminor_del_ack(mp, datahandle);
+		if (mp->tty) {
+			if (mp->tty->ldisc.write_wakeup)
+				mp->tty->ldisc.write_wakeup(mp->tty);
+		} else {
+			wake_up_interruptible(&mp->sendwait);
+		}
+		(void)handle_minor_send(mp);
+
 	} else {
-		printk(KERN_ERR "BUG: capi_signal: no skb\n");
+		/* ups, let capi application handle it :-) */
+		skb_queue_tail(&cdev->recvqueue, skb);
+		wake_up_interruptible(&cdev->recvwait);
 	}
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
 }
 
-/* -------- file_operations ----------------------------------------- */
+/* -------- file_operations for capidev ----------------------------- */
 
-static long long capi_llseek(struct file *file,
-			     long long offset, int origin)
+static loff_t
+capi_llseek(struct file *file, loff_t offset, int origin)
 {
 	return -ESPIPE;
 }
 
-static ssize_t capi_read(struct file *file, char *buf,
-		      size_t count, loff_t *ppos)
+static ssize_t
+capi_read(struct file *file, char *buf, size_t count, loff_t *ppos)
 {
-        struct inode *inode = file->f_dentry->d_inode;
-	unsigned int minor = MINOR(inode->i_rdev);
-	struct capidev *cdev;
+	struct capidev *cdev = (struct capidev *)file->private_data;
 	struct sk_buff *skb;
 	int retval;
 	size_t copied;
 
-       if (ppos != &file->f_pos)
+	if (ppos != &file->f_pos)
 		return -ESPIPE;
 
-	if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)
+	if (!cdev->applid)
 		return -ENODEV;
 
-	cdev = &capidevs[minor];
-
-	if ((skb = skb_dequeue(&cdev->recv_queue)) == 0) {
+	if ((skb = skb_dequeue(&cdev->recvqueue)) == 0) {
 
 		if (file->f_flags & O_NONBLOCK)
 			return -EAGAIN;
 
 		for (;;) {
-			interruptible_sleep_on(&cdev->recv_wait);
-			if ((skb = skb_dequeue(&cdev->recv_queue)) != 0)
+			interruptible_sleep_on(&cdev->recvwait);
+			if ((skb = skb_dequeue(&cdev->recvqueue)) != 0)
 				break;
 			if (signal_pending(current))
 				break;
@@ -212,63 +949,58 @@
 			return -ERESTARTNOHAND;
 	}
 	if (skb->len > count) {
-		skb_queue_head(&cdev->recv_queue, skb);
+		skb_queue_head(&cdev->recvqueue, skb);
 		return -EMSGSIZE;
 	}
 	retval = copy_to_user(buf, skb->data, skb->len);
 	if (retval) {
-		skb_queue_head(&cdev->recv_queue, skb);
+		skb_queue_head(&cdev->recvqueue, skb);
 		return retval;
 	}
 	copied = skb->len;
 
-	if (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3
-	    && CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND)
+	if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_IND) {
 		cdev->nrecvdatapkt++;
-        else cdev->nrecvctlpkt++;
+	} else {
+		cdev->nrecvctlpkt++;
+	}
+
 	kfree_skb(skb);
 
 	return copied;
 }
 
-static ssize_t capi_write(struct file *file, const char *buf,
-		       size_t count, loff_t *ppos)
+static ssize_t
+capi_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
 {
-        struct inode *inode = file->f_dentry->d_inode;
-	unsigned int minor = MINOR(inode->i_rdev);
-	struct capidev *cdev;
+	struct capidev *cdev = (struct capidev *)file->private_data;
 	struct sk_buff *skb;
 	int retval;
-	__u8 cmd;
-	__u8 subcmd;
 	__u16 mlen;
 
-       if (ppos != &file->f_pos)
+        if (ppos != &file->f_pos)
 		return -ESPIPE;
 
-	if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)
+	if (!cdev->applid)
 		return -ENODEV;
 
-	cdev = &capidevs[minor];
-
 	skb = alloc_skb(count, GFP_USER);
 
 	if ((retval = copy_from_user(skb_put(skb, count), buf, count))) {
 		kfree_skb(skb);
 		return retval;
 	}
-	cmd = CAPIMSG_COMMAND(skb->data);
-	subcmd = CAPIMSG_SUBCOMMAND(skb->data);
 	mlen = CAPIMSG_LEN(skb->data);
-	if (cmd == CAPI_DATA_B3 && subcmd == CAPI_REQ) {
-		__u16 dlen = CAPIMSG_DATALEN(skb->data);
-		if (mlen + dlen != count) {
+	if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) {
+		if (mlen + CAPIMSG_DATALEN(skb->data) != count) {
+			kfree_skb(skb);
+			return -EINVAL;
+		}
+	} else {
+		if (mlen != count) {
 			kfree_skb(skb);
 			return -EINVAL;
 		}
-	} else if (mlen != count) {
-		kfree_skb(skb);
-		return -EINVAL;
 	}
 	CAPIMSG_SETAPPID(skb->data, cdev->applid);
 
@@ -278,63 +1010,56 @@
 		kfree_skb(skb);
 		return -EIO;
 	}
-	if (cmd == CAPI_DATA_B3 && subcmd == CAPI_REQ)
+	if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) {
 		cdev->nsentdatapkt++;
-	else cdev->nsentctlpkt++;
+	} else {
+		cdev->nsentctlpkt++;
+	}
 	return count;
 }
 
 static unsigned int
 capi_poll(struct file *file, poll_table * wait)
 {
+	struct capidev *cdev = (struct capidev *)file->private_data;
 	unsigned int mask = 0;
-	unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
-	struct capidev *cdev;
 
-	if (!minor || minor > CAPI_MAXMINOR || !capidevs[minor].is_registered)
+	if (!cdev->applid)
 		return POLLERR;
 
-	cdev = &capidevs[minor];
-	poll_wait(file, &(cdev->recv_wait), wait);
+	poll_wait(file, &(cdev->recvwait), wait);
 	mask = POLLOUT | POLLWRNORM;
-	if (!skb_queue_empty(&cdev->recv_queue))
+	if (!skb_queue_empty(&cdev->recvqueue))
 		mask |= POLLIN | POLLRDNORM;
 	return mask;
 }
 
-static int capi_ioctl(struct inode *inode, struct file *file,
+static int
+capi_ioctl(struct inode *inode, struct file *file,
 		      unsigned int cmd, unsigned long arg)
 {
-	unsigned int minor = MINOR(inode->i_rdev);
-	struct capidev *cdev;
+	struct capidev *cdev = (struct capidev *)file->private_data;
 	capi_ioctl_struct data;
-	int retval;
-
-
-	if (minor >= CAPI_MAXMINOR || !capidevs[minor].is_open)
-		return -ENODEV;
-
-	cdev = &capidevs[minor];
+	int retval = -EINVAL;
 
 	switch (cmd) {
 	case CAPI_REGISTER:
 		{
-			if (!minor)
-				return -EINVAL;
 			retval = copy_from_user((void *) &data.rparams,
 						(void *) arg, sizeof(struct capi_register_params));
 			if (retval)
 				return -EFAULT;
-			if (cdev->is_registered)
+			if (cdev->applid)
 				return -EEXIST;
 			cdev->errcode = (*capifuncs->capi_register) (&data.rparams,
 							  &cdev->applid);
-			if (cdev->errcode)
+			if (cdev->errcode) {
+				cdev->applid = 0;
 				return -EIO;
-			(void) (*capifuncs->capi_set_signal) (cdev->applid, capi_signal, minor);
-			cdev->is_registered = 1;
+			}
+			(void) (*capifuncs->capi_set_signal) (cdev->applid, capi_signal, cdev);
 		}
-		return 0;
+		return (int)cdev->applid;
 
 	case CAPI_GET_VERSION:
 		{
@@ -440,8 +1165,6 @@
 	case CAPI_MANUFACTURER_CMD:
 		{
 			struct capi_manufacturer_cmd mcmd;
-			if (minor)
-				return -EINVAL;
 			if (!capable(CAP_SYS_ADMIN))
 				return -EPERM;
 			retval = copy_from_user((void *) &mcmd, (void *) arg,
@@ -451,121 +1174,785 @@
 			return (*capifuncs->capi_manufacturer) (mcmd.cmd, mcmd.data);
 		}
 		return 0;
+
+	case CAPI_SET_FLAGS:
+	case CAPI_CLR_FLAGS:
+		{
+			unsigned userflags;
+			retval = copy_from_user((void *) &userflags,
+						(void *) arg,
+						sizeof(userflags));
+			if (retval)
+				return -EFAULT;
+			if (cmd == CAPI_SET_FLAGS)
+				cdev->userflags |= userflags;
+			else
+				cdev->userflags &= ~userflags;
+		}
+		return 0;
+
+	case CAPI_GET_FLAGS:
+		{
+			retval = copy_to_user((void *) arg,
+					      (void *) &cdev->userflags,
+					      sizeof(cdev->userflags));
+			if (retval)
+				return -EFAULT;
+		}
+		return 0;
+
+	case CAPI_NCCI_OPENCOUNT:
+		{
+			struct capincci *nccip;
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+			struct capiminor *mp;
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+			unsigned ncci;
+			int count = 0;
+			retval = copy_from_user((void *) &ncci,
+						(void *) arg,
+						sizeof(ncci));
+			if (retval)
+				return -EFAULT;
+			nccip = capincci_find(cdev, (__u32) ncci);
+			if (!nccip)
+				return 0;
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+			if ((mp = nccip->minorp) != 0) {
+				count += atomic_read(&mp->ttyopencount);
+				if (mp->file)
+					count++;
+			}
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+			return count;
+		}
+		return 0;
+
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+	case CAPI_NCCI_GETUNIT:
+		{
+			struct capincci *nccip;
+			struct capiminor *mp;
+			unsigned ncci;
+			retval = copy_from_user((void *) &ncci,
+						(void *) arg,
+						sizeof(ncci));
+			if (retval)
+				return -EFAULT;
+			nccip = capincci_find(cdev, (__u32) ncci);
+			if (!nccip || (mp = nccip->minorp) == 0)
+				return -ESRCH;
+			return mp->minor;
+		}
+		return 0;
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
 	}
 	return -EINVAL;
 }
 
-static int capi_open(struct inode *inode, struct file *file)
+static int
+capi_open(struct inode *inode, struct file *file)
 {
-	unsigned int minor = MINOR(inode->i_rdev);
-
-	if (minor >= CAPI_MAXMINOR)
-		return -ENXIO;
-
-	if (minor) {
-		if (capidevs[minor].is_open)
-			return -EEXIST;
-
-		capidevs[minor].is_open = 1;
-		skb_queue_head_init(&capidevs[minor].recv_queue);
-		MOD_INC_USE_COUNT;
-		capidevs[minor].nopen++;
+	if (file->private_data)
+		return -EEXIST;
 
-	} else {
-		capidevs[minor].is_open++;
-		MOD_INC_USE_COUNT;
-	}
+	if ((file->private_data = capidev_alloc(file)) == 0)
+		return -ENOMEM;
 
+	MOD_INC_USE_COUNT;
+#ifdef _DEBUG_REFCOUNT
+	printk(KERN_DEBUG "capi_open %d\n", GET_USE_COUNT(&__this_module));
+#endif
 	return 0;
 }
 
 static int
 capi_release(struct inode *inode, struct file *file)
 {
-	unsigned int minor = MINOR(inode->i_rdev);
-	struct capidev *cdev;
-	struct sk_buff *skb;
-
-	if (minor >= CAPI_MAXMINOR || !capidevs[minor].is_open) {
-		printk(KERN_ERR "capi20: release minor %d ???\n", minor);
-		return 0;
-	}
-	cdev = &capidevs[minor];
-
-	if (minor) {
-
-		if (cdev->is_registered)
-			(*capifuncs->capi_release) (cdev->applid);
-
-		cdev->is_registered = 0;
-		cdev->applid = 0;
-
-		while ((skb = skb_dequeue(&cdev->recv_queue)) != 0) {
-			kfree_skb(skb);
-		}
-		cdev->is_open = 0;
-	} else {
-		cdev->is_open--;
-	}
+	struct capidev *cdev = (struct capidev *)file->private_data;
 
+	lock_kernel();
+	capincci_free(cdev, 0xffffffff);
+	capidev_free(cdev);
+	file->private_data = NULL;
+	
 	MOD_DEC_USE_COUNT;
+#ifdef _DEBUG_REFCOUNT
+	printk(KERN_DEBUG "capi_release %d\n", GET_USE_COUNT(&__this_module));
+#endif
+	unlock_kernel();
 	return 0;
 }
 
 static struct file_operations capi_fops =
 {
-	capi_llseek,
-	capi_read,
-	capi_write,
-	NULL,			/* capi_readdir */
-	capi_poll,
-	capi_ioctl,
-	NULL,			/* capi_mmap */
-	capi_open,
-        NULL,                   /* capi_flush */
-	capi_release,
-	NULL,			/* capi_fsync */
-	NULL,			/* capi_fasync */
+	llseek:		capi_llseek,
+	read:		capi_read,
+	write:		capi_write,
+	poll:		capi_poll,
+	ioctl:		capi_ioctl,
+	open:		capi_open,
+	release:	capi_release,
 };
 
-/* -------- /proc functions ----------------------------------- */
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+/* -------- file_operations for capincci ---------------------------- */
 
-/*
- * /proc/capi/capi20:
- *  minor opencount nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt
- */
-static int proc_capidev_read_proc(char *page, char **start, off_t off,
-                                       int count, int *eof, void *data)
+static int
+capinc_raw_open(struct inode *inode, struct file *file)
 {
-        struct capidev *cp;
-	int i;
-	int len = 0;
-	off_t begin = 0;
+	struct capiminor *mp;
 
-	for (i=0; i < CAPI_MAXMINOR; i++) {
-		cp = &capidevs[i+1];
-		if (cp->nopen == 0) continue;
-		len += sprintf(page+len, "%d %lu %lu %lu %lu %lu\n",
-			i+1,
-			cp->nopen,
-			cp->nrecvctlpkt,
-			cp->nrecvdatapkt,
-			cp->nsentctlpkt,
-			cp->nsentdatapkt);
-		if (len+begin > off+count)
-			goto endloop;
-		if (len+begin < off) {
-			begin += len;
-			len = 0;
+	if (file->private_data)
+		return -EEXIST;
+	if ((mp = capiminor_find(MINOR(file->f_dentry->d_inode->i_rdev))) == 0)
+		return -ENXIO;
+	if (mp->nccip == 0)
+		return -ENXIO;
+	if (mp->file)
+		return -EBUSY;
+
+#ifdef _DEBUG_REFCOUNT
+	printk(KERN_DEBUG "capi_raw_open %d\n", GET_USE_COUNT(&__this_module));
+#endif
+
+	mp->datahandle = 0;
+	mp->file = file;
+	file->private_data = (void *)mp;
+	handle_minor_recv(mp);
+	return 0;
+}
+
+static loff_t
+capinc_raw_llseek(struct file *file, loff_t offset, int origin)
+{
+	return -ESPIPE;
+}
+
+static ssize_t
+capinc_raw_read(struct file *file, char *buf, size_t count, loff_t *ppos)
+{
+	struct capiminor *mp = (struct capiminor *)file->private_data;
+	struct sk_buff *skb;
+	int retval;
+	size_t copied = 0;
+
+        if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	if (!mp || !mp->nccip)
+		return -EINVAL;
+
+	if ((skb = skb_dequeue(&mp->recvqueue)) == 0) {
+
+		if (file->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+
+		for (;;) {
+			interruptible_sleep_on(&mp->recvwait);
+			if (mp->nccip == 0)
+				return 0;
+			if ((skb = skb_dequeue(&mp->recvqueue)) != 0)
+				break;
+			if (signal_pending(current))
+				break;
+		}
+		if (skb == 0)
+			return -ERESTARTNOHAND;
+	}
+	do {
+		if (count < skb->len) {
+			retval = copy_to_user(buf, skb->data, count);
+			if (retval) {
+				skb_queue_head(&mp->recvqueue, skb);
+				return retval;
+			}
+			skb_pull(skb, count);
+			skb_queue_head(&mp->recvqueue, skb);
+			copied += count;
+			return copied;
+		} else {
+			retval = copy_to_user(buf, skb->data, skb->len);
+			if (retval) {
+				skb_queue_head(&mp->recvqueue, skb);
+				return copied;
+			}
+			copied += skb->len;
+			count -= skb->len;
+			buf += skb->len;
+			kfree_skb(skb);
+		}
+	} while ((skb = skb_dequeue(&mp->recvqueue)) != 0);
+
+	return copied;
+}
+
+static ssize_t
+capinc_raw_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+{
+	struct capiminor *mp = (struct capiminor *)file->private_data;
+	struct sk_buff *skb;
+	int retval;
+
+        if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	if (!mp || !mp->nccip)
+		return -EINVAL;
+
+	skb = alloc_skb(CAPI_DATA_B3_REQ_LEN+count, GFP_USER);
+
+	skb_reserve(skb, CAPI_DATA_B3_REQ_LEN);
+	if ((retval = copy_from_user(skb_put(skb, count), buf, count))) {
+		kfree_skb(skb);
+		return retval;
+	}
+
+	while (skb_queue_len(&mp->outqueue) > CAPINC_MAX_SENDQUEUE) {
+		if (file->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+		interruptible_sleep_on(&mp->sendwait);
+		if (mp->nccip == 0) {
+			kfree_skb(skb);
+			return -EIO;
+		}
+		if (signal_pending(current))
+			return -ERESTARTNOHAND;
+	}
+	skb_queue_tail(&mp->outqueue, skb);
+	mp->outbytes += skb->len;
+	(void)handle_minor_send(mp);
+	return count;
+}
+
+static unsigned int
+capinc_raw_poll(struct file *file, poll_table * wait)
+{
+	struct capiminor *mp = (struct capiminor *)file->private_data;
+	unsigned int mask = 0;
+
+	if (!mp || !mp->nccip)
+		return POLLERR|POLLHUP;
+
+	poll_wait(file, &(mp->recvwait), wait);
+	if (!skb_queue_empty(&mp->recvqueue))
+		mask |= POLLIN | POLLRDNORM;
+	poll_wait(file, &(mp->sendwait), wait);
+	if (skb_queue_len(&mp->outqueue) > CAPINC_MAX_SENDQUEUE)
+		mask = POLLOUT | POLLWRNORM;
+	return mask;
+}
+
+static int
+capinc_raw_ioctl(struct inode *inode, struct file *file,
+		      unsigned int cmd, unsigned long arg)
+{
+	struct capiminor *mp = (struct capiminor *)file->private_data;
+	if (!mp || !mp->nccip)
+		return -EINVAL;
+
+	switch (cmd) {
+	}
+	return -EINVAL;
+}
+
+static int
+capinc_raw_release(struct inode *inode, struct file *file)
+{
+	struct capiminor *mp = (struct capiminor *)file->private_data;
+
+	if (mp) {
+		lock_kernel();
+		mp->file = 0;
+		if (mp->nccip == 0) {
+			capiminor_free(mp);
+			file->private_data = NULL;
+		}
+		unlock_kernel();
+	}
+
+#ifdef _DEBUG_REFCOUNT
+	printk(KERN_DEBUG "capinc_raw_release %d\n", GET_USE_COUNT(&__this_module));
+#endif
+	return 0;
+}
+
+static struct file_operations capinc_raw_fops =
+{
+	llseek:		capinc_raw_llseek,
+	read:		capinc_raw_read,
+	write:		capinc_raw_write,
+	poll:		capinc_raw_poll,
+	ioctl:		capinc_raw_ioctl,
+	open:		capinc_raw_open,
+	release:	capinc_raw_release,
+};
+
+/* -------- tty_operations for capincci ----------------------------- */
+
+int capinc_tty_open(struct tty_struct * tty, struct file * file)
+{
+	struct capiminor *mp;
+
+	if ((mp = capiminor_find(MINOR(file->f_dentry->d_inode->i_rdev))) == 0)
+		return -ENXIO;
+	if (mp->nccip == 0)
+		return -ENXIO;
+	if (mp->file)
+		return -EBUSY;
+
+	skb_queue_head_init(&mp->recvqueue);
+	init_waitqueue_head(&mp->recvwait);
+	init_waitqueue_head(&mp->sendwait);
+	tty->driver_data = (void *)mp;
+#ifdef _DEBUG_REFCOUNT
+	printk(KERN_DEBUG "capi_tty_open %d\n", GET_USE_COUNT(&__this_module));
+#endif
+	if (atomic_read(&mp->ttyopencount) == 0)
+		mp->tty = tty;
+	atomic_inc(&mp->ttyopencount);
+#ifdef _DEBUG_REFCOUNT
+	printk(KERN_DEBUG "capinc_tty_open ocount=%d\n", atomic_read(&mp->ttyopencount));
+#endif
+	handle_minor_recv(mp);
+	return 0;
+}
+
+void capinc_tty_close(struct tty_struct * tty, struct file * file)
+{
+	struct capiminor *mp;
+
+	mp = (struct capiminor *)tty->driver_data;
+	if (mp)	{
+		if (atomic_dec_and_test(&mp->ttyopencount)) {
+#ifdef _DEBUG_REFCOUNT
+			printk(KERN_DEBUG "capinc_tty_close lastclose\n");
+#endif
+			tty->driver_data = (void *)0;
+			mp->tty = 0;
+		}
+#ifdef _DEBUG_REFCOUNT
+		printk(KERN_DEBUG "capinc_tty_close ocount=%d\n", atomic_read(&mp->ttyopencount));
+#endif
+		if (mp->nccip == 0)
+			capiminor_free(mp);
+	}
+
+#ifdef _DEBUG_REFCOUNT
+	printk(KERN_DEBUG "capinc_tty_close\n");
+#endif
+}
+
+int capinc_tty_write(struct tty_struct * tty, int from_user,
+		      const unsigned char *buf, int count)
+{
+	struct capiminor *mp = (struct capiminor *)tty->driver_data;
+	struct sk_buff *skb;
+	int retval;
+
+#ifdef _DEBUG_TTYFUNCS
+	printk(KERN_DEBUG "capinc_tty_write(from_user=%d,count=%d)\n",
+				from_user, count);
+#endif
+
+	if (!mp || !mp->nccip) {
+#ifdef _DEBUG_TTYFUNCS
+		printk(KERN_DEBUG "capinc_tty_write: mp or mp->ncci NULL\n");
+#endif
+		return 0;
+	}
+
+	skb = mp->ttyskb;
+	if (skb) {
+		mp->ttyskb = 0;
+		skb_queue_tail(&mp->outqueue, skb);
+		mp->outbytes += skb->len;
+	}
+
+	skb = alloc_skb(CAPI_DATA_B3_REQ_LEN+count, GFP_ATOMIC);
+	if (!skb) {
+		printk(KERN_ERR "capinc_tty_write: alloc_skb failed\n");
+		return -ENOMEM;
+	}
+
+	skb_reserve(skb, CAPI_DATA_B3_REQ_LEN);
+	if (from_user) {
+		if ((retval = copy_from_user(skb_put(skb, count), buf, count))) {
+			kfree_skb(skb);
+#ifdef _DEBUG_TTYFUNCS
+			printk(KERN_DEBUG "capinc_tty_write: copy_from_user=%d\n", retval);
+#endif
+			return retval;
+		}
+	} else {
+		memcpy(skb_put(skb, count), buf, count);
+	}
+
+	skb_queue_tail(&mp->outqueue, skb);
+	mp->outbytes += skb->len;
+	(void)handle_minor_send(mp);
+	(void)handle_minor_recv(mp);
+	return count;
+}
+
+void capinc_tty_put_char(struct tty_struct *tty, unsigned char ch)
+{
+	struct capiminor *mp = (struct capiminor *)tty->driver_data;
+	struct sk_buff *skb;
+
+#ifdef _DEBUG_TTYFUNCS
+	printk(KERN_DEBUG "capinc_put_char(%u)\n", ch);
+#endif
+
+	if (!mp || !mp->nccip) {
+#ifdef _DEBUG_TTYFUNCS
+		printk(KERN_DEBUG "capinc_tty_put_char: mp or mp->ncci NULL\n");
+#endif
+		return;
+	}
+
+	skb = mp->ttyskb;
+	if (skb) {
+		if (skb_tailroom(skb) > 0) {
+			*(skb_put(skb, 1)) = ch;
+			return;
+		}
+		mp->ttyskb = 0;
+		skb_queue_tail(&mp->outqueue, skb);
+		mp->outbytes += skb->len;
+		(void)handle_minor_send(mp);
+	}
+	skb = alloc_skb(CAPI_DATA_B3_REQ_LEN+CAPI_MAX_BLKSIZE, GFP_ATOMIC);
+	if (skb) {
+		skb_reserve(skb, CAPI_DATA_B3_REQ_LEN);
+		*(skb_put(skb, 1)) = ch;
+		mp->ttyskb = skb;
+	} else {
+		printk(KERN_ERR "capinc_put_char: char %u lost\n", ch);
+	}
+}
+
+void capinc_tty_flush_chars(struct tty_struct *tty)
+{
+	struct capiminor *mp = (struct capiminor *)tty->driver_data;
+	struct sk_buff *skb;
+
+#ifdef _DEBUG_TTYFUNCS
+	printk(KERN_DEBUG "capinc_tty_flush_chars\n");
+#endif
+
+	if (!mp || !mp->nccip) {
+#ifdef _DEBUG_TTYFUNCS
+		printk(KERN_DEBUG "capinc_tty_flush_chars: mp or mp->ncci NULL\n");
+#endif
+		return;
+	}
+
+	skb = mp->ttyskb;
+	if (skb) {
+		mp->ttyskb = 0;
+		skb_queue_tail(&mp->outqueue, skb);
+		mp->outbytes += skb->len;
+		(void)handle_minor_send(mp);
+	}
+	(void)handle_minor_recv(mp);
+}
+
+int capinc_tty_write_room(struct tty_struct *tty)
+{
+	struct capiminor *mp = (struct capiminor *)tty->driver_data;
+	int room;
+	if (!mp || !mp->nccip) {
+#ifdef _DEBUG_TTYFUNCS
+		printk(KERN_DEBUG "capinc_tty_write_room: mp or mp->ncci NULL\n");
+#endif
+		return 0;
+	}
+	room = CAPINC_MAX_SENDQUEUE-skb_queue_len(&mp->outqueue);
+	room *= CAPI_MAX_BLKSIZE;
+#ifdef _DEBUG_TTYFUNCS
+	printk(KERN_DEBUG "capinc_tty_write_room = %d\n", room);
+#endif
+	return room;
+}
+
+int capinc_tty_chars_in_buffer(struct tty_struct *tty)
+{
+	struct capiminor *mp = (struct capiminor *)tty->driver_data;
+	if (!mp || !mp->nccip) {
+#ifdef _DEBUG_TTYFUNCS
+		printk(KERN_DEBUG "capinc_tty_chars_in_buffer: mp or mp->ncci NULL\n");
+#endif
+		return 0;
+	}
+#ifdef _DEBUG_TTYFUNCS
+	printk(KERN_DEBUG "capinc_tty_chars_in_buffer = %d nack=%d sq=%d rq=%d\n",
+			mp->outbytes, mp->nack,
+			skb_queue_len(&mp->outqueue),
+			skb_queue_len(&mp->inqueue));
+#endif
+	return mp->outbytes;
+}
+
+int capinc_tty_ioctl(struct tty_struct *tty, struct file * file,
+		    unsigned int cmd, unsigned long arg)
+{
+	int error = 0;
+	switch (cmd) {
+	default:
+		error = n_tty_ioctl (tty, file, cmd, arg);
+		break;
+	}
+	return error;
+}
+
+void capinc_tty_set_termios(struct tty_struct *tty, struct termios * old)
+{
+#ifdef _DEBUG_TTYFUNCS
+	printk(KERN_DEBUG "capinc_tty_set_termios\n");
+#endif
+}
+
+void capinc_tty_throttle(struct tty_struct * tty)
+{
+	struct capiminor *mp = (struct capiminor *)tty->driver_data;
+#ifdef _DEBUG_TTYFUNCS
+	printk(KERN_DEBUG "capinc_tty_throttle\n");
+#endif
+	if (mp)
+		mp->ttyinstop = 1;
+}
+
+void capinc_tty_unthrottle(struct tty_struct * tty)
+{
+	struct capiminor *mp = (struct capiminor *)tty->driver_data;
+#ifdef _DEBUG_TTYFUNCS
+	printk(KERN_DEBUG "capinc_tty_unthrottle\n");
+#endif
+	if (mp) {
+		mp->ttyinstop = 0;
+		handle_minor_recv(mp);
+	}
+}
+
+void capinc_tty_stop(struct tty_struct *tty)
+{
+	struct capiminor *mp = (struct capiminor *)tty->driver_data;
+#ifdef _DEBUG_TTYFUNCS
+	printk(KERN_DEBUG "capinc_tty_stop\n");
+#endif
+	if (mp) {
+		mp->ttyoutstop = 1;
+	}
+}
+
+void capinc_tty_start(struct tty_struct *tty)
+{
+	struct capiminor *mp = (struct capiminor *)tty->driver_data;
+#ifdef _DEBUG_TTYFUNCS
+	printk(KERN_DEBUG "capinc_tty_start\n");
+#endif
+	if (mp) {
+		mp->ttyoutstop = 0;
+		(void)handle_minor_send(mp);
+	}
+}
+
+void capinc_tty_hangup(struct tty_struct *tty)
+{
+#ifdef _DEBUG_TTYFUNCS
+	printk(KERN_DEBUG "capinc_tty_hangup\n");
+#endif
+}
+
+void capinc_tty_break_ctl(struct tty_struct *tty, int state)
+{
+#ifdef _DEBUG_TTYFUNCS
+	printk(KERN_DEBUG "capinc_tty_break_ctl(%d)\n", state);
+#endif
+}
+
+void capinc_tty_flush_buffer(struct tty_struct *tty)
+{
+#ifdef _DEBUG_TTYFUNCS
+	printk(KERN_DEBUG "capinc_tty_flush_buffer\n");
+#endif
+}
+
+void capinc_tty_set_ldisc(struct tty_struct *tty)
+{
+#ifdef _DEBUG_TTYFUNCS
+	printk(KERN_DEBUG "capinc_tty_set_ldisc\n");
+#endif
+}
+
+void capinc_tty_send_xchar(struct tty_struct *tty, char ch)
+{
+#ifdef _DEBUG_TTYFUNCS
+	printk(KERN_DEBUG "capinc_tty_send_xchar(%d)\n", ch);
+#endif
+}
+
+int capinc_tty_read_proc(char *page, char **start, off_t off,
+			  int count, int *eof, void *data)
+{
+	return 0;
+}
+
+int capinc_write_proc(struct file *file, const char *buffer,
+			  unsigned long count, void *data)
+{
+	return 0;
+}
+
+#define CAPINC_NR_PORTS 256
+static struct tty_driver capinc_tty_driver;
+static int capinc_tty_refcount;
+static struct tty_struct *capinc_tty_table[CAPINC_NR_PORTS];
+static struct termios *capinc_tty_termios[CAPINC_NR_PORTS];
+static struct termios *capinc_tty_termios_locked[CAPINC_NR_PORTS];
+
+int capinc_tty_init(void)
+{
+	struct tty_driver *drv = &capinc_tty_driver;
+
+	/* Initialize the tty_driver structure */
+	
+	memset(drv, 0, sizeof(struct tty_driver));
+	drv->magic = TTY_DRIVER_MAGIC;
+#if (LINUX_VERSION_CODE > 0x20100)
+	drv->driver_name = "capi_nc";
+#endif
+	drv->name = "capi/%d";
+	drv->major = capi_ttymajor;
+	drv->minor_start = 0;
+	drv->num = CAPINC_NR_PORTS;
+	drv->type = TTY_DRIVER_TYPE_SERIAL;
+	drv->subtype = SERIAL_TYPE_NORMAL;
+	drv->init_termios = tty_std_termios;
+	drv->init_termios.c_iflag = ICRNL;
+	drv->init_termios.c_oflag = OPOST | ONLCR;
+	drv->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	drv->init_termios.c_lflag = 0;
+	drv->flags = TTY_DRIVER_REAL_RAW|TTY_DRIVER_RESET_TERMIOS;
+	drv->refcount = &capinc_tty_refcount;
+	drv->table = capinc_tty_table;
+	drv->termios = capinc_tty_termios;
+	drv->termios_locked = capinc_tty_termios_locked;
+
+	drv->open = capinc_tty_open;
+	drv->close = capinc_tty_close;
+	drv->write = capinc_tty_write;
+	drv->put_char = capinc_tty_put_char;
+	drv->flush_chars = capinc_tty_flush_chars;
+	drv->write_room = capinc_tty_write_room;
+	drv->chars_in_buffer = capinc_tty_chars_in_buffer;
+	drv->ioctl = capinc_tty_ioctl;
+	drv->set_termios = capinc_tty_set_termios;
+	drv->throttle = capinc_tty_throttle;
+	drv->unthrottle = capinc_tty_unthrottle;
+	drv->stop = capinc_tty_stop;
+	drv->start = capinc_tty_start;
+	drv->hangup = capinc_tty_hangup;
+#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
+	drv->break_ctl = capinc_tty_break_ctl;
+#endif
+	drv->flush_buffer = capinc_tty_flush_buffer;
+	drv->set_ldisc = capinc_tty_set_ldisc;
+#if (LINUX_VERSION_CODE >= 131343)
+	drv->send_xchar = capinc_tty_send_xchar;
+	drv->read_proc = capinc_tty_read_proc;
+#endif
+	if (tty_register_driver(drv)) {
+		printk(KERN_ERR "Couldn't register capi_nc driver\n");
+		return -1;
+	}
+	return 0;
+}
+
+void capinc_tty_exit(void)
+{
+	struct tty_driver *drv = &capinc_tty_driver;
+	int retval;
+	if ((retval = tty_unregister_driver(drv)))
+		printk(KERN_ERR "capi: failed to unregister capi_nc driver (%d)\n", retval);
+}
+
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+
+/* -------- /proc functions ----------------------------------------- */
+
+/*
+ * /proc/capi/capi20:
+ *  minor applid nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt
+ */
+static int proc_capidev_read_proc(char *page, char **start, off_t off,
+                                       int count, int *eof, void *data)
+{
+        struct capidev *cdev;
+	int len = 0;
+
+	for (cdev=capidev_openlist; cdev; cdev = cdev->next) {
+		len += sprintf(page+len, "%d %d %lu %lu %lu %lu\n",
+			cdev->minor,
+			cdev->applid,
+			cdev->nrecvctlpkt,
+			cdev->nrecvdatapkt,
+			cdev->nsentctlpkt,
+			cdev->nsentdatapkt);
+		if (len <= off) {
+			off -= len;
+			len = 0;
+		} else {
+			if (len-off > count)
+				goto endloop;
 		}
 	}
 endloop:
-	if (i >= CAPI_MAXMINOR)
+	if (len < count)
 		*eof = 1;
-	if (off >= len+begin)
-		return 0;
-	*start = page + (off-begin);
-	return ((count < begin+len-off) ? count : begin+len-off);
+	if (len>count) len = count;
+	if (len<0) len = 0;
+	return len;
+}
+
+/*
+ * /proc/capi/capi20ncci:
+ *  applid ncci
+ */
+static int proc_capincci_read_proc(char *page, char **start, off_t off,
+                                       int count, int *eof, void *data)
+{
+        struct capidev *cdev;
+        struct capincci *np;
+	int len = 0;
+
+	for (cdev=capidev_openlist; cdev; cdev = cdev->next) {
+		for (np=cdev->nccis; np; np = np->next) {
+			len += sprintf(page+len, "%d 0x%x%s\n",
+				cdev->applid,
+				np->ncci,
+#ifndef CONFIG_ISDN_CAPI_MIDDLEWARE
+				"");
+#else /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+				np->minorp && np->minorp->file ? " open" : "");
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+			if (len <= off) {
+				off -= len;
+				len = 0;
+			} else {
+				if (len-off > count)
+					goto endloop;
+			}
+		}
+	}
+endloop:
+	*start = page+off;
+	if (len < count)
+		*eof = 1;
+	if (len>count) len = count;
+	if (len<0) len = 0;
+	return len;
 }
 
 static struct procfsentries {
@@ -577,9 +1964,10 @@
 } procfsentries[] = {
    /* { "capi",		  S_IFDIR, 0 }, */
    { "capi/capi20", 	  0	 , proc_capidev_read_proc },
+   { "capi/capi20ncci",   0	 , proc_capincci_read_proc },
 };
 
-static void proc_init(void)
+static void __init proc_init(void)
 {
     int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
     int i;
@@ -591,7 +1979,7 @@
     }
 }
 
-static void proc_exit(void)
+static void  proc_exit(void)
 {
     int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
     int i;
@@ -604,42 +1992,118 @@
 	}
     }
 }
+
 /* -------- init function and module interface ---------------------- */
 
-#ifdef MODULE
-#define	 capi_init	init_module
-#endif
+
+static void lower_callback(unsigned int cmd, __u32 contr, void *data)
+{
+	struct capi_ncciinfo *np;
+	struct capidev *cdev;
+
+	switch (cmd) {
+	case KCI_CONTRUP:
+		printk(KERN_INFO "capi: controller %hu up\n", contr);
+		break;
+	case KCI_CONTRDOWN:
+		printk(KERN_INFO "capi: controller %hu down\n", contr);
+		break;
+	case KCI_NCCIUP:
+		np = (struct capi_ncciinfo *)data;
+		if ((cdev = capidev_find(np->applid)) == 0)
+			return;
+		(void)capincci_alloc(cdev, np->ncci);
+		break;
+	case KCI_NCCIDOWN:
+		np = (struct capi_ncciinfo *)data;
+		if ((cdev = capidev_find(np->applid)) == 0)
+			return;
+		(void)capincci_free(cdev, np->ncci);
+		break;
+	}
+}
 
 static struct capi_interface_user cuser = {
-	"capi20",
-	0,
+	name: "capi20",
+	callback: lower_callback,
 };
 
-int capi_init(void)
+static char rev[10];
+
+static int __init capi_init(void)
 {
-	
-	memset(capidevs, 0, sizeof(capidevs));
+	char *p;
+
+	MOD_INC_USE_COUNT;
+
+	if ((p = strchr(revision, ':'))) {
+		strcpy(rev, p + 2);
+		p = strchr(rev, '$');
+		*(p-1) = 0;
+	} else
+		strcpy(rev, "???");
 
 	if (register_chrdev(capi_major, "capi20", &capi_fops)) {
 		printk(KERN_ERR "capi20: unable to get major %d\n", capi_major);
+		MOD_DEC_USE_COUNT;
+		return -EIO;
+	}
+
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+	if (register_chrdev(capi_rawmajor, "capi/r%d", &capinc_raw_fops)) {
+		unregister_chrdev(capi_major, "capi20");
+		printk(KERN_ERR "capi20: unable to get major %d\n", capi_rawmajor);
+		MOD_DEC_USE_COUNT;
 		return -EIO;
 	}
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
 	printk(KERN_NOTICE "capi20: started up with major %d\n", capi_major);
 
 	if ((capifuncs = attach_capi_interface(&cuser)) == 0) {
+
+		MOD_DEC_USE_COUNT;
 		unregister_chrdev(capi_major, "capi20");
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+		unregister_chrdev(capi_rawmajor, "capi/r%d");
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
 		return -EIO;
 	}
+
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+	if (capinc_tty_init() < 0) {
+		(void) detach_capi_interface(&cuser);
+		unregister_chrdev(capi_major, "capi20");
+		unregister_chrdev(capi_rawmajor, "capi/r%d");
+		MOD_DEC_USE_COUNT;
+		return -ENOMEM;
+	}
+#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
+
+
 	(void)proc_init();
+
+	printk(KERN_NOTICE "capi20: Rev%s: started up with major %d\n",
+				rev, capi_major);
+
+	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
-#ifdef MODULE
-void cleanup_module(void)
+static void  capi_exit(void)
 {
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+#endif
 	(void)proc_exit();
+
 	unregister_chrdev(capi_major, "capi20");
+
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+	capinc_tty_exit();
+	unregister_chrdev(capi_rawmajor, "capi/r%d");
+#endif
 	(void) detach_capi_interface(&cuser);
+	printk(KERN_NOTICE "capi: Rev%s: unloaded\n", rev);
 }
 
-#endif
+module_init(capi_init);
+module_exit(capi_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/avmb1/capicmd.h linux.19p18/drivers/isdn/avmb1/capicmd.h
--- linux.vanilla/drivers/isdn/avmb1/capicmd.h	Fri Apr 21 12:46:08 2000
+++ linux.19p18/drivers/isdn/avmb1/capicmd.h	Wed Dec 13 22:06:43 2000
@@ -1,11 +1,22 @@
 /*
- * $Id: capicmd.h,v 1.1 1997/03/04 21:50:30 calle Exp $
+ * $Id: capicmd.h,v 1.2 2000/03/03 15:50:42 calle Exp $
  * 
  * CAPI 2.0 Interface for Linux
  * 
  * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: capicmd.h,v $
+ * Revision 1.2  2000/03/03 15:50:42  calle
+ * - kernel CAPI:
+ *   - Changed parameter "param" in capi_signal from __u32 to void *.
+ *   - rewrote notifier handling in kcapi.c
+ *   - new notifier NCCI_UP and NCCI_DOWN
+ * - User CAPI:
+ *   - /dev/capi20 is now a cloning device.
+ *   - middleware extentions prepared.
+ * - capidrv.c
+ *   - locking of list operations and module count updates.
+ *
  * Revision 1.1  1997/03/04 21:50:30  calle
  * Frirst version in isdn4linux
  *
@@ -19,6 +30,10 @@
  */
 #ifndef __CAPICMD_H__
 #define __CAPICMD_H__
+
+#define CAPI_MSG_BASELEN		8
+#define CAPI_DATA_B3_REQ_LEN		(CAPI_MSG_BASELEN+4+4+2+2+2)
+#define CAPI_DATA_B3_RESP_LEN		(CAPI_MSG_BASELEN+4+2)
 
 /*----- CAPI commands -----*/
 #define CAPI_ALERT		    0x01
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/avmb1/capidev.h linux.19p18/drivers/isdn/avmb1/capidev.h
--- linux.vanilla/drivers/isdn/avmb1/capidev.h	Fri Apr 21 12:46:08 2000
+++ linux.19p18/drivers/isdn/avmb1/capidev.h	Tue Feb 13 18:50:48 2001
@@ -1,11 +1,25 @@
 /*
- * $Id: capidev.h,v 1.4 1999/07/01 15:26:32 calle Exp $
+ * $Id: capidev.h,v 1.6 2000/11/25 17:00:59 kai Exp $
  *
  * CAPI 2.0 Interface for Linux
  *
  * (c) Copyright 1996 by Carsten Paeth (calle@calle.in-berlin.de)
  *
  * $Log: capidev.h,v $
+ * Revision 1.6  2000/11/25 17:00:59  kai
+ * compatibility cleanup - final part for the time being
+ *
+ * Revision 1.5  2000/03/03 15:50:42  calle
+ * - kernel CAPI:
+ *   - Changed parameter "param" in capi_signal from __u32 to void *.
+ *   - rewrote notifier handling in kcapi.c
+ *   - new notifier NCCI_UP and NCCI_DOWN
+ * - User CAPI:
+ *   - /dev/capi20 is now a cloning device.
+ *   - middleware extentions prepared.
+ * - capidrv.c
+ *   - locking of list operations and module count updates.
+ *
  * Revision 1.4  1999/07/01 15:26:32  calle
  * complete new version (I love it):
  * + new hardware independed "capi_driver" interface that will make it easy to:
@@ -40,18 +54,18 @@
  */
 
 struct capidev {
-	int is_open;
-	int is_registered;
-	__u16 applid;
+	struct capidev *next;
+	struct file    *file;
+	__u16		applid;
+	__u16		errcode;
+	unsigned int    minor;
+
 	struct sk_buff_head recv_queue;
-	struct wait_queue *recv_wait;
-	__u16 errcode;
+	wait_queue_head_t recv_wait;
+
 	/* Statistic */
-	unsigned long nopen;
-	unsigned long nrecvctlpkt;
-	unsigned long nrecvdatapkt;
-	unsigned long nsentctlpkt;
-	unsigned long nsentdatapkt;
+	unsigned long	nrecvctlpkt;
+	unsigned long	nrecvdatapkt;
+	unsigned long	nsentctlpkt;
+	unsigned long	nsentdatapkt;
 };
-
-#define CAPI_MAXMINOR	CAPI_MAXAPPL
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/avmb1/capidrv.c linux.19p18/drivers/isdn/avmb1/capidrv.c
--- linux.vanilla/drivers/isdn/avmb1/capidrv.c	Fri Apr 21 12:46:08 2000
+++ linux.19p18/drivers/isdn/avmb1/capidrv.c	Wed Feb 14 14:28:52 2001
@@ -1,11 +1,64 @@
 /*
- * $Id: capidrv.c,v 1.29 1999/12/06 17:13:06 calle Exp $
+ * $Id: capidrv.c,v 1.39.6.2 2001/02/13 11:43:29 kai Exp $
  *
  * ISDN4Linux Driver, using capi20 interface (kernelcapi)
  *
  * Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
  *
  * $Log: capidrv.c,v $
+ * Revision 1.39.6.2  2001/02/13 11:43:29  kai
+ * more compatility changes for 2.2.19
+ *
+ * Revision 1.39.6.1  2001/02/10 14:41:20  kai
+ * Changes from kernel tree
+ *
+ * Revision 1.39  2000/11/23 20:45:14  kai
+ * fixed module_init/exit stuff
+ * Note: compiled-in kernel doesn't work pre 2.2.18 anymore.
+ *
+ * Revision 1.38  2000/11/14 08:43:07  calle
+ * Bugfix for v110. Connectparamters where setup for sync ...
+ *
+ * Revision 1.37  2000/11/01 14:05:02  calle
+ * - use module_init/module_exit from linux/init.h.
+ * - all static struct variables are initialized with "membername:" now.
+ * - avm_cs.c, let it work with newer pcmcia-cs.
+ *
+ * Revision 1.36  2000/06/26 15:13:41  keil
+ * features should be or'ed
+ *
+ * Revision 1.35  2000/06/19 15:11:25  keil
+ * avoid use of freed structs
+ * changes from 2.4.0-ac21
+ *
+ * Revision 1.34  2000/06/19 13:13:55  calle
+ * Added Modemsupport!
+ *
+ * Revision 1.33  2000/05/06 00:52:36  kai
+ * merged changes from kernel tree
+ * fixed timer and net_device->name breakage
+ *
+ * Revision 1.32  2000/04/07 15:19:58  calle
+ * remove warnings
+ *
+ * Revision 1.31  2000/04/06 15:01:25  calle
+ * Bugfix: crash in capidrv.c when reseting a capi controller.
+ * - changed code order on remove of controller.
+ * - using tq_schedule for notifier in kcapi.c.
+ * - now using spin_lock_irqsave() and spin_unlock_irqrestore().
+ * strange: sometimes even MP hang on unload of isdn.o ...
+ *
+ * Revision 1.30  2000/03/03 15:50:42  calle
+ * - kernel CAPI:
+ *   - Changed parameter "param" in capi_signal from __u32 to void *.
+ *   - rewrote notifier handling in kcapi.c
+ *   - new notifier NCCI_UP and NCCI_DOWN
+ * - User CAPI:
+ *   - /dev/capi20 is now a cloning device.
+ *   - middleware extentions prepared.
+ * - capidrv.c
+ *   - locking of list operations and module count updates.
+ *
  * Revision 1.29  1999/12/06 17:13:06  calle
  * Added controller watchdog.
  *
@@ -151,7 +204,7 @@
 #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/sched.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/fcntl.h>
 #include <linux/fs.h>
 #include <linux/signal.h>
@@ -165,14 +218,15 @@
 #include <linux/capi.h>
 #include <linux/kernelcapi.h>
 #include <linux/ctype.h>
+#include <linux/init.h>
 #include <asm/segment.h>
 
 #include "capiutil.h"
 #include "capicmd.h"
 #include "capidrv.h"
 
-static char *revision = "$Revision: 1.29 $";
-int debugmode = 0;
+static char *revision = "$Revision: 1.39.6.2 $";
+static int debugmode = 0;
 
 MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
 MODULE_PARM(debugmode, "i");
@@ -280,6 +334,7 @@
 /* -------- data definitions ----------------------------------------- */
 
 static capidrv_data global;
+static spinlock_t global_lock = SPIN_LOCK_UNLOCKED;
 static struct capi_interface *capifuncs;
 
 static void handle_dtrace_data(capidrv_contr *card,
@@ -305,6 +360,8 @@
 		return 2;
         case ISDN_PROTO_L2_FAX:
 		return 4;
+	case ISDN_PROTO_L2_MODEM:
+		return 8;
 	}
 }
 
@@ -321,6 +378,7 @@
         case ISDN_PROTO_L2_V11096:
         case ISDN_PROTO_L2_V11019:
         case ISDN_PROTO_L2_V11038:
+	case ISDN_PROTO_L2_MODEM:
 		return 1;
         case ISDN_PROTO_L2_FAX:
 		return 4;
@@ -338,6 +396,7 @@
         case ISDN_PROTO_L2_V11096:
         case ISDN_PROTO_L2_V11019:
         case ISDN_PROTO_L2_V11038:
+	case ISDN_PROTO_L2_MODEM:
 	default:
 		return 0;
         case ISDN_PROTO_L2_FAX:
@@ -345,16 +404,16 @@
 	}
 }
 
-static _cstruct b1config_sync_v110(__u16 rate)
+static _cstruct b1config_async_v110(__u16 rate)
 {
 	/* CAPI-Spec "B1 Configuration" */
 	static unsigned char buf[9];
 	buf[0] = 8; /* len */
 	/* maximum bitrate */
 	buf[1] = rate & 0xff; buf[2] = (rate >> 8) & 0xff;
-	buf[3] = buf[4] = 0; /* reserved, bits per character */
-	buf[5] = buf[6] = 0; /* reserved, parity */
-	buf[7] = buf[9] = 0; /* reserved, stop bits */
+	buf[3] = 8; buf[4] = 0; /* 8 bits per character */
+	buf[5] = 0; buf[6] = 0; /* parity none */
+	buf[7] = 0; buf[8] = 0; /* 1 stop bit */
 	return buf;
 }
 
@@ -369,11 +428,11 @@
 	default:
 		return 0;
         case ISDN_PROTO_L2_V11096:
-	    return b1config_sync_v110(9600);
+	    return b1config_async_v110(9600);
         case ISDN_PROTO_L2_V11019:
-	    return b1config_sync_v110(19200);
+	    return b1config_async_v110(19200);
         case ISDN_PROTO_L2_V11038:
-	    return b1config_sync_v110(38400);
+	    return b1config_async_v110(38400);
 	}
 }
 
@@ -439,26 +498,28 @@
 
 static inline capidrv_contr *findcontrbydriverid(int driverid)
 {
-	capidrv_contr *p = global.contr_list;
+    	unsigned long flags;
+	capidrv_contr *p;
 
-	while (p) {
+	spin_lock_irqsave(&global_lock, flags);
+	for (p = global.contr_list; p; p = p->next)
 		if (p->myid == driverid)
-			return p;
-		p = p->next;
-	}
-	return (capidrv_contr *) 0;
+			break;
+	spin_unlock_irqrestore(&global_lock, flags);
+	return p;
 }
 
 static capidrv_contr *findcontrbynumber(__u32 contr)
 {
+	unsigned long flags;
 	capidrv_contr *p = global.contr_list;
 
-	while (p) {
+	spin_lock_irqsave(&global_lock, flags);
+	for (p = global.contr_list; p; p = p->next)
 		if (p->contrnr == contr)
-			return p;
-		p = p->next;
-	}
-	return (capidrv_contr *) 0;
+			break;
+	spin_unlock_irqrestore(&global_lock, flags);
+	return p;
 }
 
 
@@ -1501,7 +1562,7 @@
 
 static _cmsg s_cmsg;
 
-static void capidrv_signal(__u16 applid, __u32 dummy)
+static void capidrv_signal(__u16 applid, void *dummy)
 {
 	struct sk_buff *skb = 0;
 
@@ -1545,47 +1606,41 @@
 static void handle_dtrace_data(capidrv_contr *card,
 			     int send, int level2, __u8 *data, __u16 len)
 {
-    long flags;
-    __u8 *p, *end;
-    isdn_ctrl cmd;
+    	__u8 *p, *end;
+    	isdn_ctrl cmd;
 
-    if (!len) {
-       printk(KERN_DEBUG "capidrv-%d: avmb1_q931_data: len == %d\n",
+    	if (!len) {
+		printk(KERN_DEBUG "capidrv-%d: avmb1_q931_data: len == %d\n",
 				card->contrnr, len);
-       return;
-    }
-
-    save_flags(flags);
-    cli();
-
-    if (level2) {
-        PUTBYTE_TO_STATUS(card, 'D');
-        PUTBYTE_TO_STATUS(card, '2');
-        PUTBYTE_TO_STATUS(card, send ? '>' : '<');
-        PUTBYTE_TO_STATUS(card, ':');
-    } else {
-        PUTBYTE_TO_STATUS(card, 'D');
-        PUTBYTE_TO_STATUS(card, '3');
-        PUTBYTE_TO_STATUS(card, send ? '>' : '<');
-        PUTBYTE_TO_STATUS(card, ':');
-    }
+		return;
+	}
 
-    for (p = data, end = data+len; p < end; p++) {
-       __u8 w;
-       PUTBYTE_TO_STATUS(card, ' ');
-       w = (*p >> 4) & 0xf;
-       PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w);
-       w = *p & 0xf;
-       PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w);
-    }
-    PUTBYTE_TO_STATUS(card, '\n');
+	if (level2) {
+		PUTBYTE_TO_STATUS(card, 'D');
+		PUTBYTE_TO_STATUS(card, '2');
+        	PUTBYTE_TO_STATUS(card, send ? '>' : '<');
+        	PUTBYTE_TO_STATUS(card, ':');
+	} else {
+        	PUTBYTE_TO_STATUS(card, 'D');
+        	PUTBYTE_TO_STATUS(card, '3');
+        	PUTBYTE_TO_STATUS(card, send ? '>' : '<');
+        	PUTBYTE_TO_STATUS(card, ':');
+    	}
+
+	for (p = data, end = data+len; p < end; p++) {
+		__u8 w;
+		PUTBYTE_TO_STATUS(card, ' ');
+		w = (*p >> 4) & 0xf;
+		PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w);
+		w = *p & 0xf;
+		PUTBYTE_TO_STATUS(card, (w < 10) ? '0'+w : 'A'-10+w);
+	}
+	PUTBYTE_TO_STATUS(card, '\n');
 
-    restore_flags(flags);
-    
-    cmd.command = ISDN_STAT_STAVAIL;
-    cmd.driver = card->myid;
-    cmd.arg = len*3+5;
-    card->interface.statcallb(&cmd);
+	cmd.command = ISDN_STAT_STAVAIL;
+	cmd.driver = card->myid;
+	cmd.arg = len*3+5;
+	card->interface.statcallb(&cmd);
 }
 
 /* ------------------------------------------------------------------- */
@@ -1990,8 +2045,8 @@
 		return capidrv_command(c, card);
 
 	printk(KERN_ERR
-	     "capidrv-%d: if_command %d called with invalid driverId %d!\n",
-	       card->contrnr, c->command, c->driver);
+	     "capidrv: if_command %d called with invalid driverId %d!\n",
+						c->command, c->driver);
 	return -ENODEV;
 }
 
@@ -2147,50 +2202,6 @@
 	send_message(card, &cmdcmsg);
 }
 
-static void disable_dchannel_trace(capidrv_contr *card)
-{
-        __u8 manufacturer[CAPI_MANUFACTURER_LEN];
-        capi_version version;
-	__u16 contr = card->contrnr;
-	__u16 errcode;
-	__u16 avmversion[3];
-
-        errcode = (*capifuncs->capi_get_manufacturer)(contr, manufacturer);
-        if (errcode != CAPI_NOERROR) {
-	   printk(KERN_ERR "%s: can't get manufacturer (0x%x)\n",
-			card->name, errcode);
-	   return;
-	}
-	if (strstr(manufacturer, "AVM") == 0) {
-	   printk(KERN_ERR "%s: not from AVM, no d-channel trace possible (%s)\n",
-			card->name, manufacturer);
-	   return;
-	}
-        errcode = (*capifuncs->capi_get_version)(contr, &version);
-        if (errcode != CAPI_NOERROR) {
-	   printk(KERN_ERR "%s: can't get version (0x%x)\n",
-			card->name, errcode);
-	   return;
-	}
-	avmversion[0] = (version.majormanuversion >> 4) & 0x0f;
-	avmversion[1] = (version.majormanuversion << 4) & 0xf0;
-	avmversion[1] |= (version.minormanuversion >> 4) & 0x0f;
-	avmversion[2] |= version.minormanuversion & 0x0f;
-
-        if (avmversion[0] > 3 || (avmversion[0] == 3 && avmversion[1] > 5)) {
-		printk(KERN_INFO "%s: D2 trace disabled\n", card->name);
-	} else {
-		printk(KERN_INFO "%s: D3 trace disabled\n", card->name);
-	}
-	capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.appid,
-				   card->msgid++,
-				   contr,
-				   0x214D5641,  /* ManuID */
-				   0,           /* Class */
-				   1,           /* Function */
-				   (_cstruct)"\004\000\000\000\000");
-	send_message(card, &cmdcmsg);
-}
 
 static void send_listen(capidrv_contr *card)
 {
@@ -2218,14 +2229,18 @@
 static int capidrv_addcontr(__u16 contr, struct capi_profile *profp)
 {
 	capidrv_contr *card;
+	long flags;
 	isdn_ctrl cmd;
 	char id[20];
 	int i;
 
+	MOD_INC_USE_COUNT;
+
 	sprintf(id, "capidrv-%d", contr);
 	if (!(card = (capidrv_contr *) kmalloc(sizeof(capidrv_contr), GFP_ATOMIC))) {
 		printk(KERN_WARNING
 		 "capidrv: (%s) Could not allocate contr-struct.\n", id);
+		MOD_DEC_USE_COUNT;
 		return -1;
 	}
 	memset(card, 0, sizeof(capidrv_contr));
@@ -2238,6 +2253,7 @@
 		printk(KERN_WARNING
 		"capidrv: (%s) Could not allocate bchan-structs.\n", id);
 		kfree(card);
+		MOD_DEC_USE_COUNT;
 		return -1;
 	}
 	card->interface.channels = profp->nbchannel;
@@ -2246,41 +2262,49 @@
 	card->interface.writebuf_skb = if_sendbuf;
 	card->interface.writecmd = 0;
 	card->interface.readstat = if_readstat;
-	card->interface.features = ISDN_FEATURE_L2_X75I |
-	    ISDN_FEATURE_L2_X75UI |
-	    ISDN_FEATURE_L2_X75BUI |
-	    ISDN_FEATURE_L2_HDLC |
-	    ISDN_FEATURE_L2_TRANS |
-	    ISDN_FEATURE_L3_TRANS |
-	    ISDN_FEATURE_L2_V11096 |
-	    ISDN_FEATURE_L2_V11019 |
-	    ISDN_FEATURE_L2_V11038 |
-	    ISDN_FEATURE_P_UNKNOWN;
+	card->interface.features = ISDN_FEATURE_L2_HDLC |
+	    			   ISDN_FEATURE_L2_TRANS |
+	    			   ISDN_FEATURE_L3_TRANS |
+				   ISDN_FEATURE_P_UNKNOWN |
+				   ISDN_FEATURE_L2_X75I |
+				   ISDN_FEATURE_L2_X75UI |
+				   ISDN_FEATURE_L2_X75BUI;
+	if (profp->support1 & (1<<2))
+		card->interface.features |= ISDN_FEATURE_L2_V11096 |
+	    				    ISDN_FEATURE_L2_V11019 |
+	    				    ISDN_FEATURE_L2_V11038;
+	if (profp->support1 & (1<<8))
+		card->interface.features |= ISDN_FEATURE_L2_MODEM;
 	card->interface.hl_hdrlen = 22; /* len of DATA_B3_REQ */
 	strncpy(card->interface.id, id, sizeof(card->interface.id) - 1);
-	card->next = global.contr_list;
-	global.contr_list = card;
-	global.ncontr++;
+
+
 	card->q931_read = card->q931_buf;
 	card->q931_write = card->q931_buf;
 	card->q931_end = card->q931_buf + sizeof(card->q931_buf) - 1;
 
 	if (!register_isdn(&card->interface)) {
-		global.contr_list = global.contr_list->next;
 		printk(KERN_ERR "capidrv: Unable to register contr %s\n", id);
 		kfree(card->bchans);
 		kfree(card);
+		MOD_DEC_USE_COUNT;
 		return -1;
 	}
 	card->myid = card->interface.channels;
 
+	spin_lock_irqsave(&global_lock, flags);
+	card->next = global.contr_list;
+	global.contr_list = card;
+	global.ncontr++;
+	spin_unlock_irqrestore(&global_lock, flags);
+
 	memset(card->bchans, 0, sizeof(capidrv_bchan) * card->nbchan);
 	for (i = 0; i < card->nbchan; i++) {
 		card->bchans[i].contr = card;
 	}
 
-	cmd.driver = card->myid;
 	cmd.command = ISDN_STAT_RUN;
+	cmd.driver = card->myid;
 	card->interface.statcallb(&cmd);
 
 	card->cipmask = 0x1FFF03FF;	/* any */
@@ -2303,45 +2327,82 @@
 static int capidrv_delcontr(__u16 contr)
 {
 	capidrv_contr **pp, *card;
+	unsigned long flags;
 	isdn_ctrl cmd;
-	int i;
 
-	for (pp = &global.contr_list; *pp; pp = &(*pp)->next) {
-		if ((*pp)->contrnr == contr)
+	spin_lock_irqsave(&global_lock, flags);
+	for (card = global.contr_list; card; card = card->next) {
+		if (card->contrnr == contr)
 			break;
 	}
-	if (!*pp) {
+	if (!card) {
+		spin_unlock_irqrestore(&global_lock, flags);
 		printk(KERN_ERR "capidrv: delcontr: no contr %u\n", contr);
 		return -1;
 	}
-	card = *pp;
+	spin_unlock_irqrestore(&global_lock, flags);
+
+	del_timer(&card->listentimer);
 
 	if (debugmode)
 		printk(KERN_DEBUG "capidrv-%d: id=%d unloading\n",
 					card->contrnr, card->myid);
 
-	cmd.command = ISDN_STAT_UNLOAD;
+	cmd.command = ISDN_STAT_STOP;
 	cmd.driver = card->myid;
 	card->interface.statcallb(&cmd);
 
-	*pp = (*pp)->next;
-	global.ncontr--;
+	while (card->nbchan) {
 
-	for (i = 0; i < card->nbchan; i++) {
-		if (card->bchans[i].nccip)
-			free_ncci(card, card->bchans[i].nccip);
-		if (card->bchans[i].plcip)
-			free_plci(card, card->bchans[i].plcip);
+		cmd.command = ISDN_STAT_DISCH;
+		cmd.driver = card->myid;
+		cmd.arg = card->nbchan-1;
+	        cmd.parm.num[0] = 0;
+		if (debugmode)
+			printk(KERN_DEBUG "capidrv-%d: id=%d disable chan=%ld\n",
+					card->contrnr, card->myid, cmd.arg);
+		card->interface.statcallb(&cmd);
+
+		if (card->bchans[card->nbchan-1].nccip)
+			free_ncci(card, card->bchans[card->nbchan-1].nccip);
+		if (card->bchans[card->nbchan-1].plcip)
+			free_plci(card, card->bchans[card->nbchan-1].plcip);
 		if (card->plci_list)
 			printk(KERN_ERR "capidrv: bug in free_plci()\n");
+		card->nbchan--;
 	}
 	kfree(card->bchans);
-	del_timer(&card->listentimer);
+	card->bchans = 0;
+
+	if (debugmode)
+		printk(KERN_DEBUG "capidrv-%d: id=%d isdn unload\n",
+					card->contrnr, card->myid);
+
+	cmd.command = ISDN_STAT_UNLOAD;
+	cmd.driver = card->myid;
+	card->interface.statcallb(&cmd);
+
+	if (debugmode)
+		printk(KERN_DEBUG "capidrv-%d: id=%d remove contr from list\n",
+					card->contrnr, card->myid);
+
+	spin_lock_irqsave(&global_lock, flags);
+	for (pp = &global.contr_list; *pp; pp = &(*pp)->next) {
+		if (*pp == card) {
+			*pp = (*pp)->next;
+			card->next = 0;
+			global.ncontr--;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&global_lock, flags);
 
 	printk(KERN_INFO "%s: now down.\n", card->name);
 
 	kfree(card);
 
+	MOD_DEC_USE_COUNT;
+
 	return 0;
 }
 
@@ -2394,7 +2455,7 @@
    { "capi/capidrv", 	  0	 , proc_capidrv_read_proc },
 };
 
-static void proc_init(void)
+static void __init proc_init(void)
 {
     int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
     int i;
@@ -2406,7 +2467,7 @@
     }
 }
 
-static void proc_exit(void)
+static void  proc_exit(void)
 {
     int nelem = sizeof(procfsentries)/sizeof(procfsentries[0]);
     int i;
@@ -2421,15 +2482,11 @@
 }
 
 static struct capi_interface_user cuser = {
-	"capidrv",
-	lower_callback
+	name: "capidrv",
+	callback: lower_callback
 };
 
-#ifdef MODULE
-#define capidrv_init init_module
-#endif
-
-int capidrv_init(void)
+static int __init capidrv_init(void)
 {
 	struct capi_register_params rparam;
 	capi_profile profile;
@@ -2438,10 +2495,14 @@
 	__u32 ncontr, contr;
 	__u16 errcode;
 
+	MOD_INC_USE_COUNT;
+
 	capifuncs = attach_capi_interface(&cuser);
 
-	if (!capifuncs)
+	if (!capifuncs) {
+		MOD_DEC_USE_COUNT;
 		return -EIO;
+	}
 
 	if ((p = strchr(revision, ':'))) {
 		strcpy(rev, p + 1);
@@ -2456,6 +2517,7 @@
 	errcode = (*capifuncs->capi_register) (&rparam, &global.appid);
 	if (errcode) {
 		detach_capi_interface(&cuser);
+		MOD_DEC_USE_COUNT;
 		return -EIO;
 	}
 
@@ -2463,6 +2525,7 @@
 	if (errcode != CAPI_NOERROR) {
 		(void) (*capifuncs->capi_release) (global.appid);
 		detach_capi_interface(&cuser);
+		MOD_DEC_USE_COUNT;
 		return -EIO;
 	}
 
@@ -2477,17 +2540,18 @@
 	}
 	proc_init();
 
+	printk(KERN_NOTICE "capidrv: Rev%s: loaded\n", rev);
+	MOD_DEC_USE_COUNT;
+
 	return 0;
 }
 
-#ifdef MODULE
-void cleanup_module(void)
+static void  capidrv_exit(void)
 {
-	capidrv_contr *card, *next;
 	char rev[10];
 	char *p;
 
-	if ((p = strchr(revision, ':'))) {
+	if ((p = strchr(revision, ':')) != 0) {
 		strcpy(rev, p + 1);
 		p = strchr(rev, '$');
 		*p = 0;
@@ -2495,17 +2559,14 @@
 		strcpy(rev, " ??? ");
 	}
 
-	for (card = global.contr_list; card; card = next) {
-		next = card->next;
-		disable_dchannel_trace(card);
-		capidrv_delcontr(card->contrnr);
-	}
-
 	(void) (*capifuncs->capi_release) (global.appid);
+
 	detach_capi_interface(&cuser);
+
 	proc_exit();
 
 	printk(KERN_NOTICE "capidrv: Rev%s: unloaded\n", rev);
 }
 
-#endif
+module_init(capidrv_init);
+module_exit(capidrv_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/avmb1/capifs.c linux.19p18/drivers/isdn/avmb1/capifs.c
--- linux.vanilla/drivers/isdn/avmb1/capifs.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/avmb1/capifs.c	Wed Feb 14 14:28:52 2001
@@ -0,0 +1,626 @@
+/*
+ * $Id: capifs.c,v 1.14.6.3 2001/02/13 11:43:29 kai Exp $
+ * 
+ * (c) Copyright 2000 by Carsten Paeth (calle@calle.de)
+ *
+ * Heavily based on devpts filesystem from H. Peter Anvin
+ * 
+ * $Log: capifs.c,v $
+ * Revision 1.14.6.3  2001/02/13 11:43:29  kai
+ * more compatility changes for 2.2.19
+ *
+ * Revision 1.14.6.2  2001/02/10 14:41:20  kai
+ * Changes from kernel tree
+ *
+ * Revision 1.14.6.1  2000/11/28 12:02:45  kai
+ * MODULE_DEVICE_TABLE for 2.4
+ *
+ * Revision 1.14.2.1  2000/11/26 17:47:53  kai
+ * added PCI_DEV_TABLE for 2.4
+ *
+ * Revision 1.14  2000/11/23 20:45:14  kai
+ * fixed module_init/exit stuff
+ * Note: compiled-in kernel doesn't work pre 2.2.18 anymore.
+ *
+ * Revision 1.13  2000/11/18 16:17:25  kai
+ * change from 2.4 tree
+ *
+ * Revision 1.12  2000/11/01 14:05:02  calle
+ * - use module_init/module_exit from linux/init.h.
+ * - all static struct variables are initialized with "membername:" now.
+ * - avm_cs.c, let it work with newer pcmcia-cs.
+ *
+ * Revision 1.11  2000/10/24 15:08:47  calle
+ * Too much includes.
+ *
+ * Revision 1.10  2000/10/12 10:12:35  calle
+ * Bugfix: second iput(inode) on umount, destroies a foreign inode.
+ *
+ * Revision 1.9  2000/08/20 07:30:13  keil
+ * changes for 2.4
+ *
+ * Revision 1.8  2000/07/20 10:23:13  calle
+ * Include isdn_compat.h for people that don't use -p option of std2kern.
+ *
+ * Revision 1.7  2000/06/18 16:09:54  keil
+ * more changes for 2.4
+ *
+ * Revision 1.6  2000/04/03 13:29:25  calle
+ * make Tim Waugh happy (module unload races in 2.3.99-pre3).
+ * no real problem there, but now it is much cleaner ...
+ *
+ * Revision 1.5  2000/03/13 17:49:52  calle
+ * make it running with 2.3.51.
+ *
+ * Revision 1.4  2000/03/08 17:06:33  calle
+ * - changes for devfs and 2.3.49
+ * - capifs now configurable (no need with devfs)
+ * - New Middleware ioctl CAPI_NCCI_GETUNIT
+ * - Middleware again tested with 2.2.14 and 2.3.49 (with and without devfs)
+ *
+ * Revision 1.3  2000/03/06 18:00:23  calle
+ * - Middleware extention now working with 2.3.49 (capifs).
+ * - Fixed typos in debug section of capi.c
+ * - Bugfix: Makefile corrected for b1pcmcia.c
+ *
+ * Revision 1.2  2000/03/06 09:17:07  calle
+ * - capifs: fileoperations now in inode (change for 2.3.49)
+ * - Config.in: Middleware extention not a tristate, uups.
+ *
+ * Revision 1.1  2000/03/03 16:48:38  calle
+ * - Added CAPI2.0 Middleware support (CONFIG_ISDN_CAPI)
+ *   It is now possible to create a connection with a CAPI2.0 applikation
+ *   and than to handle the data connection from /dev/capi/ (capifs) and also
+ *   using async or sync PPP on this connection.
+ *   The two major device number 190 and 191 are not confirmed yet,
+ *   but I want to save the code in cvs, before I go on.
+ *
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/fs.h>
+#include <linux/tty.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/stat.h>
+#include <linux/param.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/kdev_t.h>
+#include <linux/kernel.h>
+#include <linux/locks.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+
+MODULE_AUTHOR("Carsten Paeth <calle@calle.de>");
+
+static char *revision = "$Revision: 1.14.6.3 $";
+
+struct capifs_ncci {
+	struct inode *inode;
+	char used;
+	char type;
+	unsigned int num;
+	kdev_t kdev;
+};
+
+struct capifs_sb_info {
+	u32 magic;
+	struct super_block *next;
+	struct super_block **back;
+	int setuid;
+	int setgid;
+	uid_t   uid;
+	gid_t   gid;
+	umode_t mode;
+
+	unsigned int max_ncci;
+	struct capifs_ncci *nccis;
+};
+
+#define CAPIFS_SUPER_MAGIC (('C'<<8)|'N')
+#define CAPIFS_SBI_MAGIC   (('C'<<24)|('A'<<16)|('P'<<8)|'I')
+
+static inline struct capifs_sb_info *SBI(struct super_block *sb)
+{
+	return (struct capifs_sb_info *)(sb->u.generic_sbp);
+}
+
+/* ------------------------------------------------------------------ */
+
+static int capifs_root_readdir(struct file *,void *,filldir_t);
+static struct dentry *capifs_root_lookup(struct inode *,struct dentry *);
+static int capifs_revalidate(struct dentry *, int);
+
+static struct file_operations capifs_root_operations = {
+	readdir:	capifs_root_readdir,
+};
+
+struct inode_operations capifs_root_inode_operations = {
+	default_file_ops: &capifs_root_operations, /* file operations */
+	lookup: capifs_root_lookup,
+};
+
+static struct dentry_operations capifs_dentry_operations = {
+	d_revalidate: capifs_revalidate,
+};
+
+/*
+ * /dev/capi/%d
+ * /dev/capi/r%d
+ */
+
+static int capifs_root_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+	struct inode * inode = filp->f_dentry->d_inode;
+	struct capifs_sb_info * sbi = SBI(filp->f_dentry->d_inode->i_sb);
+	off_t nr;
+	char numbuf[32];
+
+	nr = filp->f_pos;
+
+	switch(nr)
+	{
+	case 0:
+		if (filldir(dirent, ".", 1, nr, inode->i_ino) < 0)
+			return 0;
+		filp->f_pos = ++nr;
+		/* fall through */
+	case 1:
+		if (filldir(dirent, "..", 2, nr, inode->i_ino) < 0)
+			return 0;
+		filp->f_pos = ++nr;
+		/* fall through */
+	default:
+		while (nr < sbi->max_ncci) {
+			int n = nr - 2;
+			struct capifs_ncci *np = &sbi->nccis[n];
+			if (np->inode && np->used) {
+				char *p = numbuf;
+				if (np->type) *p++ = np->type;
+				sprintf(p, "%u", np->num);
+				if ( filldir(dirent, numbuf, strlen(numbuf), nr, nr) < 0 )
+					return 0;
+			}
+			filp->f_pos = ++nr;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+/*
+ * Revalidate is called on every cache lookup.  We use it to check that
+ * the ncci really does still exist.  Never revalidate negative dentries;
+ * for simplicity (fix later?)
+ */
+static int capifs_revalidate(struct dentry * dentry, int flags)
+{
+	struct capifs_sb_info *sbi;
+
+	if ( !dentry->d_inode )
+		return 0;
+
+	sbi = SBI(dentry->d_inode->i_sb);
+
+	return ( sbi->nccis[dentry->d_inode->i_ino - 2].inode == dentry->d_inode );
+}
+
+static struct dentry *capifs_root_lookup(struct inode * dir, struct dentry * dentry)
+{
+	struct capifs_sb_info *sbi = SBI(dir->i_sb);
+	struct capifs_ncci *np;
+	unsigned int i;
+	char numbuf[32];
+	char *p, *tmp;
+	unsigned int num;
+	char type = 0;
+
+	dentry->d_inode = NULL;	/* Assume failure */
+	dentry->d_op    = &capifs_dentry_operations;
+
+	if (dentry->d_name.len >= sizeof(numbuf) )
+		return NULL;
+	strncpy(numbuf, dentry->d_name.name, dentry->d_name.len);
+	numbuf[dentry->d_name.len] = 0;
+        p = numbuf;
+	if (!isdigit(*p)) type = *p++;
+	tmp = p;
+	num = (unsigned int)simple_strtoul(p, &tmp, 10);
+	if (tmp == p || *tmp)
+		return NULL;
+
+	for (i = 0, np = sbi->nccis ; i < sbi->max_ncci; i++, np++) {
+		if (np->used && np->num == num && np->type == type)
+			break;
+	}
+
+	if ( i >= sbi->max_ncci )
+		return NULL;
+
+	dentry->d_inode = np->inode;
+	if ( dentry->d_inode )
+		dentry->d_inode->i_count++;
+	
+	d_add(dentry, dentry->d_inode);
+
+	return NULL;
+}
+
+/* ------------------------------------------------------------------ */
+
+static struct super_block *mounts = NULL;
+
+static void capifs_put_super(struct super_block *sb)
+{
+	struct capifs_sb_info *sbi = SBI(sb);
+	struct inode *inode;
+	int i;
+
+	for ( i = 0 ; i < sbi->max_ncci ; i++ ) {
+		if ( (inode = sbi->nccis[i].inode) ) {
+			if (inode->i_count != 1 )
+				printk("capifs_put_super: badness: entry %d count %d\n",
+				       i, (unsigned)inode->i_count);
+			inode->i_nlink--;
+			iput(inode);
+		}
+	}
+
+	*sbi->back = sbi->next;
+	if ( sbi->next )
+		SBI(sbi->next)->back = sbi->back;
+
+	kfree(sbi->nccis);
+	kfree(sbi);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51)
+	MOD_DEC_USE_COUNT;
+#endif
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51)
+static int capifs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
+static void capifs_write_inode(struct inode *inode) { };
+#else
+static int capifs_statfs(struct super_block *sb, struct statfs *buf);
+#endif
+static void capifs_read_inode(struct inode *inode);
+
+static struct super_operations capifs_sops = {
+	read_inode:	capifs_read_inode,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51)
+	write_inode:	capifs_write_inode,
+#endif
+	put_super:	capifs_put_super,
+	statfs:		capifs_statfs,
+};
+
+static int capifs_parse_options(char *options, struct capifs_sb_info *sbi)
+{
+	int setuid = 0;
+	int setgid = 0;
+	uid_t uid = 0;
+	gid_t gid = 0;
+	umode_t mode = 0600;
+	unsigned int maxncci = 512;
+	char *this_char, *value;
+
+	this_char = NULL;
+	if ( options )
+		this_char = strtok(options,",");
+	for ( ; this_char; this_char = strtok(NULL,",")) {
+		if ((value = strchr(this_char,'=')) != NULL)
+			*value++ = 0;
+		if (!strcmp(this_char,"uid")) {
+			if (!value || !*value)
+				return 1;
+			uid = simple_strtoul(value,&value,0);
+			if (*value)
+				return 1;
+			setuid = 1;
+		}
+		else if (!strcmp(this_char,"gid")) {
+			if (!value || !*value)
+				return 1;
+			gid = simple_strtoul(value,&value,0);
+			if (*value)
+				return 1;
+			setgid = 1;
+		}
+		else if (!strcmp(this_char,"mode")) {
+			if (!value || !*value)
+				return 1;
+			mode = simple_strtoul(value,&value,8);
+			if (*value)
+				return 1;
+		}
+		else if (!strcmp(this_char,"maxncci")) {
+			if (!value || !*value)
+				return 1;
+			maxncci = simple_strtoul(value,&value,8);
+			if (*value)
+				return 1;
+		}
+		else
+			return 1;
+	}
+	sbi->setuid   = setuid;
+	sbi->setgid   = setgid;
+	sbi->uid      = uid;
+	sbi->gid      = gid;
+	sbi->mode     = mode & ~S_IFMT;
+	sbi->max_ncci = maxncci;
+
+	return 0;
+}
+
+struct super_block *capifs_read_super(struct super_block *s, void *data,
+				      int silent)
+{
+	struct inode * root_inode;
+	struct dentry * root;
+	struct capifs_sb_info *sbi;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51)
+	MOD_INC_USE_COUNT;
+	lock_super(s);
+#endif
+	/* Super block already completed? */
+	if (s->s_root)
+		goto out;
+
+	sbi = (struct capifs_sb_info *) kmalloc(sizeof(struct capifs_sb_info), GFP_KERNEL);
+	if ( !sbi )
+		goto fail;
+
+	memset(sbi, 0, sizeof(struct capifs_sb_info));
+	sbi->magic  = CAPIFS_SBI_MAGIC;
+
+	if ( capifs_parse_options(data,sbi) ) {
+		kfree(sbi);
+		printk("capifs: called with bogus options\n");
+		goto fail;
+	}
+
+	sbi->nccis = kmalloc(sizeof(struct capifs_ncci) * sbi->max_ncci, GFP_KERNEL);
+	if ( !sbi->nccis ) {
+		kfree(sbi);
+		goto fail;
+	}
+	memset(sbi->nccis, 0, sizeof(struct capifs_ncci) * sbi->max_ncci);
+
+	s->u.generic_sbp = (void *) sbi;
+	s->s_blocksize = 1024;
+	s->s_blocksize_bits = 10;
+	s->s_magic = CAPIFS_SUPER_MAGIC;
+	s->s_op = &capifs_sops;
+	s->s_root = NULL;
+
+	/*
+	 * Get the root inode and dentry, but defer checking for errors.
+	 */
+	root_inode = iget(s, 1); /* inode 1 == root directory */
+	root = d_alloc_root(root_inode, NULL);
+
+	/*
+	 * Check whether somebody else completed the super block.
+	 */
+	if (s->s_root) {
+		if (root) dput(root);
+		else iput(root_inode);
+		goto out;
+	}
+
+	if (!root) {
+		printk("capifs: get root dentry failed\n");
+		/*
+	 	* iput() can block, so we clear the super block first.
+	 	*/
+		iput(root_inode);
+		kfree(sbi->nccis);
+		kfree(sbi);
+		goto fail;
+	}
+
+	/*
+	 * Check whether somebody else completed the super block.
+	 */
+	if (s->s_root)
+		goto out;
+	
+	/*
+	 * Success! Install the root dentry now to indicate completion.
+	 */
+	s->s_root = root;
+
+	sbi->next = mounts;
+	if ( sbi->next )
+		SBI(sbi->next)->back = &(sbi->next);
+	sbi->back = &mounts;
+	mounts = s;
+
+out:	/* Success ... somebody else completed the super block for us. */ 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51)
+	unlock_super(s);
+#endif
+	return s;
+fail:
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51)
+	unlock_super(s);
+	MOD_DEC_USE_COUNT;
+#endif
+	return NULL;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51)
+static int capifs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
+{
+	struct statfs tmp;
+
+	tmp.f_type = CAPIFS_SUPER_MAGIC;
+	tmp.f_bsize = 1024;
+	tmp.f_blocks = 0;
+	tmp.f_bfree = 0;
+	tmp.f_bavail = 0;
+	tmp.f_files = 0;
+	tmp.f_ffree = 0;
+	tmp.f_namelen = NAME_MAX;
+	return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+}
+#else
+static int capifs_statfs(struct super_block *sb, struct statfs *buf)
+{
+	buf->f_type = CAPIFS_SUPER_MAGIC;
+	buf->f_bsize = 1024;
+	buf->f_blocks = 0;
+	buf->f_bfree = 0;
+	buf->f_bavail = 0;
+	buf->f_files = 0;
+	buf->f_ffree = 0;
+	buf->f_namelen = NAME_MAX;
+	return 0;
+}
+#endif
+
+static void capifs_read_inode(struct inode *inode)
+{
+	ino_t ino = inode->i_ino;
+	struct capifs_sb_info *sbi = SBI(inode->i_sb);
+
+	inode->i_mode = 0;
+	inode->i_nlink = 0;
+	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+	inode->i_blocks = 0;
+	inode->i_blksize = 1024;
+	inode->i_uid = inode->i_gid = 0;
+
+	if ( ino == 1 ) {
+		inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
+		inode->i_op = &capifs_root_inode_operations;
+		inode->i_nlink = 2;
+		return;
+	} 
+
+	ino -= 2;
+	if ( ino >= sbi->max_ncci )
+		return;		/* Bogus */
+	
+	inode->i_mode = S_IFCHR;
+	inode->i_op = &chrdev_inode_operations;
+
+	return;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,51)
+static struct file_system_type capifs_fs_type = {
+	"capifs",
+	0,
+	capifs_read_super,
+	NULL
+};
+#else
+static DECLARE_FSTYPE(capifs_fs_type, "capifs", capifs_read_super, 0);
+#endif
+
+void capifs_new_ncci(char type, unsigned int num, kdev_t device)
+{
+	struct super_block *sb;
+	struct capifs_sb_info *sbi;
+	struct capifs_ncci *np;
+	ino_t ino;
+
+	for ( sb = mounts ; sb ; sb = sbi->next ) {
+		sbi = SBI(sb);
+
+		for (ino = 0, np = sbi->nccis ; ino < sbi->max_ncci; ino++, np++) {
+			if (np->used == 0) {
+				np->used = 1;
+				np->type = type;
+				np->num = num;
+				np->kdev = device;
+				break;
+			}
+		}
+
+		if ((np->inode = iget(sb, ino+2)) != 0) {
+			struct inode *inode = np->inode;
+			inode->i_uid = sbi->setuid ? sbi->uid : current->fsuid;
+			inode->i_gid = sbi->setgid ? sbi->gid : current->fsgid;
+			inode->i_mode = sbi->mode | S_IFCHR;
+			inode->i_rdev = np->kdev;
+			inode->i_nlink++;
+		}
+	}
+}
+
+void capifs_free_ncci(char type, unsigned int num)
+{
+	struct super_block *sb;
+	struct capifs_sb_info *sbi;
+	struct inode *inode;
+	struct capifs_ncci *np;
+	ino_t ino;
+
+	for ( sb = mounts ; sb ; sb = sbi->next ) {
+		sbi = SBI(sb);
+
+		for (ino = 0, np = sbi->nccis ; ino < sbi->max_ncci; ino++, np++) {
+			if (!np->used || np->type != type || np->num != num)
+				continue;
+			if (np->inode) {
+				inode = np->inode;
+				np->inode = 0;
+				np->used = 0;
+				inode->i_nlink--;
+				iput(inode);
+				break;
+			}
+		}
+	}
+}
+
+static int __init capifs_init(void)
+{
+	char rev[10];
+	char *p;
+	int err;
+
+	MOD_INC_USE_COUNT;
+
+	if ((p = strchr(revision, ':'))) {
+		strcpy(rev, p + 1);
+		p = strchr(rev, '$');
+		*p = 0;
+	} else
+		strcpy(rev, "1.0");
+
+	err = register_filesystem(&capifs_fs_type);
+	if (err) {
+		MOD_DEC_USE_COUNT;
+		return err;
+	}
+#ifdef MODULE
+        printk(KERN_NOTICE "capifs: Rev%s: loaded\n", rev);
+#else
+	printk(KERN_NOTICE "capifs: Rev%s: started\n", rev);
+#endif
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static void  capifs_exit(void)
+{
+	unregister_filesystem(&capifs_fs_type);
+}
+
+EXPORT_SYMBOL(capifs_new_ncci);
+EXPORT_SYMBOL(capifs_free_ncci);
+
+module_init(capifs_init);
+module_exit(capifs_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/avmb1/capifs.h linux.19p18/drivers/isdn/avmb1/capifs.h
--- linux.vanilla/drivers/isdn/avmb1/capifs.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/avmb1/capifs.h	Wed Dec 13 22:06:44 2000
@@ -0,0 +1,25 @@
+/*
+ * $Id: capifs.h,v 1.2 2000/03/08 17:06:33 calle Exp $
+ * 
+ * (c) Copyright 2000 by Carsten Paeth (calle@calle.de)
+ *
+ * $Log: capifs.h,v $
+ * Revision 1.2  2000/03/08 17:06:33  calle
+ * - changes for devfs and 2.3.49
+ * - capifs now configurable (no need with devfs)
+ * - New Middleware ioctl CAPI_NCCI_GETUNIT
+ * - Middleware again tested with 2.2.14 and 2.3.49 (with and without devfs)
+ *
+ * Revision 1.1  2000/03/03 16:48:38  calle
+ * - Added CAPI2.0 Middleware support (CONFIG_ISDN_CAPI)
+ *   It is now possible to create a connection with a CAPI2.0 applikation
+ *   and than to handle the data connection from /dev/capi/ (capifs) and also
+ *   using async or sync PPP on this connection.
+ *   The two major device number 190 and 191 are not confirmed yet,
+ *   but I want to save the code in cvs, before I go on.
+ *
+ *
+ */
+
+void capifs_new_ncci(char type, unsigned int num, kdev_t device);
+void capifs_free_ncci(char type, unsigned int num);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/avmb1/capiutil.c linux.19p18/drivers/isdn/avmb1/capiutil.c
--- linux.vanilla/drivers/isdn/avmb1/capiutil.c	Fri Apr 21 12:46:08 2000
+++ linux.19p18/drivers/isdn/avmb1/capiutil.c	Wed Feb 14 14:28:52 2001
@@ -1,5 +1,5 @@
 /*
- * $Id: capiutil.c,v 1.10 1999/08/31 11:19:54 paul Exp $
+ * $Id: capiutil.c,v 1.13.6.1 2001/02/13 11:43:29 kai Exp $
  *
  * CAPI 2.0 convert capi message to capi message struct
  *
@@ -7,6 +7,29 @@
  * Rewritten for Linux 1996 by Carsten Paeth (calle@calle.in-berlin.de)
  *
  * $Log: capiutil.c,v $
+ * Revision 1.13.6.1  2001/02/13 11:43:29  kai
+ * more compatility changes for 2.2.19
+ *
+ * Revision 1.13  2000/11/23 20:45:14  kai
+ * fixed module_init/exit stuff
+ * Note: compiled-in kernel doesn't work pre 2.2.18 anymore.
+ *
+ * Revision 1.12  2000/11/01 14:05:02  calle
+ * - use module_init/module_exit from linux/init.h.
+ * - all static struct variables are initialized with "membername:" now.
+ * - avm_cs.c, let it work with newer pcmcia-cs.
+ *
+ * Revision 1.11  2000/03/03 15:50:42  calle
+ * - kernel CAPI:
+ *   - Changed parameter "param" in capi_signal from __u32 to void *.
+ *   - rewrote notifier handling in kcapi.c
+ *   - new notifier NCCI_UP and NCCI_DOWN
+ * - User CAPI:
+ *   - /dev/capi20 is now a cloning device.
+ *   - middleware extentions prepared.
+ * - capidrv.c
+ *   - locking of list operations and module count updates.
+ *
  * Revision 1.10  1999/08/31 11:19:54  paul
  * various spelling corrections (new checksums may be needed, Karsten!)
  *
@@ -70,6 +93,7 @@
 #include <linux/stddef.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/init.h>
 #include <asm/segment.h>
 #include <linux/config.h>
 
@@ -794,7 +818,7 @@
     /*15 */ "Class",
     /*16 */ "ConnectedNumber",
     /*17 */ "ConnectedSubaddress",
-    /*18 */ "Data",
+    /*18 */ "Data32",
     /*19 */ "DataHandle",
     /*1a */ "DataLength",
     /*1b */ "FacilityConfirmationParameter",
@@ -892,13 +916,7 @@
 			cmsg->l += 2;
 			break;
 		case _CDWORD:
-			if (strcmp(NAME, "Data") == 0) {
-				bufprint("%-*s = ", slen, NAME);
-				printstructlen((__u8 *) * (__u32 *) (cmsg->m + cmsg->l),
-					       *(__u16 *) (cmsg->m + cmsg->l + sizeof(__u32)));
-				bufprint("\n");
-			} else
-				bufprint("%-*s = 0x%lx\n", slen, NAME, *(__u32 *) (cmsg->m + cmsg->l));
+			bufprint("%-*s = 0x%lx\n", slen, NAME, *(__u32 *) (cmsg->m + cmsg->l));
 			cmsg->l += 4;
 			break;
 		case _CSTRUCT:
@@ -973,7 +991,6 @@
 	return buf;
 }
 
-
 EXPORT_SYMBOL(capi_cmsg2message);
 EXPORT_SYMBOL(capi_message2cmsg);
 EXPORT_SYMBOL(capi_cmsg_header);
@@ -982,15 +999,14 @@
 EXPORT_SYMBOL(capi_message2str);
 EXPORT_SYMBOL(capi_info2str);
 
-#ifdef MODULE
-
-int init_module(void)
-{
-	return 0;
+static int __init capiutil_init(void)
+{ 
+	return 0; 
 }
 
-void cleanup_module(void)
+static void  capiutil_exit(void)
 {
 }
 
-#endif
+module_init(capiutil_init);
+module_exit(capiutil_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/avmb1/capiutil.h linux.19p18/drivers/isdn/avmb1/capiutil.h
--- linux.vanilla/drivers/isdn/avmb1/capiutil.h	Fri Apr 21 23:23:03 2000
+++ linux.19p18/drivers/isdn/avmb1/capiutil.h	Wed Dec 13 22:06:44 2000
@@ -1,5 +1,5 @@
 /*
- * $Id: capiutil.h,v 1.4 1999/09/15 08:16:03 calle Exp $
+ * $Id: capiutil.h,v 1.5 2000/03/03 15:50:42 calle Exp $
  * 
  * CAPI 2.0 defines & types
  * 
@@ -7,6 +7,17 @@
  * Rewritten for Linux 1996 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: capiutil.h,v $
+ * Revision 1.5  2000/03/03 15:50:42  calle
+ * - kernel CAPI:
+ *   - Changed parameter "param" in capi_signal from __u32 to void *.
+ *   - rewrote notifier handling in kcapi.c
+ *   - new notifier NCCI_UP and NCCI_DOWN
+ * - User CAPI:
+ *   - /dev/capi20 is now a cloning device.
+ *   - middleware extentions prepared.
+ * - capidrv.c
+ *   - locking of list operations and module count updates.
+ *
  * Revision 1.4  1999/09/15 08:16:03  calle
  * Implementation of 64Bit extention complete.
  *
@@ -36,28 +47,47 @@
 
 #include <asm/types.h>
 
-#define	CAPIMSG_LEN(m)		(m[0] | (m[1] << 8))
-#define	CAPIMSG_APPID(m)	(m[2] | (m[3] << 8))
-#define	CAPIMSG_COMMAND(m)	(m[4])
-#define	CAPIMSG_SUBCOMMAND(m)	(m[5])
-#define	CAPIMSG_MSGID(m)	(m[6] | (m[7] << 8))
+#define CAPIMSG_BASELEN		8
+#define CAPIMSG_U8(m, off)	(m[off])
+#define CAPIMSG_U16(m, off)	(m[off]|(m[(off)+1]<<8))
+#define CAPIMSG_U32(m, off)	(m[off]|(m[(off)+1]<<8)|(m[(off)+2]<<16)|(m[(off)+3]<<24))
+#define	CAPIMSG_LEN(m)		CAPIMSG_U16(m,0)
+#define	CAPIMSG_APPID(m)	CAPIMSG_U16(m,2)
+#define	CAPIMSG_COMMAND(m)	CAPIMSG_U8(m,4)
+#define	CAPIMSG_SUBCOMMAND(m)	CAPIMSG_U8(m,5)
+#define CAPIMSG_CMD(m)		(((m[4])<<8)|(m[5]))
+#define	CAPIMSG_MSGID(m)	CAPIMSG_U16(m,6)
 #define CAPIMSG_CONTROLLER(m)	(m[8] & 0x7f)
-#define CAPIMSG_CONTROL(m)	(m[8]|(m[9]<<8)|(m[10]<<16)|(m[11]<<24))
+#define CAPIMSG_CONTROL(m)	CAPIMSG_U32(m, 8)
 #define CAPIMSG_NCCI(m)		CAPIMSG_CONTROL(m)
-#define CAPIMSG_DATA(m)		(m[12]|(m[13]<<8)|(m[14]<<16)|(m[15]<<24))
-#define CAPIMSG_DATALEN(m)	(m[16] | (m[17]<<8))
+#define CAPIMSG_DATALEN(m)	CAPIMSG_U16(m,16) /* DATA_B3_REQ */
+
+static inline void capimsg_setu8(void *m, int off, __u8 val)
+{
+	((__u8 *)m)[off] = val;
+}
+
+static inline void capimsg_setu16(void *m, int off, __u16 val)
+{
+	((__u8 *)m)[off] = val & 0xff;
+	((__u8 *)m)[off+1] = (val >> 8) & 0xff;
+}
+
+static inline void capimsg_setu32(void *m, int off, __u32 val)
+{
+	((__u8 *)m)[off] = val & 0xff;
+	((__u8 *)m)[off+1] = (val >> 8) & 0xff;
+	((__u8 *)m)[off+2] = (val >> 16) & 0xff;
+	((__u8 *)m)[off+3] = (val >> 24) & 0xff;
+}
 
-#define	CAPIMSG_SETAPPID(m, applid) \
-	do { \
-		((__u8 *)m)[2] = (__u16)(applid) & 0xff; \
-		((__u8 *)m)[3] = ((__u16)(applid) >> 8) & 0xff; \
-	} while (0)
-
-#define	CAPIMSG_SETLEN(m, len) \
-	do { \
-		((__u8 *)m)[0] = (__u16)(len) & 0xff; \
-		((__u8 *)m)[1] = ((__u16)(len) >> 8) & 0xff; \
-	} while (0)
+#define	CAPIMSG_SETLEN(m, len)		capimsg_setu16(m, 0, len)
+#define	CAPIMSG_SETAPPID(m, applid)	capimsg_setu16(m, 2, applid)
+#define	CAPIMSG_SETCOMMAND(m,cmd)	capimsg_setu8(m, 4, cmd)
+#define	CAPIMSG_SETSUBCOMMAND(m, cmd)	capimsg_setu8(m, 5, cmd)
+#define	CAPIMSG_SETMSGID(m, msgid)	capimsg_setu16(m, 6, msgid)
+#define	CAPIMSG_SETCONTROL(m, contr)	capimsg_setu32(m, 8, contr)
+#define	CAPIMSG_SETDATALEN(m, len)	capimsg_setu16(m, 16, len)
 
 /*----- basic-type definitions -----*/
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/avmb1/kcapi.c linux.19p18/drivers/isdn/avmb1/kcapi.c
--- linux.vanilla/drivers/isdn/avmb1/kcapi.c	Sun Jun 11 21:44:13 2000
+++ linux.19p18/drivers/isdn/avmb1/kcapi.c	Wed Feb 14 14:28:52 2001
@@ -1,11 +1,62 @@
 /*
- * $Id: kcapi.c,v 1.12 2000/01/28 16:45:39 calle Exp $
+ * $Id: kcapi.c,v 1.21.6.2 2001/02/13 11:43:29 kai Exp $
  * 
  * Kernel CAPI 2.0 Module
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: kcapi.c,v $
+ * Revision 1.21.6.2  2001/02/13 11:43:29  kai
+ * more compatility changes for 2.2.19
+ *
+ * Revision 1.21.6.1  2000/12/10 23:39:19  kai
+ * in 2.4 we don't have tq_scheduler anymore.
+ * also add one supported card to hfc_pci.c
+ * (from main branch)
+ *
+ * Revision 1.21  2000/11/23 20:45:14  kai
+ * fixed module_init/exit stuff
+ * Note: compiled-in kernel doesn't work pre 2.2.18 anymore.
+ *
+ * Revision 1.20  2000/11/19 17:01:53  kai
+ * compatibility cleanup - part 2
+ *
+ * Revision 1.19  2000/11/01 14:05:02  calle
+ * - use module_init/module_exit from linux/init.h.
+ * - all static struct variables are initialized with "membername:" now.
+ * - avm_cs.c, let it work with newer pcmcia-cs.
+ *
+ * Revision 1.18  2000/07/20 10:22:27  calle
+ * - Made procfs function cleaner and removed variable "begin".
+ *
+ * Revision 1.17  2000/04/21 13:00:56  calle
+ * Bugfix: driver_proc_info was also wrong.
+ *
+ * Revision 1.16  2000/04/21 12:38:42  calle
+ * Bugfix: error in proc_ functions, begin-off => off-begin
+ *
+ * Revision 1.15  2000/04/06 15:01:25  calle
+ * Bugfix: crash in capidrv.c when reseting a capi controller.
+ * - changed code order on remove of controller.
+ * - using tq_schedule for notifier in kcapi.c.
+ * - now using spin_lock_irqsave() and spin_unlock_irqrestore().
+ * strange: sometimes even MP hang on unload of isdn.o ...
+ *
+ * Revision 1.14  2000/04/03 13:29:25  calle
+ * make Tim Waugh happy (module unload races in 2.3.99-pre3).
+ * no real problem there, but now it is much cleaner ...
+ *
+ * Revision 1.13  2000/03/03 15:50:42  calle
+ * - kernel CAPI:
+ *   - Changed parameter "param" in capi_signal from __u32 to void *.
+ *   - rewrote notifier handling in kcapi.c
+ *   - new notifier NCCI_UP and NCCI_DOWN
+ * - User CAPI:
+ *   - /dev/capi20 is now a cloning device.
+ *   - middleware extentions prepared.
+ * - capidrv.c
+ *   - locking of list operations and module count updates.
+ *
  * Revision 1.12  2000/01/28 16:45:39  calle
  * new manufacturer command KCAPI_CMD_ADDCARD (generic addcard),
  * will search named driver and call the add_card function if one exist.
@@ -78,6 +129,8 @@
 #include <linux/tqueue.h>
 #include <linux/capi.h>
 #include <linux/kernelcapi.h>
+#include <linux/locks.h>
+#include <linux/init.h>
 #include <asm/uaccess.h>
 #include "capicmd.h"
 #include "capiutil.h"
@@ -86,7 +139,7 @@
 #include <linux/b1lli.h>
 #endif
 
-static char *revision = "$Revision: 1.12 $";
+static char *revision = "$Revision: 1.21.6.2 $";
 
 /* ------------------------------------------------------------- */
 
@@ -125,8 +178,8 @@
 	__u16 applid;
 	capi_register_params rparam;
 	int releasing;
-	__u32 param;
-	void (*signal) (__u16 applid, __u32 param);
+	void *param;
+	void (*signal) (__u16 applid, void *param);
 	struct sk_buff_head recv_queue;
 	int nncci;
 	struct capi_ncci *nccilist;
@@ -137,6 +190,14 @@
 	unsigned long nsentdatapkt;
 };
 
+struct capi_notifier {
+	struct capi_notifier *next;
+	unsigned int cmd;
+	__u32 controller;
+	__u16 applid;
+	__u32 ncci;
+};
+
 /* ------------------------------------------------------------- */
 
 static struct capi_version driver_version = {2, 0, 1, 1<<4};
@@ -160,9 +221,9 @@
 static int ncards = 0;
 static struct sk_buff_head recv_queue;
 static struct capi_interface_user *capi_users = 0;
+static spinlock_t capi_users_lock = SPIN_LOCK_UNLOCKED;
 static struct capi_driver *drivers;
-static long notify_up_set = 0;
-static long notify_down_set = 0;
+static spinlock_t drivers_lock = SPIN_LOCK_UNLOCKED;
 
 static struct tq_struct tq_state_notify;
 static struct tq_struct tq_recv_notify;
@@ -226,7 +287,6 @@
 	struct capi_appl *ap;
 	int i;
 	int len = 0;
-	off_t begin = 0;
 
 	for (i=0; i < CAPI_MAXAPPL; i++) {
 		ap = &applications[i];
@@ -238,20 +298,21 @@
 			ap->rparam.datablklen,
 			ap->nncci,
                         skb_queue_len(&ap->recv_queue));
-		if (len+begin > off+count)
-			goto endloop;
-		if (len+begin < off) {
-			begin += len;
+		if (len <= off) {
+			off -= len;
 			len = 0;
+		} else {
+			if (len-off > count)
+				goto endloop;
 		}
 	}
 endloop:
-	if (i >= CAPI_MAXAPPL)
+	*start = page+off;
+	if (len < count)
 		*eof = 1;
-	if (off >= len+begin)
-		return 0;
-	*start = page + (off-begin);
-	return ((count < begin+len-off) ? count : begin+len-off);
+	if (len>count) len = count;
+	if (len<0) len = 0;
+	return len;
 }
 
 /*
@@ -265,7 +326,6 @@
 	struct capi_ncci *np;
 	int i;
 	int len = 0;
-	off_t begin = 0;
 
 	for (i=0; i < CAPI_MAXAPPL; i++) {
 		ap = &applications[i];
@@ -276,21 +336,22 @@
 				np->ncci,
 				np->winsize,
 				np->nmsg);
-			if (len+begin > off+count)
-				goto endloop;
-			if (len+begin < off) {
-				begin += len;
+			if (len <= off) {
+				off -= len;
 				len = 0;
+			} else {
+				if (len-off > count)
+					goto endloop;
 			}
 		}
 	}
 endloop:
-	if (i >= CAPI_MAXAPPL)
+	*start = page+off;
+	if (len < count)
 		*eof = 1;
-	if (off >= len+begin)
-		return 0;
-	*start = page + (off-begin);
-	return ((count < begin+len-off) ? count : begin+len-off);
+	if (len>count) len = count;
+	if (len<0) len = 0;
+	return len;
 }
 
 /*
@@ -302,27 +363,29 @@
 {
 	struct capi_driver *driver;
 	int len = 0;
-	off_t begin = 0;
 
+	spin_lock(&drivers_lock);
 	for (driver = drivers; driver; driver = driver->next) {
 		len += sprintf(page+len, "%-32s %d %s\n",
 					driver->name,
 					driver->ncontroller,
 					driver->revision);
-		if (len+begin > off+count)
-			goto endloop;
-		if (len+begin < off) {
-			begin += len;
+		if (len <= off) {
+			off -= len;
 			len = 0;
+		} else {
+			if (len-off > count)
+				goto endloop;
 		}
 	}
 endloop:
-	if (!driver)
+	spin_unlock(&drivers_lock);
+	*start = page+off;
+	if (len < count)
 		*eof = 1;
-	if (off >= len+begin)
-		return 0;
-	*start = page + (off-begin);
-	return ((count < begin+len-off) ? count : begin+len-off);
+	if (len>count) len = count;
+	if (len<0) len = 0;
+	return len;
 }
 
 /*
@@ -334,24 +397,26 @@
 {
         struct capi_interface_user *cp;
 	int len = 0;
-	off_t begin = 0;
 
+	spin_lock(&capi_users_lock);
         for (cp = capi_users; cp ; cp = cp->next) {
 		len += sprintf(page+len, "%s\n", cp->name);
-		if (len+begin > off+count)
-			goto endloop;
-		if (len+begin < off) {
-			begin += len;
+		if (len <= off) {
+			off -= len;
 			len = 0;
+		} else {
+			if (len-off > count)
+				goto endloop;
 		}
 	}
 endloop:
-	if (cp == 0)
+	spin_unlock(&capi_users_lock);
+	*start = page+off;
+	if (len < count)
 		*eof = 1;
-	if (off >= len+begin)
-		return 0;
-	*start = page + (off-begin);
-	return ((count < begin+len-off) ? count : begin+len-off);
+	if (len>count) len = count;
+	if (len<0) len = 0;
+	return len;
 }
 
 /*
@@ -364,7 +429,6 @@
 	struct capi_ctr *cp;
 	int i;
 	int len = 0;
-	off_t begin = 0;
 
 	for (i=0; i < CAPI_MAXCONTR; i++) {
 		cp = &cards[i];
@@ -375,20 +439,21 @@
 			cp->name,
 			cp->driver->procinfo ?  cp->driver->procinfo(cp) : ""
 			);
-		if (len+begin > off+count)
-			goto endloop;
-		if (len+begin < off) {
-			begin += len;
+		if (len <= off) {
+			off -= len;
 			len = 0;
+		} else {
+			if (len-off > count)
+				goto endloop;
 		}
 	}
 endloop:
-	if (i >= CAPI_MAXCONTR)
+	*start = page+off;
+	if (len < count)
 		*eof = 1;
-	if (off >= len+begin)
-		return 0;
-	*start = page + (off-begin);
-	return ((count < begin+len-off) ? count : begin+len-off);
+	if (len>count) len = count;
+	if (len<0) len = 0;
+	return len;
 }
 
 /*
@@ -401,7 +466,6 @@
 	struct capi_appl *ap;
 	int i;
 	int len = 0;
-	off_t begin = 0;
 
 	for (i=0; i < CAPI_MAXAPPL; i++) {
 		ap = &applications[i];
@@ -412,20 +476,21 @@
 			ap->nrecvdatapkt,
 			ap->nsentctlpkt,
 			ap->nsentdatapkt);
-		if (len+begin > off+count)
-			goto endloop;
-		if (len+begin < off) {
-			begin += len;
+		if (len <= off) {
+			off -= len;
 			len = 0;
+		} else {
+			if (len-off > count)
+				goto endloop;
 		}
 	}
 endloop:
-	if (i >= CAPI_MAXAPPL)
+	*start = page+off;
+	if (len < count)
 		*eof = 1;
-	if (off >= len+begin)
-		return 0;
-	*start = page + (off-begin);
-	return ((count < begin+len-off) ? count : begin+len-off);
+	if (len>count) len = count;
+	if (len<0) len = 0;
+	return len;
 }
 
 /*
@@ -438,7 +503,6 @@
 	struct capi_ctr *cp;
 	int i;
 	int len = 0;
-	off_t begin = 0;
 
 	for (i=0; i < CAPI_MAXCONTR; i++) {
 		cp = &cards[i];
@@ -449,20 +513,21 @@
 			cp->nrecvdatapkt,
 			cp->nsentctlpkt,
 			cp->nsentdatapkt);
-		if (len+begin > off+count)
-			goto endloop;
-		if (len+begin < off) {
-			begin += len;
+		if (len <= off) {
+			off -= len;
 			len = 0;
+		} else {
+			if (len-off > count)
+				goto endloop;
 		}
 	}
 endloop:
-	if (i >= CAPI_MAXCONTR)
+	*start = page+off;
+	if (len < count)
 		*eof = 1;
-	if (off >= len+begin)
-		return 0;
-	*start = page + (off-begin);
-	return ((count < begin+len-off) ? count : begin+len-off);
+	if (len>count) len = count;
+	if (len<0) len = 0;
+	return len;
 }
 
 static struct procfsentries {
@@ -510,6 +575,167 @@
     }
 }
 
+/* -------- Notifier handling --------------------------------- */
+
+static struct capi_notifier_list{
+	struct capi_notifier *head;
+	struct capi_notifier *tail;
+} notifier_list;
+
+static spinlock_t notifier_lock = SPIN_LOCK_UNLOCKED;
+
+static inline void notify_enqueue(struct capi_notifier *np)
+{
+	struct capi_notifier_list *q = &notifier_list;
+	unsigned long flags;
+
+	spin_lock_irqsave(&notifier_lock, flags);
+	if (q->tail) {
+		q->tail->next = np;
+		q->tail = np;
+	} else {
+		q->head = q->tail = np;
+	}
+	spin_unlock_irqrestore(&notifier_lock, flags);
+}
+
+static inline struct capi_notifier *notify_dequeue(void)
+{
+	struct capi_notifier_list *q = &notifier_list;
+	struct capi_notifier *np = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&notifier_lock, flags);
+	if (q->head) {
+		np = q->head;
+		if ((q->head = np->next) == 0)
+ 			q->tail = 0;
+		np->next = 0;
+	}
+	spin_unlock_irqrestore(&notifier_lock, flags);
+	return np;
+}
+
+static int notify_push(unsigned int cmd, __u32 controller,
+				__u16 applid, __u32 ncci)
+{
+	struct capi_notifier *np;
+
+	MOD_INC_USE_COUNT;
+	np = (struct capi_notifier *)kmalloc(sizeof(struct capi_notifier), GFP_ATOMIC);
+	if (!np) {
+		MOD_DEC_USE_COUNT;
+		return -1;
+	}
+	memset(np, 0, sizeof(struct capi_notifier));
+	np->cmd = cmd;
+	np->controller = controller;
+	np->applid = applid;
+	np->ncci = ncci;
+	notify_enqueue(np);
+	/*
+	 * The notifier will result in adding/deleteing
+	 * of devices. Devices can only removed in
+	 * user process, not in bh.
+	 */
+	queue_task(&tq_state_notify, &tq_scheduler);
+	return 0;
+}
+
+/* -------- KCI_CONTRUP --------------------------------------- */
+
+static void notify_up(__u32 contr)
+{
+	struct capi_interface_user *p;
+
+        printk(KERN_NOTICE "kcapi: notify up contr %d\n", contr);
+	spin_lock(&capi_users_lock);
+	for (p = capi_users; p; p = p->next) {
+		if (!p->callback) continue;
+		(*p->callback) (KCI_CONTRUP, contr, &CARD(contr)->profile);
+	}
+	spin_unlock(&capi_users_lock);
+}
+
+/* -------- KCI_CONTRDOWN ------------------------------------- */
+
+static void notify_down(__u32 contr)
+{
+	struct capi_interface_user *p;
+        printk(KERN_NOTICE "kcapi: notify down contr %d\n", contr);
+	spin_lock(&capi_users_lock);
+	for (p = capi_users; p; p = p->next) {
+		if (!p->callback) continue;
+		(*p->callback) (KCI_CONTRDOWN, contr, 0);
+	}
+	spin_unlock(&capi_users_lock);
+}
+
+/* -------- KCI_NCCIUP ---------------------------------------- */
+
+static void notify_ncciup(__u32 contr, __u16 applid, __u32 ncci)
+{
+	struct capi_interface_user *p;
+	struct capi_ncciinfo n;
+	n.applid = applid;
+	n.ncci = ncci;
+        /*printk(KERN_NOTICE "kcapi: notify up contr %d\n", contr);*/
+	spin_lock(&capi_users_lock);
+	for (p = capi_users; p; p = p->next) {
+		if (!p->callback) continue;
+		(*p->callback) (KCI_NCCIUP, contr, &n);
+	}
+	spin_unlock(&capi_users_lock);
+};
+
+/* -------- KCI_NCCIDOWN -------------------------------------- */
+
+static void notify_nccidown(__u32 contr, __u16 applid, __u32 ncci)
+{
+	struct capi_interface_user *p;
+	struct capi_ncciinfo n;
+	n.applid = applid;
+	n.ncci = ncci;
+        /*printk(KERN_NOTICE "kcapi: notify down contr %d\n", contr);*/
+	spin_lock(&capi_users_lock);
+	for (p = capi_users; p; p = p->next) {
+		if (!p->callback) continue;
+		(*p->callback) (KCI_NCCIDOWN, contr, &n);
+	}
+	spin_unlock(&capi_users_lock);
+};
+
+/* ------------------------------------------------------------ */
+
+static void inline notify_doit(struct capi_notifier *np)
+{
+	switch (np->cmd) {
+		case KCI_CONTRUP:
+			notify_up(np->controller);
+			break;
+		case KCI_CONTRDOWN:
+			notify_down(np->controller);
+			break;
+		case KCI_NCCIUP:
+			notify_ncciup(np->controller, np->applid, np->ncci);
+			break;
+		case KCI_NCCIDOWN:
+			notify_nccidown(np->controller, np->applid, np->ncci);
+			break;
+	}
+}
+
+static void notify_handler(void *dummy)
+{
+	struct capi_notifier *np;
+
+	while ((np = notify_dequeue()) != 0) {
+		notify_doit(np);
+		kfree(np);
+		MOD_DEC_USE_COUNT;
+	}
+}
+	
 /* -------- NCCI Handling ------------------------------------- */
 
 static inline void mq_init(struct capi_ncci * np)
@@ -617,6 +843,7 @@
 	APPL(appl)->nncci++;
 	printk(KERN_INFO "kcapi: appl %d ncci 0x%x up\n", appl, ncci);
 
+	notify_push(KCI_NCCIUP, CARDNR(card), appl, ncci);
 }
 
 static void controllercb_free_ncci(struct capi_ctr * card,
@@ -634,6 +861,7 @@
 			kfree(np);
 			APPL(appl)->nncci--;
 			printk(KERN_INFO "kcapi: appl %d ncci 0x%x down\n", appl, ncci);
+			notify_push(KCI_NCCIDOWN, CARDNR(card), appl, ncci);
 			return;
 		}
 	}
@@ -734,42 +962,6 @@
 	kfree_skb(skb);
 }
 
-/* -------- Notifier ------------------------------------------ */
-
-static void notify_up(__u32 contr)
-{
-	struct capi_interface_user *p;
-
-        printk(KERN_NOTICE "kcapi: notify up contr %d\n", contr);
-	for (p = capi_users; p; p = p->next) {
-		if (!p->callback) continue;
-		(*p->callback) (KCI_CONTRUP, contr, &CARD(contr)->profile);
-	}
-}
-
-static void notify_down(__u32 contr)
-{
-	struct capi_interface_user *p;
-        printk(KERN_NOTICE "kcapi: notify down contr %d\n", contr);
-	for (p = capi_users; p; p = p->next) {
-		if (!p->callback) continue;
-		(*p->callback) (KCI_CONTRDOWN, contr, 0);
-	}
-}
-
-static void notify_handler(void *dummy)
-{
-	__u32 contr;
-
-	for (contr=1; VALID_CARD(contr); contr++)
-		 if (test_and_clear_bit(contr, &notify_up_set))
-			 notify_up(contr);
-	for (contr=1; VALID_CARD(contr); contr++)
-		 if (test_and_clear_bit(contr, &notify_down_set))
-			 notify_down(contr);
-}
-
-
 static void controllercb_ready(struct capi_ctr * card)
 {
 	__u16 appl;
@@ -782,11 +974,10 @@
 		card->driver->register_appl(card, appl, &APPL(appl)->rparam);
 	}
 
-        set_bit(CARDNR(card), &notify_up_set);
-        queue_task(&tq_state_notify, &tq_scheduler);
-
         printk(KERN_NOTICE "kcapi: card %d \"%s\" ready.\n",
 		CARDNR(card), card->name);
+
+	notify_push(KCI_CONTRUP, CARDNR(card), 0, 0);
 }
 
 static void controllercb_reseted(struct capi_ctr * card)
@@ -812,6 +1003,7 @@
 				struct capi_ncci *np = *pp;
 				*pp = np->next;
 				printk(KERN_INFO "kcapi: appl %d ncci 0x%x forced down!\n", appl, np->ncci);
+				notify_push(KCI_NCCIDOWN, CARDNR(card), appl, np->ncci);
 				kfree(np);
 				nextpp = pp;
 			} else {
@@ -819,9 +1011,10 @@
 			}
 		}
 	}
-	set_bit(CARDNR(card), &notify_down_set);
-	queue_task(&tq_state_notify, &tq_scheduler);
+
 	printk(KERN_NOTICE "kcapi: card %d down.\n", CARDNR(card));
+
+	notify_push(KCI_CONTRDOWN, CARDNR(card), 0, 0);
 }
 
 static void controllercb_suspend_output(struct capi_ctr *card)
@@ -937,7 +1130,7 @@
 	if (len < off) 
            return 0;
 	*eof = 1;
-	*start = page - off;
+	*start = page + off;
 	return ((count < len-off) ? count : len-off);
 }
 
@@ -952,9 +1145,12 @@
 {
 	struct capi_driver **pp;
 
+	MOD_INC_USE_COUNT;
+	spin_lock(&drivers_lock);
 	for (pp = &drivers; *pp; pp = &(*pp)->next) ;
 	driver->next = 0;
 	*pp = driver;
+	spin_unlock(&drivers_lock);
 	printk(KERN_NOTICE "kcapi: driver %s attached\n", driver->name);
 	sprintf(driver->procfn, "capi/drivers/%s", driver->name);
 	driver->procent = create_proc_entry(driver->procfn, 0, 0);
@@ -974,6 +1170,7 @@
 void detach_capi_driver(struct capi_driver *driver)
 {
 	struct capi_driver **pp;
+	spin_lock(&drivers_lock);
 	for (pp = &drivers; *pp && *pp != driver; pp = &(*pp)->next) ;
 	if (*pp) {
 		*pp = (*pp)->next;
@@ -981,10 +1178,12 @@
 	} else {
 		printk(KERN_ERR "kcapi: driver %s double detach ?\n", driver->name);
 	}
+	spin_unlock(&drivers_lock);
 	if (driver->procent) {
 	   remove_proc_entry(driver->procfn, 0);
 	   driver->procent = 0;
 	}
+	MOD_DEC_USE_COUNT;
 }
 
 /* ------------------------------------------------------------- */
@@ -1041,6 +1240,7 @@
 
 	if (!VALID_APPLID(applid) || APPL(applid)->releasing)
 		return CAPI_ILLAPPNR;
+	APPL(applid)->releasing++;
 	while ((skb = skb_dequeue(&APPL(applid)->recv_queue)) != 0)
 		kfree_skb(skb);
 	for (i = 0; i < CAPI_MAXCONTR; i++) {
@@ -1049,6 +1249,7 @@
 		APPL(applid)->releasing++;
 		cards[i].driver->release_appl(&cards[i], applid);
 	}
+	APPL(applid)->releasing--;
 	if (APPL(applid)->releasing <= 0) {
 	        APPL(applid)->signal = 0;
 		APPL_MARK_FREE(applid);
@@ -1128,8 +1329,8 @@
 }
 
 static __u16 capi_set_signal(__u16 applid,
-			     void (*signal) (__u16 applid, __u32 param),
-			     __u32 param)
+			     void (*signal) (__u16 applid, void *param),
+			     void *param)
 {
 	if (!VALID_APPLID(applid))
 		return CAPI_ILLAPPNR;
@@ -1194,10 +1395,12 @@
 static struct capi_driver *find_driver(char *name)
 {
 	struct capi_driver *dp;
+	spin_lock(&drivers_lock);
 	for (dp = drivers; dp; dp = dp->next)
 		if (strcmp(dp->name, name) == 0)
-			return dp;
-	return 0;
+			break;
+	spin_unlock(&drivers_lock);
+	return dp;
 }
 
 #ifdef CONFIG_AVMB1_COMPAT
@@ -1272,6 +1475,10 @@
 		card = CARD(ldef.contr);
 		if (card->cardstate == CARD_FREE)
 			return -ESRCH;
+		if (card->driver->load_firmware == 0) {
+			printk(KERN_DEBUG "kcapi: load: driver \%s\" has no load function\n", card->driver->name);
+			return -ESRCH;
+		}
 
 		if (ldef.t4file.len <= 0) {
 			printk(KERN_DEBUG "kcapi: load: invalid parameter: length of t4file is %d ?\n", ldef.t4file.len);
@@ -1304,7 +1511,7 @@
 
 		while (card->cardstate != CARD_RUNNING) {
 
-			current->state = TASK_INTERRUPTIBLE;
+			set_current_state(TASK_INTERRUPTIBLE);
 			schedule_timeout(HZ/10);	/* 0.1 sec */
 
 			if (signal_pending(current))
@@ -1329,7 +1536,7 @@
 
 		while (card->cardstate > CARD_DETECTED) {
 
-			current->state = TASK_INTERRUPTIBLE;
+			set_current_state(TASK_INTERRUPTIBLE);
 			schedule_timeout(HZ/10);	/* 0.1 sec */
 
 			if (signal_pending(current))
@@ -1380,7 +1587,7 @@
 
 		while (card->cardstate != CARD_FREE) {
 
-			current->state = TASK_INTERRUPTIBLE;
+			set_current_state(TASK_INTERRUPTIBLE);
 			schedule_timeout(HZ/10);	/* 0.1 sec */
 
 			if (signal_pending(current))
@@ -1490,16 +1697,20 @@
 {
 	struct capi_interface_user *p;
 
+	MOD_INC_USE_COUNT;
+	spin_lock(&capi_users_lock);
 	for (p = capi_users; p; p = p->next) {
 		if (p == userp) {
+			spin_unlock(&capi_users_lock);
 			printk(KERN_ERR "kcapi: double attach from %s\n",
 			       userp->name);
+			MOD_DEC_USE_COUNT;
 			return 0;
 		}
 	}
 	userp->next = capi_users;
 	capi_users = userp;
-	MOD_INC_USE_COUNT;
+	spin_unlock(&capi_users_lock);
 	printk(KERN_NOTICE "kcapi: %s attached\n", userp->name);
 
 	return &avmb1_interface;
@@ -1509,15 +1720,18 @@
 {
 	struct capi_interface_user **pp;
 
+	spin_lock(&capi_users_lock);
 	for (pp = &capi_users; *pp; pp = &(*pp)->next) {
 		if (*pp == userp) {
 			*pp = userp->next;
+			spin_unlock(&capi_users_lock);
 			userp->next = 0;
-			MOD_DEC_USE_COUNT;
 			printk(KERN_NOTICE "kcapi: %s detached\n", userp->name);
+			MOD_DEC_USE_COUNT;
 			return 0;
 		}
 	}
+	spin_unlock(&capi_users_lock);
 	printk(KERN_ERR "kcapi: double detach from %s\n", userp->name);
 	return -1;
 }
@@ -1531,42 +1745,18 @@
 EXPORT_SYMBOL(attach_capi_driver);
 EXPORT_SYMBOL(detach_capi_driver);
 
-#ifndef MODULE
-#ifdef CONFIG_ISDN_DRV_AVMB1_B1ISA
-extern int b1isa_init(void);
-#endif
-#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCI
-extern int b1pci_init(void);
-#endif
-#ifdef CONFIG_ISDN_DRV_AVMB1_T1ISA
-extern int t1isa_init(void);
-#endif
-#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
-extern int b1pcmcia_init(void);
-#endif
-#ifdef CONFIG_ISDN_DRV_AVMB1_T1PCI
-extern int t1pci_init(void);
-#endif
-#ifdef CONFIG_ISDN_DRV_AVMB1_C4
-extern int c4_init(void);
-#endif
-#endif
-
 /*
  * init / exit functions
  */
 
-#ifdef MODULE
-#define kcapi_init init_module
-#endif
-
-int kcapi_init(void)
+static int __init kcapi_init(void)
 {
 	char *p;
 	char rev[10];
 
+	MOD_INC_USE_COUNT;
+
 	skb_queue_head_init(&recv_queue);
-	/* init_bh(CAPI_BH, do_capi_bh); */
 
 	tq_state_notify.routine = notify_handler;
 	tq_state_notify.data = 0;
@@ -1587,30 +1777,12 @@
         printk(KERN_NOTICE "CAPI-driver Rev%s: loaded\n", rev);
 #else
 	printk(KERN_NOTICE "CAPI-driver Rev%s: started\n", rev);
-#ifdef CONFIG_ISDN_DRV_AVMB1_B1ISA
-	(void)b1isa_init();
-#endif
-#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCI
-	(void)b1pci_init();
-#endif
-#ifdef CONFIG_ISDN_DRV_AVMB1_T1ISA
-	(void)t1isa_init();
-#endif
-#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
-	(void)b1pcmcia_init();
-#endif
-#ifdef CONFIG_ISDN_DRV_AVMB1_T1PCI
-	(void)t1pci_init();
-#endif
-#ifdef CONFIG_ISDN_DRV_AVMB1_C4
-	(void)c4_init();
-#endif
 #endif
+	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
-#ifdef MODULE
-void cleanup_module(void)
+static void  kcapi_exit(void)
 {
 	char rev[10];
 	char *p;
@@ -1623,8 +1795,9 @@
 		strcpy(rev, "1.0");
 	}
 
-	schedule(); /* execute queued tasks .... */
         proc_capi_exit();
 	printk(KERN_NOTICE "CAPI-driver Rev%s: unloaded\n", rev);
 }
-#endif
+
+module_init(kcapi_init);
+module_exit(kcapi_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/avmb1/t1isa.c linux.19p18/drivers/isdn/avmb1/t1isa.c
--- linux.vanilla/drivers/isdn/avmb1/t1isa.c	Mon Dec 11 22:12:45 2000
+++ linux.19p18/drivers/isdn/avmb1/t1isa.c	Wed Feb 14 14:28:52 2001
@@ -1,11 +1,36 @@
 /*
- * $Id: t1isa.c,v 1.10 2000/02/02 18:36:04 calle Exp $
+ * $Id: t1isa.c,v 1.16.6.1 2001/02/13 11:43:29 kai Exp $
  * 
  * Module for AVM T1 HEMA-card.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: t1isa.c,v $
+ * Revision 1.16.6.1  2001/02/13 11:43:29  kai
+ * more compatility changes for 2.2.19
+ *
+ * Revision 1.16  2000/11/23 20:45:14  kai
+ * fixed module_init/exit stuff
+ * Note: compiled-in kernel doesn't work pre 2.2.18 anymore.
+ *
+ * Revision 1.15  2000/11/01 14:05:02  calle
+ * - use module_init/module_exit from linux/init.h.
+ * - all static struct variables are initialized with "membername:" now.
+ * - avm_cs.c, let it work with newer pcmcia-cs.
+ *
+ * Revision 1.14  2000/10/10 17:44:19  kai
+ * changes from/for 2.2.18
+ *
+ * Revision 1.13  2000/08/04 15:36:31  calle
+ * copied wrong from file to file :-(
+ *
+ * Revision 1.12  2000/08/04 12:20:08  calle
+ * - Fix unsigned/signed warning in the right way ...
+ *
+ * Revision 1.11  2000/04/03 13:29:25  calle
+ * make Tim Waugh happy (module unload races in 2.3.99-pre3).
+ * no real problem there, but now it is much cleaner ...
+ *
  * Revision 1.10  2000/02/02 18:36:04  calle
  * - Modules are now locked while init_module is running
  * - fixed problem with memory mapping if address is not aligned
@@ -75,13 +100,14 @@
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/capi.h>
+#include <linux/init.h>
 #include <asm/io.h>
 #include "capicmd.h"
 #include "capiutil.h"
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.10 $";
+static char *revision = "$Revision: 1.16.6.1 $";
 
 /* ------------------------------------------------------------- */
 
@@ -190,7 +216,7 @@
 	struct sk_buff *skb;
 
 	unsigned ApplId;
-	signed MsgLen;
+	unsigned MsgLen;
 	unsigned DataB3Len;
 	unsigned NCCI;
 	unsigned WindowSize;
@@ -278,25 +304,30 @@
 		case RECEIVE_TASK_READY:
 			ApplId = (unsigned) b1_get_word(card->port);
 			MsgLen = t1_get_slice(card->port, card->msgbuf);
-			card->msgbuf[MsgLen--] = 0;
-			while (    MsgLen >= 0
-			       && (   card->msgbuf[MsgLen] == '\n'
-				   || card->msgbuf[MsgLen] == '\r'))
-				card->msgbuf[MsgLen--] = 0;
+			card->msgbuf[MsgLen] = 0;
+			while (    MsgLen > 0
+			       && (   card->msgbuf[MsgLen-1] == '\n'
+				   || card->msgbuf[MsgLen-1] == '\r')) {
+				card->msgbuf[MsgLen-1] = 0;
+				MsgLen--;
+			}
 			printk(KERN_INFO "%s: task %d \"%s\" ready.\n",
 					card->name, ApplId, card->msgbuf);
 			break;
 
 		case RECEIVE_DEBUGMSG:
 			MsgLen = t1_get_slice(card->port, card->msgbuf);
-			card->msgbuf[MsgLen--] = 0;
-			while (    MsgLen >= 0
-			       && (   card->msgbuf[MsgLen] == '\n'
-				   || card->msgbuf[MsgLen] == '\r'))
-				card->msgbuf[MsgLen--] = 0;
+			card->msgbuf[MsgLen] = 0;
+			while (    MsgLen > 0
+			       && (   card->msgbuf[MsgLen-1] == '\n'
+				   || card->msgbuf[MsgLen-1] == '\r')) {
+				card->msgbuf[MsgLen-1] = 0;
+				MsgLen--;
+			}
 			printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf);
 			break;
 
+
 		case 0xff:
 			printk(KERN_ERR "%s: card reseted ?\n", card->name);
 			return;
@@ -573,31 +604,29 @@
 /* ------------------------------------------------------------- */
 
 static struct capi_driver t1isa_driver = {
-    "t1isa",
-    "0.0",
-    t1isa_load_firmware,
-    t1isa_reset_ctr,
-    t1isa_remove_ctr,
-    b1_register_appl,
-    b1_release_appl,
-    t1isa_send_message,
-
-    t1isa_procinfo,
-    b1ctl_read_proc,
-    0,	/* use standard driver_read_proc */
+    name: "t1isa",
+    revision: "0.0",
+    load_firmware: t1isa_load_firmware,
+    reset_ctr: t1isa_reset_ctr,
+    remove_ctr: t1isa_remove_ctr,
+    register_appl: b1_register_appl,
+    release_appl: b1_release_appl,
+    send_message: t1isa_send_message,
+
+    procinfo: t1isa_procinfo,
+    ctr_read_proc: b1ctl_read_proc,
+    driver_read_proc: 0,	/* use standard driver_read_proc */
 
-    t1isa_add_card,
+    add_card: t1isa_add_card,
 };
 
-#ifdef MODULE
-#define t1isa_init init_module
-void cleanup_module(void);
-#endif
-
-int t1isa_init(void)
+static int __init t1isa_init(void)
 {
 	struct capi_driver *driver = &t1isa_driver;
 	char *p;
+	int retval = 0;
+
+	MOD_INC_USE_COUNT;
 
 	if ((p = strchr(revision, ':'))) {
 		strncpy(driver->revision, p + 1, sizeof(driver->revision));
@@ -612,14 +641,17 @@
 	if (!di) {
 		printk(KERN_ERR "%s: failed to attach capi_driver\n",
 				driver->name);
-		return -EIO;
+		retval = -EIO;
 	}
-	return 0;
+
+	MOD_DEC_USE_COUNT;
+	return retval;
 }
 
-#ifdef MODULE
-void cleanup_module(void)
+static void  t1isa_exit(void)
 {
     detach_capi_driver(&t1isa_driver);
 }
-#endif
+
+module_init(t1isa_init);
+module_exit(t1isa_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/avmb1/t1pci.c linux.19p18/drivers/isdn/avmb1/t1pci.c
--- linux.vanilla/drivers/isdn/avmb1/t1pci.c	Fri Apr 21 12:46:08 2000
+++ linux.19p18/drivers/isdn/avmb1/t1pci.c	Wed Feb 14 14:28:52 2001
@@ -1,11 +1,54 @@
 /*
- * $Id: t1pci.c,v 1.5 2000/02/02 18:36:04 calle Exp $
+ * $Id: t1pci.c,v 1.13.6.2 2001/02/13 11:43:29 kai Exp $
  * 
  * Module for AVM T1 PCI-card.
  * 
  * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
  * $Log: t1pci.c,v $
+ * Revision 1.13.6.2  2001/02/13 11:43:29  kai
+ * more compatility changes for 2.2.19
+ *
+ * Revision 1.13.6.1  2000/11/28 12:02:45  kai
+ * MODULE_DEVICE_TABLE for 2.4
+ *
+ * Revision 1.13.2.2  2000/11/26 17:47:53  kai
+ * added PCI_DEV_TABLE for 2.4
+ *
+ * Revision 1.13.2.1  2000/11/26 17:14:19  kai
+ * fix device ids
+ * also needs patches to include/linux/pci_ids.h
+ *
+ * Revision 1.13  2000/11/23 20:45:14  kai
+ * fixed module_init/exit stuff
+ * Note: compiled-in kernel doesn't work pre 2.2.18 anymore.
+ *
+ * Revision 1.12  2000/11/01 14:05:02  calle
+ * - use module_init/module_exit from linux/init.h.
+ * - all static struct variables are initialized with "membername:" now.
+ * - avm_cs.c, let it work with newer pcmcia-cs.
+ *
+ * Revision 1.11  2000/08/08 09:24:19  calle
+ * calls to pci_enable_device surounded by #ifndef COMPAT_HAS_2_2_PCI
+ *
+ * Revision 1.10  2000/07/20 10:21:21  calle
+ * Bugfix: driver will not be unregistered, if not cards were detected.
+ *         this result in an oops in kcapi.c
+ *
+ * Revision 1.9  2000/05/19 15:43:22  calle
+ * added calls to pci_device_start().
+ *
+ * Revision 1.8  2000/05/06 00:52:36  kai
+ * merged changes from kernel tree
+ * fixed timer and net_device->name breakage
+ *
+ * Revision 1.7  2000/04/07 15:26:55  calle
+ * better error message if cabel not connected or T1 has no power.
+ *
+ * Revision 1.6  2000/04/03 13:29:25  calle
+ * make Tim Waugh happy (module unload races in 2.3.99-pre3).
+ * no real problem there, but now it is much cleaner ...
+ *
  * Revision 1.5  2000/02/02 18:36:04  calle
  * - Modules are now locked while init_module is running
  * - fixed problem with memory mapping if address is not aligned
@@ -40,30 +83,22 @@
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/pci.h>
+#include <linux/isdn_compat.h>
 #include <linux/capi.h>
+#include <linux/init.h>
 #include <asm/io.h>
 #include "capicmd.h"
 #include "capiutil.h"
 #include "capilli.h"
 #include "avmcard.h"
 
-static char *revision = "$Revision: 1.5 $";
+static char *revision = "$Revision: 1.13.6.2 $";
 
 #undef CONFIG_T1PCI_DEBUG
 #undef CONFIG_T1PCI_POLLDEBUG
 
 /* ------------------------------------------------------------- */
 
-#ifndef PCI_VENDOR_ID_AVM
-#define PCI_VENDOR_ID_AVM	0x1244
-#endif
-
-#ifndef PCI_DEVICE_ID_AVM_T1
-#define PCI_DEVICE_ID_AVM_T1	0x1200
-#endif
-
-/* ------------------------------------------------------------- */
-
 MODULE_AUTHOR("Carsten Paeth <calle@calle.in-berlin.de>");
 
 /* ------------------------------------------------------------- */
@@ -164,7 +199,11 @@
 	b1dma_reset(card);
 
 	if ((retval = t1pci_detect(card)) != 0) {
-		printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
+		if (retval < 6)
+			printk(KERN_NOTICE "%s: NO card at 0x%x (%d)\n",
+					driver->name, card->port, retval);
+		else
+			printk(KERN_NOTICE "%s: card at 0x%x, but cabel not connected or T1 has no power (%d)\n",
 					driver->name, card->port, retval);
                 iounmap((void *) (((unsigned long) card->mbase) & PAGE_MASK));
 	        kfree(card->ctrlinfo);
@@ -234,36 +273,33 @@
 /* ------------------------------------------------------------- */
 
 static struct capi_driver t1pci_driver = {
-    "t1pci",
-    "0.0",
-    b1dma_load_firmware,
-    b1dma_reset_ctr,
-    t1pci_remove_ctr,
-    b1dma_register_appl,
-    b1dma_release_appl,
-    b1dma_send_message,
-
-    t1pci_procinfo,
-    b1dmactl_read_proc,
-    0,	/* use standard driver_read_proc */
+    name: "t1pci",
+    revision: "0.0",
+    load_firmware: b1dma_load_firmware,
+    reset_ctr: b1dma_reset_ctr,
+    remove_ctr: t1pci_remove_ctr,
+    register_appl: b1dma_register_appl,
+    release_appl: b1dma_release_appl,
+    send_message: b1dma_send_message,
+
+    procinfo: t1pci_procinfo,
+    ctr_read_proc: b1dmactl_read_proc,
+    driver_read_proc: 0,	/* use standard driver_read_proc */
 
-    0, /* no add_card function */
+    add_card: 0, /* no add_card function */
 };
 
-#ifdef MODULE
-#define t1pci_init init_module
-void cleanup_module(void);
-#endif
-
 static int ncards = 0;
 
-int t1pci_init(void)
+static int __init t1pci_init(void)
 {
 	struct capi_driver *driver = &t1pci_driver;
 	struct pci_dev *dev = NULL;
 	char *p;
 	int retval;
 
+	MOD_INC_USE_COUNT;
+
 	if ((p = strchr(revision, ':'))) {
 		strncpy(driver->revision, p + 1, sizeof(driver->revision));
 		p = strchr(driver->revision, '$');
@@ -277,6 +313,7 @@
 	if (!di) {
 		printk(KERN_ERR "%s: failed to attach capi_driver\n",
 				driver->name);
+		MOD_DEC_USE_COUNT;
 		return -EIO;
 	}
 
@@ -284,6 +321,7 @@
 	if (!pci_present()) {
 		printk(KERN_ERR "%s: no PCI bus present\n", driver->name);
     		detach_capi_driver(driver);
+		MOD_DEC_USE_COUNT;
 		return -EIO;
 	}
 
@@ -291,9 +329,10 @@
 		struct capicardparams param;
 
 		param.port = dev->base_address[ 1] & PCI_BASE_ADDRESS_IO_MASK;
-		param.irq = dev->irq;
+ 		param.irq = dev->irq;
 		param.membase = dev->base_address[ 0] & PCI_BASE_ADDRESS_MEM_MASK;
 
+
 		printk(KERN_INFO
 			"%s: PCI BIOS reports AVM-T1-PCI at i/o %#x, irq %d, mem %#x\n",
 			driver->name, param.port, param.irq, param.membase);
@@ -302,9 +341,8 @@
 		        printk(KERN_ERR
 			"%s: no AVM-T1-PCI at i/o %#x, irq %d detected, mem %#x\n",
 			driver->name, param.port, param.irq, param.membase);
-#ifdef MODULE
-			cleanup_module();
-#endif
+    			detach_capi_driver(&t1pci_driver);
+			MOD_DEC_USE_COUNT;
 			return retval;
 		}
 		ncards++;
@@ -312,19 +350,24 @@
 	if (ncards) {
 		printk(KERN_INFO "%s: %d T1-PCI card(s) detected\n",
 				driver->name, ncards);
+		MOD_DEC_USE_COUNT;
 		return 0;
 	}
 	printk(KERN_ERR "%s: NO T1-PCI card detected\n", driver->name);
+	detach_capi_driver(&t1pci_driver);
+	MOD_DEC_USE_COUNT;
 	return -ESRCH;
 #else
 	printk(KERN_ERR "%s: kernel not compiled with PCI.\n", driver->name);
+	MOD_DEC_USE_COUNT;
 	return -EIO;
 #endif
 }
 
-#ifdef MODULE
-void cleanup_module(void)
+static void  t1pci_exit(void)
 {
     detach_capi_driver(&t1pci_driver);
 }
-#endif
+
+module_init(t1pci_init);
+module_exit(t1pci_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/divert/Makefile linux.19p18/drivers/isdn/divert/Makefile
--- linux.vanilla/drivers/isdn/divert/Makefile	Fri Apr 21 12:46:08 2000
+++ linux.19p18/drivers/isdn/divert/Makefile	Tue Feb 13 18:38:13 2001
@@ -1,18 +1,26 @@
-L_OBJS :=
-LX_OBJS :=
-M_OBJS :=
-MX_OBJS :=
-O_OBJS :=
-OX_OBJS :=
-L_TARGET :=
-O_TARGET :=
-
-O_OBJS += isdn_divert.o divert_procfs.o
-O_TARGET := dss1_divert.o
-M_OBJS += dss1_divert.o
-OX_OBJS += divert_init.o
+#
+# Makefile for the dss1_divert ISDN module
+#
 
-include $(TOPDIR)/Rules.make
+# The target object and module list name.
+
+O_TARGET	:= vmlinux-obj.o
+
+# Multipart objects.
+
+list-multi		:= dss1_divert.o
+dss1_divert-objs	:= isdn_divert.o divert_procfs.o divert_init.o
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_ISDN_DIVERSION)	+= dss1_divert.o
+
+include $(TOPDIR)/drivers/isdn/Rules.make
+
+# Link rules for multi-part drivers.
+
+dss1_divert.o: $(dss1_divert-objs)
+	$(LD) -r -o $@ $(dss1_divert-objs)
 
 
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/divert/divert_init.c linux.19p18/drivers/isdn/divert/divert_init.c
--- linux.vanilla/drivers/isdn/divert/divert_init.c	Mon Dec 11 22:12:45 2000
+++ linux.19p18/drivers/isdn/divert/divert_init.c	Tue Feb 13 18:50:48 2001
@@ -1,5 +1,5 @@
 /* 
- * $Id: divert_init.c,v 1.5 2000/11/13 22:51:47 kai Exp $
+ * $Id: divert_init.c,v 1.5.6.2 2001/01/24 22:18:17 kai Exp $
  *
  * Module init for DSS1 diversion services for i4l.
  *
@@ -23,6 +23,7 @@
 
 #include <linux/module.h>
 #include <linux/version.h>
+#include <linux/init.h>
 #include "isdn_divert.h"
 
 /********************/
@@ -46,7 +47,7 @@
 /* Module interface code */
 /* no cmd line parms     */
 /*************************/
-int init_module(void)
+static int __init divert_init(void)
 { int i;
 
   if (divert_dev_init())
@@ -63,12 +64,12 @@
 #endif
   printk(KERN_INFO "dss1_divert module successfully installed\n");
   return(0);
-} /* init_module */
+}
 
 /**********************/
 /* Module deinit code */
 /**********************/
-void cleanup_module(void)
+static void  divert_exit(void)
 { int flags;
   int i;
 
@@ -89,6 +90,8 @@
   deleterule(-1); /* delete all rules and free mem */
   deleteprocs();
   printk(KERN_INFO "dss1_divert module successfully removed \n");
-} /* cleanup_module */
+}
 
+module_init(divert_init);
+module_exit(divert_exit);
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/divert/divert_procfs.c linux.19p18/drivers/isdn/divert/divert_procfs.c
--- linux.vanilla/drivers/isdn/divert/divert_procfs.c	Mon Dec 11 22:12:45 2000
+++ linux.19p18/drivers/isdn/divert/divert_procfs.c	Tue Feb 13 18:50:48 2001
@@ -1,5 +1,5 @@
 /*
- * $Id: divert_procfs.c,v 1.10 2000/11/13 22:51:47 kai Exp $
+ * $Id: divert_procfs.c,v 1.11 2000/11/25 17:01:00 kai Exp $
  *
  * Filesystem handling for the diversion supplementary services.
  *
@@ -32,6 +32,7 @@
 #include <linux/fs.h>
 #endif
 #include <linux/isdnif.h>
+#include <linux/isdn_compat.h>
 #include "isdn_divert.h"
 
 /*********************************/
@@ -40,7 +41,7 @@
 ulong if_used = 0;		/* number of interface users */
 static struct divert_info *divert_info_head = NULL;	/* head of queue */
 static struct divert_info *divert_info_tail = NULL;	/* pointer to last entry */
-static struct wait_queue *rd_queue = 0;		/* Queue IO */
+static wait_queue_head_t rd_queue;
 
 /*********************************/
 /* put an info buffer into queue */
@@ -281,19 +282,14 @@
 
 static struct file_operations isdn_fops =
 {
-	isdn_divert_lseek,
-	isdn_divert_read,
-	isdn_divert_write,
-	NULL,			/* isdn_readdir */
-	isdn_divert_poll,	/* isdn_poll */
-	isdn_divert_ioctl,	/* isdn_ioctl */
-	NULL,			/* isdn_mmap */
-	isdn_divert_open,
-	NULL,			/* flush */
-	isdn_divert_close,
-	NULL			/* fsync */
+	llseek:         isdn_divert_lseek,
+	read:           isdn_divert_read,
+	write:          isdn_divert_write,
+	poll:           isdn_divert_poll,
+	ioctl:          isdn_divert_ioctl,
+	open:           isdn_divert_open,
+	release:        isdn_divert_close,                                      
 };
-
 struct inode_operations divert_file_inode_operations;
 
 /****************************/
@@ -310,6 +306,7 @@
 divert_dev_init(void)
 {
 
+	init_waitqueue_head(&rd_queue);
 
 #ifdef CONFIG_PROC_FS
 	isdn_proc_entry = create_proc_entry("isdn", S_IFDIR | S_IRUGO | S_IXUGO, proc_net);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/divert/isdn_divert.c linux.19p18/drivers/isdn/divert/isdn_divert.c
--- linux.vanilla/drivers/isdn/divert/isdn_divert.c	Fri Apr 21 12:46:08 2000
+++ linux.19p18/drivers/isdn/divert/isdn_divert.c	Mon Feb 12 15:02:35 2001
@@ -1,5 +1,5 @@
 /* 
- * $Id: isdn_divert.c,v 1.5 1999/08/31 11:20:04 paul Exp $
+ * $Id: isdn_divert.c,v 1.6.6.1 2001/02/07 11:31:31 kai Exp $
  *
  * DSS1 main diversion supplementary handling for i4l.
  *
@@ -19,25 +19,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
- * $Log: isdn_divert.c,v $
- * Revision 1.5  1999/08/31 11:20:04  paul
- * various spelling corrections (new checksums may be needed, Karsten!)
- *
- * Revision 1.4  1999/08/25 20:02:21  werner
- * Changed return values for stat_icall(w) from 3->4 and 4->5 because of conflicts
- * with existing software definitions. (PtP incomplete called party number)
- *
- * Revision 1.3  1999/08/22 20:26:35  calle
- * backported changes from kernel 2.3.14:
- * - several #include "config.h" gone, others come.
- * - "struct device" changed to "struct net_device" in 2.3.14, added a
- *   define in isdn_compat.h for older kernel versions.
- *
- * Revision 1.2  1999/07/04 21:37:32  werner
- * Ported from kernel version 2.0
- *
- *
- *
  */
 
 
@@ -206,7 +187,7 @@
   restore_flags(flags);
   *procid = cs->ics.parm.dss1_io.ll_id;  
 
-  sprintf(cs->info,"%d 0x%lx %s%s 0 %s %0x %d%s%s\n",
+  sprintf(cs->info,"%d 0x%lx %s%s 0 %s %02x %d%s%s\n",
 	  (!mode ) ? DIVERT_DEACTIVATE : (mode == 1) ? DIVERT_ACTIVATE : DIVERT_REPORT,
           cs->ics.parm.dss1_io.ll_id,
           (mode != 2) ? "" : "0 ",
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/divert/isdn_divert.h linux.19p18/drivers/isdn/divert/isdn_divert.h
--- linux.vanilla/drivers/isdn/divert/isdn_divert.h	Fri Apr 21 23:22:31 2000
+++ linux.19p18/drivers/isdn/divert/isdn_divert.h	Sat Mar  3 22:59:49 2001
@@ -1,5 +1,5 @@
 /* 
- * $Id: isdn_divert.h,v 1.4 1999/09/02 13:24:12 paul Exp $
+ * $Id: isdn_divert.h,v 1.5 2000/11/13 22:51:47 kai Exp $
  *
  * Header for the diversion supplementary ioctl interface.
  *
@@ -18,19 +18,6 @@
  * 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. 
- *
- * $Log: isdn_divert.h,v $
- * Revision 1.4  1999/09/02 13:24:12  paul
- * cosmetics; text following #endif is not ANSI C
- *
- * Revision 1.3  1999/08/22 20:26:37  calle
- * backported changes from kernel 2.3.14:
- * - several #include "config.h" gone, others come.
- * - "struct device" changed to "struct net_device" in 2.3.14, added a
- *   define in isdn_compat.h for older kernel versions.
- *
- * Revision 1.2  1999/07/04 21:37:33  werner
- * Ported from kernel version 2.0
  *
  */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/Divas_mod.c linux.19p18/drivers/isdn/eicon/Divas_mod.c
--- linux.vanilla/drivers/isdn/eicon/Divas_mod.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/eicon/Divas_mod.c	Mon Feb 19 18:28:19 2001
@@ -0,0 +1,151 @@
+
+/*
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#undef N_DATA
+
+#include <linux/kernel.h>
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <errno.h>
+
+#include "adapter.h"
+#include "uxio.h"
+
+#include <linux/isdn_compat.h>
+
+#ifdef MODULE
+#include "idi.h"
+void DIVA_DIDD_Write(DESCRIPTOR *, int);
+EXPORT_SYMBOL_NOVERS(DIVA_DIDD_Read);
+EXPORT_SYMBOL_NOVERS(DIVA_DIDD_Write);
+EXPORT_SYMBOL_NOVERS(DivasPrintf);
+#endif
+
+int DivasCardsDiscover(void);
+
+static int __init
+divas_init(void)
+{
+	printk(KERN_DEBUG "DIVA Server Driver - initialising\n");
+	
+	printk(KERN_DEBUG "DIVA Server Driver - Version 2.0.16\n");
+
+
+#if !defined(CONFIG_PCI)
+	printk(KERN_WARNING "CONFIG_PCI is not defined!\n");
+	return -ENODEV;
+#endif
+
+	if (pci_present())
+	{
+		if (DivasCardsDiscover() < 0)
+		{
+			printk(KERN_WARNING "Divas: Not loaded\n");
+			return -ENODEV;
+		}
+	}
+	else
+	{
+		printk(KERN_WARNING "Divas: No PCI bus present\n");
+		return -ENODEV;
+	}
+
+    return 0;
+}
+
+static void 
+divas_exit(void)
+{
+	card_t *pCard;
+	word wCardIndex;
+	extern int Divas_major;
+
+	printk(KERN_DEBUG "DIVA Server Driver - unloading\n");
+
+	pCard = DivasCards;
+	for (wCardIndex = 0; wCardIndex < MAX_CARDS; wCardIndex++)
+	{
+		if ((pCard->hw) && (pCard->hw->in_use))
+		{
+
+			(*pCard->card_reset)(pCard);
+			
+			UxIsrRemove(pCard->hw, pCard);
+			UxCardHandleFree(pCard->hw);
+
+			if(pCard->e_tbl != NULL)
+			{
+				kfree(pCard->e_tbl);
+			}
+
+			
+			if(pCard->hw->card_type == DIA_CARD_TYPE_DIVA_SERVER_B)
+			{	
+				release_region(pCard->hw->io_base,0x20);		
+				release_region(pCard->hw->reset_base,0x80);		
+			}
+
+			// If this is a 4BRI ...
+			if (pCard->hw->card_type == DIA_CARD_TYPE_DIVA_SERVER_Q)
+			{
+				// Skip over the next 3 virtual adapters
+				wCardIndex += 3;
+
+				// But free their handles 
+				pCard++;
+				UxCardHandleFree(pCard->hw);
+			
+				if(pCard->e_tbl != NULL)
+				{
+					kfree(pCard->e_tbl);
+				}
+				
+				pCard++;
+				UxCardHandleFree(pCard->hw);
+				
+				if(pCard->e_tbl != NULL)
+				{
+					kfree(pCard->e_tbl);
+				}
+				
+				pCard++;
+				UxCardHandleFree(pCard->hw);
+				
+				if(pCard->e_tbl != NULL)
+				{
+					kfree(pCard->e_tbl);
+				}
+			}
+		}
+		pCard++;
+	}
+
+	unregister_chrdev(Divas_major, "Divas");
+}
+
+module_init(divas_init);
+module_exit(divas_exit);
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/Makefile linux.19p18/drivers/isdn/eicon/Makefile
--- linux.vanilla/drivers/isdn/eicon/Makefile	Fri Apr 21 12:46:09 2000
+++ linux.19p18/drivers/isdn/eicon/Makefile	Mon Feb 19 18:28:19 2001
@@ -1,13 +1,42 @@
-L_OBJS :=
-M_OBJS :=
-O_OBJS := eicon_mod.o eicon_isa.o eicon_pci.o eicon_idi.o eicon_io.o
-
-O_TARGET :=
-ifeq ($(CONFIG_ISDN_DRV_EICON),y)
-  O_TARGET += eicon.o
-else
-  O_TARGET += eicon.o
-  M_OBJS   = eicon.o
-endif
+# Makefile for the eicon ISDN device driver
+
+# The target object and module list name.
+
+O_TARGET	:= vmlinux-obj.o
+
+# Objects that export symbols.
+
+export-objs	:= Divas_mod.o eicon_mod.o
+
+# Multipart objects.
+
+list-multi	:= eicon.o divas.o
+eicon-objs	:= eicon_mod.o eicon_isa.o eicon_pci.o eicon_idi.o \
+		   eicon_io.o
+divas-objs	:= common.o idi.o bri.o pri.o log.o xlog.o kprintf.o fpga.o \
+		   fourbri.o lincfg.o linchr.o linsys.o linio.o Divas_mod.o
+
+# Optional parts of multipart objects.
+
+eicon-objs-$(CONFIG_ISDN_DRV_EICON_PCI) += common.o idi.o bri.o pri.o log.o \
+		   xlog.o kprintf.o fpga.o fourbri.o lincfg.o linchr.o \
+		   linsys.o linio.o
+
+eicon-objs 	+= $(eicon-objs-y)
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_ISDN_DRV_EICON_OLD)    	+= eicon.o
+obj-$(CONFIG_ISDN_DRV_EICON_DIVAS)	+= divas.o
+
+include $(TOPDIR)/drivers/isdn/Rules.make
+
+# Link rules for multi-part drivers.
+
+eicon.o: $(eicon-objs)
+	$(LD) -r -o $@ $(eicon-objs)
+
+divas.o: $(divas-objs)
+	$(LD) -r -o $@ $(divas-objs)
+
 
-include $(TOPDIR)/Rules.make
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/adapter.h linux.19p18/drivers/isdn/eicon/adapter.h
--- linux.vanilla/drivers/isdn/eicon/adapter.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/eicon/adapter.h	Tue Feb 20 13:44:47 2001
@@ -0,0 +1,262 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.7  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+/* Main internal include file for Diva Server driver */
+
+#if !defined(ADAPTER_H)
+#define ADAPTER_H
+
+#include "sys.h"
+#include "idi.h"
+#include "divas.h"
+#undef ID_MASK
+#include "pc.h"
+
+#define XMOREC 0x1f
+#define XMOREF 0x20
+#define XBUSY  0x40
+#define RMORE  0x80
+
+        /* structure for all information we have to keep on a per   */
+        /* adapater basis                                           */
+
+typedef struct adapter_s ADAPTER;
+
+struct adapter_s {
+  void * io;
+
+  byte IdTable[256];
+  byte ReadyInt;
+
+  byte (* ram_in)(ADAPTER * a, void * adr);
+  word (* ram_inw)(ADAPTER * a, void * adr);
+  void (* ram_in_buffer)(ADAPTER * a, void * adr, void * P, word length);
+  void (* ram_look_ahead)(ADAPTER * a, PBUFFER * RBuffer, ENTITY * e);
+
+  void (* ram_out)(ADAPTER * a, void * adr, byte data);
+  void (* ram_outw)(ADAPTER * a, void * adr, word data);
+  void (* ram_out_buffer)(ADAPTER * a, void * adr, void * P, word length);
+
+  void (* ram_inc)(ADAPTER * a, void * adr);
+};
+
+typedef struct card card_t;
+
+typedef int	card_load_fn_t(card_t *card, dia_load_t *load);
+typedef int	card_config_fn_t(card_t *card, dia_config_t *config);
+typedef int	card_start_fn_t(card_t *card, byte *channels);
+typedef	int	card_reset_fn_t(card_t *card);
+typedef int card_mem_get_fn_t(card_t *card, mem_block_t *mem_block);
+
+#define	MAX_PENTITIES	256		/* Number of entities primary adapter */
+#define MAX_ENTITIES	16		/* Number of entities standard adapter */
+
+typedef struct e_info_s E_INFO;
+
+struct e_info_s
+{
+	ENTITY		*e;				/* entity pointer */
+	byte		next;			/* chaining index */
+	word		assign_ref;		/* assign reference */
+};
+
+/* DIVA card info (details hidden from user) */
+
+typedef struct	ux_diva_card_s ux_diva_card_t;
+
+/* card info */
+
+struct card
+{
+	ADAPTER				a;				/* per-adapter information */
+	dia_card_t			cfg;			/* card configuration */
+	int 				state;			/* State of the adapter */
+	dword 				serial_no;		/* serial number */
+	int 				test_int_pend;	/* set for interrupt testing */
+	ux_diva_card_t		*hw;			/* O/S-specific handle */
+	card_reset_fn_t		*card_reset;	/* call this to reset card */
+	card_load_fn_t		*card_load;		/* call this to load card */
+	card_config_fn_t	*card_config;	/* call this to config card */
+	card_start_fn_t		*card_start;	/* call this to start card */
+	card_mem_get_fn_t	*card_mem_get;	/* call this to get card memory */
+	E_INFO				*e_tbl;			/* table of ENTITY pointers */
+	byte				e_head;			/* list of active ENTITIES */
+	byte				e_tail;			/* list of active ENTITIES */
+	int					e_count;		/* # of active ENTITIES */
+	int					e_max;			/* total # of ENTITIES */
+	byte				assign;			/* assign queue entry */
+	PBUFFER				RBuffer;		/* Copy of receive lookahead buffer */
+	int					log_types;		/* bit-mask of active logs */
+	word				xlog_offset;	/* offset to XLOG buffer on card */
+	void		(*out)(ADAPTER *a);
+	byte		(*dpc)(ADAPTER * a);
+	byte		(*test_int)(ADAPTER * a);
+	void		(*clear_int)(ADAPTER * a);
+	void		(*reset_int)(card_t *c);
+	int  		is_live;
+
+	int		(*card_isr)(card_t *card);
+
+	int 		int_pend;		/* interrupt pending */
+	long		interrupt_reentered;
+	long 		dpc_reentered;
+	int 		set_xlog_request;
+
+} ;
+
+/* card information */
+
+#define	MAX_CARDS	20		/* max number of cards on a system */
+
+extern
+card_t			DivasCards[];
+
+extern
+int				DivasCardNext;
+
+extern
+dia_config_t	DivasCardConfigs[];
+
+extern
+byte 			DivasFlavourConfig[];
+
+/*------------------------------------------------------------------*/
+/* public functions of IDI common code                              */
+/*------------------------------------------------------------------*/
+
+void DivasOut(ADAPTER * a);
+byte DivasDpc(ADAPTER * a);
+byte DivasTestInt(ADAPTER * a);
+void DivasClearInt(ADAPTER * a);
+
+/*------------------------------------------------------------------*/
+/* public functions of configuration platform-specific code         */
+/*------------------------------------------------------------------*/
+
+int DivasConfigGet(dia_card_t *card);
+
+/*------------------------------------------------------------------*/
+/* public functions of LOG related code                             */
+/*------------------------------------------------------------------*/
+
+void	DivasXlogReq(int card_num);
+int		DivasXlogRetrieve(card_t *card);
+void	DivasLog(dia_log_t *log);
+void	DivasLogIdi(card_t *card, ENTITY *e, int request);
+
+/*------------------------------------------------------------------*/
+/* public functions to initialise cards for each type supported     */
+/*------------------------------------------------------------------*/
+
+int		DivasPriInit(card_t *card, dia_card_t *cfg);
+
+int		DivasBriInit(card_t *card, dia_card_t *cfg);
+int		Divas4BriInit(card_t *card, dia_card_t *cfg);
+void 	DivasBriPatch(card_t *card);
+
+/*------------------------------------------------------------------*/
+/* public functions of log common code                              */
+/*------------------------------------------------------------------*/
+
+extern	char	*DivasLogFifoRead(void);
+extern	void	DivasLogFifoWrite(char *entry, int length);
+extern	int		DivasLogFifoEmpty(void);
+extern	int		DivasLogFifoFull(void);
+extern	void    DivasLogAdd(void *buffer, int length);
+
+/*------------------------------------------------------------------*/
+/* public functions of misc. platform-specific code         		*/
+/*------------------------------------------------------------------*/
+
+int		DivasDpcSchedule(void);
+void		DivasDoDpc(void *);
+void		DivasDoRequestDpc(void *pData);
+int		DivasScheduleRequestDpc(void);
+
+/* table of IDI request functions */
+
+extern
+IDI_CALL	DivasIdiRequest[];
+
+/*
+ * intialisation entry point
+ */
+
+int		DivasInit(void);
+
+/*
+ * Get information on the number and type of cards present
+ */
+
+extern
+int 	DivasCardsDiscover(void);
+
+/*
+ * initialise a new card
+ */
+
+int		DivasCardNew(dia_card_t *card);
+
+/*
+ * configure specified card
+ */
+
+int		DivasCardConfig(dia_config_t *config);
+
+/*
+ * load specified binary code onto card
+ */
+
+int		DivasCardLoad(dia_load_t *load);
+
+/*
+ * start specified card running
+ */
+
+int		DivasCardStart(int card_id);
+
+/*
+ * ISR for card
+ * Returns 0 if specified card was interrupting
+ */
+
+int		DivasIsr(void *arg);
+
+/*
+ * Get number of active cards
+ */
+
+int		DivasGetNum(void);
+
+/*
+ * Get list of active cards
+ */
+
+int		DivasGetList(dia_card_list_t *card_list);
+
+/* definitions common to several card types */
+
+#define DIVAS_SHARED_OFFSET     (0x1000)
+
+#endif /* ADAPTER_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/bri.c linux.19p18/drivers/isdn/eicon/bri.c
--- linux.vanilla/drivers/isdn/eicon/bri.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/eicon/bri.c	Mon Feb 19 18:28:19 2001
@@ -0,0 +1,714 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.8  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+#include <sys/types.h>
+
+#include "sys.h"
+#include "idi.h"
+#include "divas.h"
+#include "pc.h"
+#include "pr_pc.h"
+#include "dsp_defs.h"
+
+#include "adapter.h"
+#include "uxio.h"
+
+#define PCI_COMMAND	0x04
+#define PCI_STATUS	0x06
+#define PCI_LATENCY	0x0D
+#define PCI_BADDR0	0x10
+#define PCI_BADDR1	0x14
+#define PCI_BADDR2	0x18
+
+#define DIVAS_SIGNATURE 0x4447
+
+/* offset to start of MAINT area (used by xlog) */
+
+#define	DIVAS_MAINT_OFFSET	0xff00		/* value for BRI card */
+
+#define PROTCAP_TELINDUS	0x1
+#define PROTCAP_V90D		0x8
+
+word GetProtFeatureValue(char *sw_id);
+byte io_in(ADAPTER *a, void *adr);
+word io_inw(ADAPTER *a, void *adr);
+void io_in_buffer(ADAPTER *a, void *adr, void *P, word length);
+void io_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e);
+void io_out(ADAPTER *a, void *adr, byte data);
+void io_outw(ADAPTER *a, void *adr, word data);
+void io_out_buffer(ADAPTER *a, void *adr, void *P, word length);
+void io_inc(ADAPTER *a, void *adr);
+
+static int diva_server_bri_test_int(card_t *card);
+static int bri_ISR (card_t* card);
+
+#define PLX_IOBASE		0
+#define	DIVAS_IOBASE	1
+
+#define	REG_DATA		0x00
+#define	REG_ADDRLO		0x04
+#define REG_ADDRHI		0x0C
+#define REG_IOCTRL		0x10
+
+#define M_PCI_RESET	0x10
+
+byte UxCardPortIoIn(ux_diva_card_t *card, byte *base, int offset);
+word UxCardPortIoInW(ux_diva_card_t *card, byte *base, int offset);
+void UxCardPortIoOut(ux_diva_card_t *card, byte *base, int offset, byte);
+void UxCardPortIoOutW(ux_diva_card_t *card, byte *base, int offset, word);
+
+int DivasBRIInitPCI(card_t *card, dia_card_t *cfg);
+
+static
+int	diva_server_bri_reset(card_t *card)
+{
+	byte *DivasIOBase;
+	word i;
+	dword dwWait;
+
+	UxCardLog(0);
+
+	DPRINTF(("divas: resetting BRI adapter"));
+
+	DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0);
+
+	for (i=0; i < 50000; i++)
+		;
+
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0);
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0);
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_DATA  , 0);
+
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF);
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x0000);
+
+	for (i=0; i<0x8000; i++)
+	{
+		UxCardPortIoOutW(card->hw, DivasIOBase, REG_DATA , 0);
+	}
+
+	for (dwWait=0; dwWait < 0x00FFFFFF; dwWait++)
+		;
+
+	UxCardMemDetach(card->hw, DivasIOBase);
+
+	return 0;
+}
+
+static
+void diva_server_bri_reset_int(card_t *card)
+{
+	byte *DivasIOBase = NULL;
+
+	DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0x08);
+
+	UxCardMemDetach(card->hw, DivasIOBase);
+
+	return;
+}
+
+static
+int diva_server_bri_start(card_t *card, byte *channels)
+{
+	byte *DivasIOBase, *PLXIOBase;
+	word wSig = 0;
+	word i;
+	dword dwSerialNum;
+	byte bPLX9060 = FALSE;
+
+	DPRINTF(("divas: starting Diva Server BRI card"));
+
+	card->is_live = FALSE;
+
+	DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF);
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x1E);
+
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA  , 0);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA  , 0);
+	
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0x08);
+
+	/* wait for signature to indicate card has started */
+	for (i = 0; i < 300; i++)
+	{
+		UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF);
+		UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x1E);
+		wSig = UxCardPortIoInW(card->hw, DivasIOBase, REG_DATA);
+
+		if (wSig == DIVAS_SIGNATURE)
+		{
+			DPRINTF(("divas: card started after %d ms", i * 10));
+			break;
+		}
+		UxPause(10);
+	}
+
+	if (wSig != DIVAS_SIGNATURE)
+	{
+		DPRINTF(("divas: card failed to start (Sig=0x%x)", wSig));
+		UxCardMemDetach(card->hw, DivasIOBase);
+		return -1;
+	}
+
+	card->is_live = TRUE;
+
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF);
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 0x3F6);
+	*channels = UxCardPortIoInW(card->hw, DivasIOBase, REG_DATA);
+
+	UxCardMemDetach(card->hw, DivasIOBase);
+
+	PLXIOBase = UxCardMemAttach(card->hw, PLX_IOBASE);
+
+	bPLX9060 = UxCardPortIoInW(card->hw, PLXIOBase, 0x6C) | UxCardPortIoInW(card->hw, PLXIOBase, 0x6E);
+
+	if (bPLX9060)
+	{ 
+		dwSerialNum = (UxCardPortIoInW(card->hw, PLXIOBase, 0x1E) << 16) | 
+					(UxCardPortIoInW(card->hw, PLXIOBase, 0x22));
+		DPRINTF(("divas: PLX9060 in use. Serial number 0x%04X", dwSerialNum));
+	}
+	else
+	{
+		dwSerialNum = (UxCardPortIoInW(card->hw, PLXIOBase, 0x22) << 16) | 
+					(UxCardPortIoInW(card->hw, PLXIOBase, 0x26));
+		DPRINTF(("divas: PLX9050 in use. Serial number 0x%04X", dwSerialNum));
+	}
+
+	UxCardMemDetach(card->hw, PLXIOBase);
+
+	card->serial_no = dwSerialNum;
+
+	diva_server_bri_test_int(card);
+	
+	return 0;
+}
+
+static
+int diva_server_bri_load(card_t *card, dia_load_t *load)
+{
+	byte *DivasIOBase;
+	dword r3000_base;
+	dword dwAddr, dwLength, i;
+	word wTest, aWord;
+
+	DPRINTF(("divas: loading Diva Server BRI card"));
+
+	switch (load->code_type)
+	{
+		case DIA_CPU_CODE:
+		DPRINTF(("divas: loading RISC %s", &load->code[0x80]));
+
+		card->hw->features = GetProtFeatureValue((char *)&load->code[0x80]);
+		DPRINTF(("divas: features 0x%x", card->hw->features));
+		if (card->hw->features == 0xFFFF)
+		{
+			DPRINTF(("divas: invalid feature string failed load\n"));
+			return -1;
+		}
+
+		r3000_base = 0;
+		break;
+
+		case DIA_DSP_CODE:
+		DPRINTF(("divas: DSP code \"%s\"", load->code));
+
+		if ((card->hw->features) && (!(card->hw->features & PROTCAP_TELINDUS)))
+		{
+			DPRINTF(("divas: only Telindus style binaries supported"));
+			return -1;
+		}
+
+		if ((card->hw->features) && (card->hw->features & PROTCAP_V90D))
+		{
+			DPRINTF(("divas: V.90 DSP binary"));
+			r3000_base = (0xBF790000 + (((sizeof(dword) + (sizeof(t_dsp_download_desc)* DSP_MAX_DOWNLOAD_COUNT)) + 3) & 0xFFFFFFFC));
+		}
+		else
+		{
+			DPRINTF(("divas: non-V.90 DSP binary"));
+			r3000_base = (0xBF7A0000 + (((sizeof(dword) + (sizeof(t_dsp_download_desc)* DSP_MAX_DOWNLOAD_COUNT)) + 3) & 0xFFFFFFFC));
+		}
+		DPRINTF(("divas: loading at 0x%x", r3000_base));
+		break;
+
+		case DIA_TABLE_CODE:
+		DPRINTF(("divas: TABLE code"));
+		if ((card->hw->features) && (card->hw->features & PROTCAP_V90D))
+		{
+			r3000_base = 0xBF790000 + sizeof(dword);
+		}
+		else
+		{
+			r3000_base = 0xBF7A0000 + sizeof(dword);
+		}
+
+		break;
+
+		case DIA_DLOAD_CNT:
+		DPRINTF(("divas: COUNT code"));
+		if ((card->hw->features) && (card->hw->features & PROTCAP_V90D))
+		{
+			r3000_base = 0xBF790000;
+		}
+		else
+		{
+			r3000_base = 0xBF7A0000;
+		}
+		break;
+
+		default:
+		DPRINTF(("divas: unknown code type %d", load->code_type));
+		return -1;
+		break;
+	}
+
+	DPRINTF(("divas: Writing %d bytes to adapter, address 0x%x", load->length, r3000_base));
+
+	DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+	DPRINTF(("divas: Attached to 0x%04X", DivasIOBase));
+
+	dwLength = load->length;
+
+	for (i=0; i < dwLength; i++)
+	{
+		dwAddr = r3000_base + i;
+
+		UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, dwAddr >> 16);
+		UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, dwAddr);
+
+		UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, load->code[i]);
+	}
+
+	DPRINTF(("divas: Verifying"));
+
+	for (i=0; i<dwLength; i++)
+	{
+		dwAddr = r3000_base + i;
+
+		UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, dwAddr >> 16);
+		UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, dwAddr);
+
+		wTest = UxCardPortIoIn(card->hw, DivasIOBase, REG_DATA);
+
+		aWord = load->code[i];
+
+		if (wTest != aWord)
+		{
+			DPRINTF(("divas: load verify failed on byte %d", i));
+			DPRINTF(("divas: RAM 0x%x   File 0x%x",wTest,aWord));
+			
+			UxCardMemDetach(card->hw, DivasIOBase);
+
+			return -1;
+		}
+	}
+
+	DPRINTF(("divas: Loaded and verified. Detaching from adapter"));
+
+	UxCardMemDetach(card->hw, DivasIOBase);
+
+	UxCardLog(0);
+
+	return 0;
+}
+
+static
+int diva_server_bri_config(card_t *card, dia_config_t *config)
+{
+	byte *DivasIOBase, i;
+
+	DPRINTF(("divas: configuring Diva Server BRI card"));
+
+	DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, 0xFF);
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 8);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->tei);
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 9);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->nt2);
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 10);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->sig_flags);
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 11);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->watchdog);
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 12);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->permanent);
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 13);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0);
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 14);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->stable_l2);
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 15);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->no_order_check);
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 16);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0);
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 17);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0);
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 18);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->low_channel);
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 19);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->prot_version);
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 20);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->crc4);
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 21);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0);
+
+	if ((card->hw->features) && (card->hw->features & PROTCAP_V90D))
+	{
+		DPRINTF(("divas: Signifying V.90"));
+		UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 22);
+		UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 4);
+	}
+	else
+	{
+		UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 22);
+		UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 0);
+	}
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 23);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, card->serial_no & 0xFF);
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 24);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, (card->serial_no >> 8) & 0xFF);
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 25);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, (card->serial_no >> 16) & 0xFF);
+
+	UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 26);
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, 21);
+
+	for (i=0; i<32; i++)
+	{
+		UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 32+i);
+		UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[0].oad[i]);
+
+		UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 64+i);
+		UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[0].osa[i]);
+
+		UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 96+i);
+		UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[0].spid[i]);
+
+
+		UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 128+i);
+		UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[1].oad[i]);
+
+		UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 160+i);
+		UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[1].osa[i]);
+
+		UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, 192+i);
+		UxCardPortIoOut(card->hw, DivasIOBase, REG_DATA, config->terminal[1].spid[i]);
+	}
+
+	UxCardMemDetach(card->hw, DivasIOBase);
+
+	return 0;
+}
+
+void DivasBriPatch(card_t *card)
+{
+	dword	PLXIOBase = 0;
+	dword	DivasIOBase = 0;
+
+	PLXIOBase = card->cfg.reset_base;
+	DivasIOBase = card->cfg.io_base;
+
+	if(card->hw == NULL)
+	{
+		DPRINTF(("Divas: BRI PATCH (PLX chip) card->hw is null"));
+		return;
+	}
+
+	if (PLXIOBase == 0)
+	{
+		DPRINTF(("Divas: BRI (PLX chip) cannot be patched. The BRI adapter may"));
+		DPRINTF(("Divas:   not function properly. If you do encounter problems,"));
+		DPRINTF(("Divas:   ensure that your machine is using the latest BIOS."));
+		return;
+	}
+
+	DPRINTF(("Divas: PLX I/O Base 0x%x", PLXIOBase));
+	DPRINTF(("Divas: Divas I/O Base 0x%x", DivasIOBase));
+
+	if (PLXIOBase & 0x80)
+	{
+		dword dwSize, dwSerialNum, dwCmd;
+		boolean_t bPLX9060;
+		word wSerHi, wSerLo;
+
+		DPRINTF(("Divas: Patch required"));
+		dwCmd = 0;
+		UxPciConfigWrite(card->hw, 4, PCI_COMMAND, &dwCmd);
+
+		PLXIOBase &= ~0x80;
+		UxPciConfigWrite(card->hw, 4, PCI_BADDR1, &PLXIOBase);
+
+		dwSize = 0xFFFFFFFF;
+		UxPciConfigWrite(card->hw, 4, PCI_BADDR1, &dwSize);
+		UxPciConfigRead(card->hw, 4, PCI_BADDR1, &dwSize);
+		
+		dwSize = (~ (dwSize & ~7)) + 1;
+
+		DivasIOBase = PLXIOBase + dwSize;
+
+		card->cfg.reset_base = PLXIOBase;
+		card->cfg.io_base = DivasIOBase;
+		UxPciConfigWrite(card->hw, 4, PCI_BADDR1, &card->cfg.reset_base);
+		UxPciConfigWrite(card->hw, 4, PCI_BADDR2, &card->cfg.io_base);
+
+		dwCmd = 5;
+		UxPciConfigWrite(card->hw, 4, PCI_COMMAND, &dwCmd);
+
+		bPLX9060 = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6C) | 
+			   UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6E);
+
+		if (bPLX9060)
+		{
+			wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x1E);
+			wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22);
+			dwSerialNum = (wSerHi << 16) | wSerLo;
+			UxCardLog(0);
+		}
+		else
+		{
+			wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22);
+			wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x26);
+			dwSerialNum = (wSerHi << 16) | wSerLo;
+			UxCardLog(0);
+		}
+	}
+	else
+	{
+		word wSerHi, wSerLo;
+		boolean_t bPLX9060;
+		dword dwSerialNum;
+
+		DPRINTF(("divas: No patch required"));
+
+		bPLX9060 = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6C) | 
+			   UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x6E);
+
+		if (bPLX9060)
+		{
+			wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x1E);
+			wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22);
+			dwSerialNum = (wSerHi << 16) | wSerLo;
+		}
+		else
+		{
+			wSerHi = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x22);
+			wSerLo = UxCardPortIoInW(card->hw, (void *) card->cfg.reset_base, 0x26);
+			dwSerialNum = (wSerHi << 16) | wSerLo;
+		}
+	}
+	DPRINTF(("Divas: After patching:"));
+	DPRINTF(("Divas: PLX I/O Base 0x%x", PLXIOBase));
+	DPRINTF(("Divas: Divas I/O Base 0x%x", DivasIOBase));
+
+}
+
+#define TEST_INT_DIVAS_BRI	0x12
+static
+int	diva_server_bri_test_int(card_t *card)
+{
+	boolean_t bPLX9060 = FALSE;
+	byte *PLXIOBase = NULL, *DivasIOBase = NULL;
+
+	DPRINTF(("divas: test interrupt for Diva Server BRI card"));
+
+	PLXIOBase = UxCardMemAttach(card->hw, PLX_IOBASE);
+
+	bPLX9060 = UxCardPortIoInW(card->hw, PLXIOBase, 0x6C) || UxCardPortIoInW(card->hw, PLXIOBase, 0x6E);
+
+	if (bPLX9060)
+	{ /* PLX9060 */
+		UxCardPortIoOut(card->hw, PLXIOBase, 0x69, 0x09);
+	}
+	else
+	{ /* PLX9050 */
+		UxCardPortIoOut(card->hw, PLXIOBase, 0x4C, 0x41);
+	}
+
+	card->test_int_pend = TEST_INT_DIVAS_BRI;
+
+	UxCardMemDetach(card->hw, PLXIOBase);
+
+	DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+	UxCardPortIoOut(card->hw, DivasIOBase, REG_IOCTRL, 0x89);
+
+	UxCardMemDetach(card->hw, DivasIOBase);
+	
+	return 0;
+}
+
+static
+int diva_server_bri_mem_get(card_t *card, mem_block_t *mem_block)
+{
+	dword user_addr = mem_block->addr;
+	word	length = 0;
+	dword	addr;
+	word	i;
+	byte *DivasIOBase;
+
+	DPRINTF(("divas: Retrieving memory from 0x%x", user_addr));
+
+	DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+	addr = user_addr;
+
+	for (i=0; i < (16 * 8); i++)
+	{
+		addr = user_addr + i;
+
+		UxCardPortIoOut(card->hw, DivasIOBase, REG_ADDRHI, addr >> 16);
+		UxCardPortIoOutW(card->hw, DivasIOBase, REG_ADDRLO, (word) addr);
+
+		mem_block->data[i] = UxCardPortIoIn(card->hw, DivasIOBase, REG_DATA);
+		length++;
+	}
+
+	UxCardMemDetach(card->hw, DivasIOBase);
+
+	return length;
+}
+
+int DivasBriInit(card_t *card, dia_card_t *cfg)
+{
+	DPRINTF(("divas: initialise Diva Server BRI card"));
+
+	if (DivasBRIInitPCI(card, cfg) == -1)
+	{
+		return -1;
+	}
+
+	card->card_reset 		= diva_server_bri_reset;
+	card->card_start 		= diva_server_bri_start;
+	card->card_load  		= diva_server_bri_load;
+	card->card_config		= diva_server_bri_config;
+	card->reset_int 		= diva_server_bri_reset_int;
+	card->card_mem_get 		= diva_server_bri_mem_get;
+
+	card->xlog_offset 		= DIVAS_MAINT_OFFSET;
+
+	card->out 			= DivasOut;
+	card->test_int 			= DivasTestInt;
+	card->dpc 			= DivasDpc;
+	card->clear_int 		= DivasClearInt;
+	card->card_isr 			= bri_ISR;
+
+	card->a.ram_out 		= io_out;
+	card->a.ram_outw 		= io_outw;
+	card->a.ram_out_buffer 	= io_out_buffer;
+	card->a.ram_inc 		= io_inc;
+
+	card->a.ram_in 			= io_in;
+	card->a.ram_inw 		= io_inw;
+	card->a.ram_in_buffer 	= io_in_buffer;
+	card->a.ram_look_ahead	= io_look_ahead;
+
+	return 0;
+}
+
+word GetProtFeatureValue(char *sw_id)
+{
+	word features = 0;
+
+	while ((*sw_id) && (sw_id[0] != '['))
+		sw_id++;
+
+	if (sw_id == NULL)
+	{
+		DPRINTF(("divas: no feature string present"));
+		features = -1;
+	}
+	else
+	{
+		byte i, shifter;
+
+		sw_id += 3;
+
+		for (i=0, shifter=12; i<4; i++, shifter-=4)
+		{
+			if ((sw_id[i] >= '0') && (sw_id[i] <= '9'))
+			{
+				features |= (sw_id[i] - '0') << shifter;
+			}
+			else if ((sw_id[i] >= 'a') && (sw_id[i] <= 'f'))
+			{
+				features |= (sw_id[i] - 'a' + 10) << shifter;
+			}
+			else if ((sw_id[i] >= 'A') && (sw_id[i] <= 'F'))
+			{
+				features |= (sw_id[i] - 'A' + 10) << shifter;
+			}
+			else
+			{
+				DPRINTF(("divas: invalid feature string"));
+				return -1;
+			}
+		}
+	}
+
+	return features;
+}
+
+
+int bri_ISR (card_t* card) 
+{
+	int served = 0;
+	byte *DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+	if (UxCardPortIoIn (card->hw, DivasIOBase, M_PCI_RESET) & 0x01) 
+	{
+		served = 1;
+		card->int_pend  += 1;
+		DivasDpcSchedule(); /* ISR DPC */
+		UxCardPortIoOut (card->hw, DivasIOBase, M_PCI_RESET, 0x08);
+	}
+
+	UxCardMemDetach(card->hw, DivasIOBase);
+
+	return (served != 0);
+}
+
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/common.c linux.19p18/drivers/isdn/eicon/common.c
--- linux.vanilla/drivers/isdn/eicon/common.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/eicon/common.c	Mon Feb 19 18:28:19 2001
@@ -0,0 +1,896 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.15  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+#include "sys.h"
+#include "idi.h"
+#include "constant.h"
+#include "divas.h"
+#include "pc.h"
+#include "pr_pc.h"
+
+#include "uxio.h"
+#include <sys/types.h>
+
+#define MAX_ADDR_LEN
+
+#define DIVAS_LOAD_CMD		0x02
+#define DIVAS_START_CMD		0x03
+#define DIVAS_IRQ_RESET		0xC18
+#define DIVAS_IRQ_RESET_VAL	0xFE
+
+#define	PCI_COMMAND	0x04
+#define	PCI_STATUS	0x06
+#define	PCI_LATENCY	0x0D
+#define PCI_INTERRUPT	0x3C
+
+#define TEST_INT_DIVAS		0x11
+#define TEST_INT_DIVAS_BRI	0x12
+#define TEST_INT_DIVAS_Q	0x13
+
+#define DIVAS_RESET	0x81
+#define DIVAS_LED1	0x04
+#define DIVAS_LED2	0x08
+#define DIVAS_LED3	0x20
+#define DIVAS_LED4	0x40
+
+#define DIVAS_SIGNATURE 0x4447
+
+#define MP_PROTOCOL_ADDR 0xA0011000
+
+#define PLX_IOBASE	0
+#define	DIVAS_IOBASE	1
+
+typedef struct {
+		dword cmd;
+		dword addr;
+		dword len;
+		dword err;
+		dword live;
+		dword reserved[(0x1020>>2)-6];
+		dword signature;
+		byte  data[1];
+} diva_server_boot_t;
+
+int		DivasCardNext;
+card_t	DivasCards[MAX_CARDS];
+
+dia_config_t *DivasConfig(card_t *, dia_config_t *);
+
+static
+DESCRIPTOR DIDD_Table[32];
+
+void    DIVA_DIDD_Read( DESCRIPTOR *table, int tablelength )
+{
+        bzero(table, tablelength);
+
+        if (tablelength > sizeof(DIDD_Table))
+          tablelength = sizeof(DIDD_Table);
+
+        if(tablelength % sizeof(DESCRIPTOR)) {
+          tablelength /= sizeof(DESCRIPTOR);
+          tablelength *= sizeof(DESCRIPTOR);
+        }
+
+        if (tablelength > 0)
+          bcopy((caddr_t)DIDD_Table, (caddr_t)table, tablelength);
+
+	return;
+}
+
+void 	DIVA_DIDD_Write(DESCRIPTOR *table, int tablelength)
+{
+        if (tablelength > sizeof(DIDD_Table))
+          tablelength = sizeof(DIDD_Table);
+
+	bcopy((caddr_t)table, (caddr_t)DIDD_Table, tablelength);
+
+	return;
+}
+
+static
+void    init_idi_tab(void)
+{
+    DESCRIPTOR d[32];
+
+    bzero(d, sizeof(d));
+
+    d[0].type = IDI_DIMAINT;  /* identify the DIMAINT entry */
+    d[0].channels = 0; /* zero channels associated with dimaint*/
+    d[0].features = 0; /* no features associated with dimaint */
+    d[0].request = (IDI_CALL) DivasPrintf;
+    
+    DIVA_DIDD_Write(d, sizeof(d));
+
+    return;
+}
+
+/*
+ * I/O routines for memory mapped cards
+ */
+
+byte mem_in(ADAPTER *a, void *adr)
+{
+	card_t			*card = a->io;
+	unsigned char	*b, *m;
+	byte			value;
+
+	m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+	m += (unsigned int) adr;
+
+	value = UxCardMemIn(card->hw, m);
+
+	UxCardMemDetach(card->hw, b);
+
+	return value;
+}
+
+word mem_inw(ADAPTER *a, void *adr)
+{
+	card_t			*card = a->io;
+	unsigned char	*b, *m;
+	word			value;
+
+	m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+	m += (unsigned int) adr;
+
+	value = UxCardMemInW(card->hw, m);
+
+	UxCardMemDetach(card->hw, b);
+
+	return value;
+}
+
+void mem_in_buffer(ADAPTER *a, void *adr, void *P, word length)
+{
+	card_t			*card = a->io;
+	unsigned char	*b, *m;
+
+	m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+	m += (unsigned int) adr;
+
+	UxCardMemInBuffer(card->hw, m, P, length);
+
+	UxCardMemDetach(card->hw, b);
+
+	return;
+}
+
+void mem_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e)
+{
+	card_t			*card = a->io;
+	unsigned char	*b, *m;
+
+	m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+	m += (dword) &RBuffer->length;
+	card->RBuffer.length = UxCardMemInW(card->hw, m);
+
+	m = b;
+	m += (dword) &RBuffer->P;
+	UxCardMemInBuffer(card->hw, m, card->RBuffer.P, card->RBuffer.length);
+
+	e->RBuffer = (DBUFFER *) &card->RBuffer;
+
+	UxCardMemDetach(card->hw, b);
+
+	return;
+}
+
+void mem_out(ADAPTER *a, void *adr, byte data)
+{
+	card_t			*card = a->io;
+	unsigned char	*b, *m;
+
+	m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+	m += (unsigned int) adr;
+
+	UxCardMemOut(card->hw, m, data);
+
+	UxCardMemDetach(card->hw, b);
+
+	return;
+}
+
+void mem_outw(ADAPTER *a, void *adr, word data)
+{
+	card_t			*card = a->io;
+	unsigned char	*b, *m;
+
+	m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+	m += (unsigned int) adr;
+
+	UxCardMemOutW(card->hw, m, data);
+
+	UxCardMemDetach(card->hw, b);
+
+	return;
+}
+
+void mem_out_buffer(ADAPTER *a, void *adr, void *P, word length)
+{
+	card_t			*card = a->io;
+	unsigned char	*b, *m;
+
+	m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+	m += (unsigned int) adr;
+
+	UxCardMemOutBuffer(card->hw, m, P, length);
+
+	UxCardMemDetach(card->hw, b);
+
+	return;
+}
+
+void mem_inc(ADAPTER *a, void *adr)
+{
+	word			value;
+	card_t			*card = a->io;
+	unsigned char	*b, *m;
+
+	m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+	m += (unsigned int) adr;
+
+	value = UxCardMemInW(card->hw, m);
+	value++;
+	UxCardMemOutW(card->hw, m, value);
+
+	UxCardMemDetach(card->hw, b);
+
+	return;
+}
+
+/*
+ * I/O routines for I/O mapped cards
+ */
+
+byte io_in(ADAPTER *a, void *adr)
+{
+	card_t		    *card = a->io;
+	byte		    value;
+	byte	*DivasIOBase = NULL;
+
+	DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+	value = UxCardIoIn(card->hw, DivasIOBase, adr);
+
+	UxCardMemDetach(card->hw, DivasIOBase);
+
+    return value;
+}
+
+word io_inw(ADAPTER *a, void *adr)
+{
+	card_t		*card = a->io;
+	word		value;
+	byte	*DivasIOBase = NULL;
+
+	DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+	value = UxCardIoInW(card->hw, DivasIOBase, adr);
+
+	UxCardMemDetach(card->hw, DivasIOBase);
+
+	return value;
+}
+
+void io_in_buffer(ADAPTER *a, void *adr, void *P, word length)
+{
+	card_t *card = a->io;
+	byte *DivasIOBase = NULL;
+
+	DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+	UxCardIoInBuffer(card->hw, DivasIOBase, adr, P,length);
+
+	UxCardMemDetach(card->hw, DivasIOBase);
+
+    return;
+}
+
+void io_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e)
+{
+	card_t *card = a->io;
+	byte *DivasIOBase = NULL;
+
+	DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+	card->RBuffer.length = UxCardIoInW(card->hw, DivasIOBase, (byte *) RBuffer);
+
+	UxCardIoInBuffer(card->hw, DivasIOBase, &RBuffer->P, card->RBuffer.P, card->RBuffer.length);
+
+	UxCardMemDetach(card->hw, DivasIOBase);
+
+	e->RBuffer = (DBUFFER *) &card->RBuffer;
+
+    return;
+}
+
+void io_out(ADAPTER *a, void *adr, byte data)
+{
+	card_t		*card = a->io;
+	byte	*DivasIOBase = NULL;
+
+	DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+	UxCardIoOut(card->hw, DivasIOBase, adr, data);
+
+	UxCardMemDetach(card->hw, DivasIOBase);
+
+    return;
+}
+
+void io_outw(ADAPTER *a, void *adr, word data)
+{
+	card_t		*card = a->io;
+	byte	*DivasIOBase = NULL;
+
+	DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+	UxCardIoOutW(card->hw, DivasIOBase, adr, data);
+
+	UxCardMemDetach(card->hw, DivasIOBase);
+
+    return;
+}
+
+void io_out_buffer(ADAPTER *a, void *adr, void *P, word length)
+{
+	card_t		*card = a->io;
+	byte *DivasIOBase = NULL;
+
+	DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+	UxCardIoOutBuffer(card->hw, DivasIOBase, adr, P, length);
+
+	UxCardMemDetach(card->hw, DivasIOBase);
+
+    return;
+}
+
+void io_inc(ADAPTER *a, void *adr)
+{
+	word		value;
+	card_t		*card = a->io;
+	byte *DivasIOBase;
+
+	DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+
+	value = UxCardIoInW(card->hw, DivasIOBase, adr);
+	
+	value++;
+
+	UxCardIoOutW(card->hw, DivasIOBase, adr, value);
+
+	UxCardMemDetach(card->hw, DivasIOBase);
+
+    return;
+}
+
+static
+void test_int(card_t *card)
+
+{
+	byte *shared, *DivasIOBase;
+
+	switch (card->test_int_pend)
+	{
+		case TEST_INT_DIVAS:
+			DPRINTF(("divas: test interrupt pending"));
+			shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+			if (UxCardMemIn(card->hw, &shared[0x3FE]))
+			{
+				UxCardMemOut(card->hw, 
+								&(((struct pr_ram *)shared)->RcOutput), 0);
+				UxCardMemDetach(card->hw, shared);
+            	(*card->reset_int)(card);
+				shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+				UxCardMemOut(card->hw, &shared[0x3FE], 0);
+				DPRINTF(("divas: test interrupt cleared"));
+			}
+
+			UxCardMemDetach(card->hw, shared);
+
+			card->test_int_pend = 0;
+			break;
+
+		case TEST_INT_DIVAS_BRI:
+			DPRINTF(("divas: BRI test interrupt pending"));
+			(*card->reset_int)(card);
+			DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+			UxCardIoOutW(card->hw, DivasIOBase, (void *) 0x3FE, 0);
+			UxCardMemDetach(card->hw, DivasIOBase);
+			DPRINTF(("divas: test interrupt cleared"));
+			card->test_int_pend = 0;
+			break;
+
+		case TEST_INT_DIVAS_Q:
+			DPRINTF(("divas: 4BRI test interrupt pending"));
+			(*card->reset_int)(card);
+			card->test_int_pend = 0;
+			break;
+
+		default:
+			DPRINTF(("divas: unknown test interrupt pending"));
+			return;
+	}
+	return;
+}
+
+void card_isr (void *dev_id)
+{
+	card_t *card = (card_t *) dev_id;
+	ADAPTER *a = &card->a;
+	int ipl;
+
+	if (card->test_int_pend)
+	{
+		ipl = UxCardLock(card->hw);
+		card->int_pend=0;
+		test_int(card);
+		UxCardUnlock(card->hw,ipl);
+		return;
+	}
+	
+	if(card->card_isr)
+	{
+		(*(card->card_isr))(card);
+	}
+	else
+	{
+		ipl = UxCardLock(card->hw);
+	
+		if ((card->test_int)(a))
+		{
+			(card->reset_int)(card);
+		}
+		
+		UxCardUnlock(card->hw,ipl);
+		
+	}
+
+}
+
+int DivasCardNew(dia_card_t *card_info)
+{
+	card_t *card;
+	byte b;
+	static boolean_t first_call = TRUE;
+	boolean_t NeedISRandReset = FALSE;
+
+	DPRINTF(("divas: new card "));
+
+	if (first_call)
+	{
+		first_call = FALSE;
+		init_idi_tab();
+	}
+
+	DivasConfigGet(card_info);
+	
+	if (DivasCardNext == DIM(DivasCards))
+	{
+		KDPRINTF((KERN_WARNING "Divas: no space available for new card"));
+		return -1;
+	}
+
+	card = &DivasCards[DivasCardNext];
+
+	card->state = DIA_UNKNOWN;
+
+	card->cfg = *card_info;
+
+	card->a.io = card;
+
+	if (UxCardHandleGet(&card->hw, card_info))
+	{
+		KDPRINTF((KERN_WARNING "Divas: cannot get OS specific handle for card"));
+		return -1;
+	}
+
+	if (card_info->card_type == DIA_CARD_TYPE_DIVA_SERVER_B)
+	{
+		DivasBriPatch(card);
+		card_info->io_base = card->cfg.io_base;
+	}
+
+	switch (card_info->card_type)
+	{
+		case DIA_CARD_TYPE_DIVA_SERVER:
+			if (DivasPriInit(card, card_info))
+			{
+				return -1;
+			}
+			NeedISRandReset = TRUE;
+			break;
+
+		case DIA_CARD_TYPE_DIVA_SERVER_B:
+			if (DivasBriInit(card, card_info))
+			{
+				return -1;
+			}
+			NeedISRandReset = TRUE;
+			break;
+
+ 		case DIA_CARD_TYPE_DIVA_SERVER_Q:
+			if (Divas4BriInit(card, card_info))
+			{
+				return -1;
+			}
+
+			if (card_info->name[6] == '0')
+			{
+				NeedISRandReset = TRUE;
+			}
+			else // Need to set paramater for ISR anyway
+			{
+				card->hw->user_isr_arg = card;
+				card->hw->user_isr = card_isr;
+			}
+			break;   
+
+		default:
+			KDPRINTF((KERN_WARNING "Divas: unsupported card type (%d)", card_info->card_type));
+			return -1;
+	}
+
+	if (NeedISRandReset)
+	{
+		if (UxIsrInstall(card->hw, card_isr, card))
+		{
+			KDPRINTF((KERN_WARNING "Divas: Install ISR failed (IRQ %d)", card->cfg.irq));
+			UxCardHandleFree(card->hw);
+			return -1;
+		}
+
+		b = card->cfg.irq;
+
+		UxPciConfigWrite(card->hw, sizeof(b), PCI_INTERRUPT, &b);
+
+		if (card_info->card_type != DIA_CARD_TYPE_DIVA_SERVER_Q)
+		{
+			if ((*card->card_reset)(card))
+			{
+				KDPRINTF((KERN_WARNING "Divas: Adapter reset failed"));
+				return -1;
+			}
+			card->state = DIA_RESET;
+		}
+
+		NeedISRandReset = FALSE;
+	}
+
+	DivasCardNext++;
+
+	return 0;
+}
+
+void	*get_card(int card_id)
+{
+	int i;
+
+	for (i=0; i < DivasCardNext; i++)
+	{
+		if (DivasCards[i].cfg.card_id == card_id)
+		{
+			return(&DivasCards[i]);
+		}
+	}
+
+	DPRINTF(("divas: get_card() : no such card id (%d)", card_id));
+
+	return NULL;
+}
+
+int DivasCardConfig(dia_config_t *config)
+{
+	card_t *card;
+	int status;
+
+	DPRINTF(("divas: configuring card"));
+
+	card = get_card(config->card_id);
+	if (!card)
+	{
+		return -1;
+	}
+
+	config = DivasConfig(card, config);
+
+	status = (*card->card_config)(card, config);
+
+	if (!status)
+	{
+		card->state = DIA_CONFIGURED;
+	}
+	return status;
+}
+
+int DivasCardLoad(dia_load_t *load)
+{
+	card_t *card;
+	int	status;
+
+	card = get_card(load->card_id);
+	if (!card)
+	{
+		return -1;
+	}
+
+	if (card->state == DIA_RUNNING)
+	{
+		(*card->card_reset)(card);
+	}
+
+	status = (*card->card_load)(card, load);
+	if (!status)
+	{
+		card->state = DIA_LOADED;
+	}
+	return status;
+}
+
+static int idi_register(card_t *card, byte channels)
+{
+    DESCRIPTOR d[32];
+    int length, num_entities;
+
+	DPRINTF(("divas: registering card with IDI"));
+
+	num_entities = (channels > 2) ? MAX_PENTITIES : MAX_ENTITIES;
+	card->e_tbl = UxAlloc(sizeof(E_INFO) * num_entities);
+
+	if (!card->e_tbl)
+	{
+		KDPRINTF((KERN_WARNING "Divas: IDI register failed - no memory available"));
+		return -1;
+	}
+
+	bzero(card->e_tbl, sizeof(E_INFO) * num_entities);
+	card->e_max = num_entities;
+
+    DIVA_DIDD_Read(d, sizeof(d));
+
+        for(length=0; length < DIM(d); length++)
+          if (d[length].type == 0) break;
+
+	if (length >= DIM(d))
+	{
+		KDPRINTF((KERN_WARNING "Divas: IDI register failed - table full"));
+		return -1;
+	}
+
+	switch (card->cfg.card_type)
+	{
+		case DIA_CARD_TYPE_DIVA_SERVER:
+		d[length].type = IDI_ADAPTER_PR;
+		/* d[length].serial = card->serial_no; */
+		break;
+
+		case DIA_CARD_TYPE_DIVA_SERVER_B:
+		d[length].type = IDI_ADAPTER_MAESTRA;
+		/* d[length].serial = card->serial_no; */
+		break;
+
+		// 4BRI is treated as 4 BRI adapters
+		case DIA_CARD_TYPE_DIVA_SERVER_Q:
+		d[length].type = IDI_ADAPTER_MAESTRA;
+		/* d[length].serial = card->cfg.serial; */
+	}
+
+	d[length].features = 0;
+	d[length].features |= DI_FAX3|DI_MODEM|DI_POST|DI_V110|DI_V120;
+
+	if ( card->hw->features & PROTCAP_MANIF )
+	{
+		d[length].features |= DI_MANAGE ;
+	}
+	if ( card->hw->features & PROTCAP_V_42 )
+	{
+		d[length].features |= DI_V_42 ;
+	}
+	if ( card->hw->features & PROTCAP_EXTD_FAX )
+	{
+		d[length].features |= DI_EXTD_FAX ;
+	}
+
+	d[length].channels = channels;
+	d[length].request = DivasIdiRequest[card - DivasCards];
+
+	length++;
+
+	DIVA_DIDD_Write(d, sizeof(d));
+
+    return 0;
+}
+
+int DivasCardStart(int card_id)
+{
+	card_t *card;
+	byte channels;
+	int status;
+
+	DPRINTF(("divas: starting card"));
+
+	card = get_card(card_id);
+	if (!card)
+	{
+		return -1;
+	}
+
+	status = (*card->card_start)(card, &channels);
+	if (status)
+	{
+		return status;
+	}
+
+	/* 4BRI == 4 x BRI so call idi_register 4 times each with 2 channels */
+	if (card->cfg.card_type == DIA_CARD_TYPE_DIVA_SERVER_Q)
+	{
+		int i;
+		card_t *FourBRISlave;
+
+		for (i=3; i >= 0; i--)
+		{
+			FourBRISlave = get_card(card_id - i); /* 0, 1, 2, 3 */
+			if (FourBRISlave)
+			{
+				idi_register(FourBRISlave, 2);
+				FourBRISlave->state = DIA_RUNNING;
+			}
+		}
+		card->serial_no = card->cfg.serial;
+
+		DPRINTF(("divas: card id %d (4BRI), serial no. 0x%x ready with %d channels", 
+				card_id - 3, card->serial_no, (int) channels));
+	}
+	else
+	{
+		status = idi_register(card, channels);
+		if (!status)
+		{
+			card->state = DIA_RUNNING;
+			DPRINTF(("divas: card id %d, serial no. 0x%x ready with %d channels", 
+						card_id, card->serial_no, (int) channels));
+		}
+	}
+
+	return status;
+}
+
+int DivasGetMem(mem_block_t *mem_block)
+{
+	card_t *card;
+	word	card_id = mem_block->card_id;
+
+	card = get_card(card_id);
+	if (!card)
+	{
+		return 0;
+	}
+
+	return (*card->card_mem_get)(card, mem_block);
+}
+
+
+/*
+ * Deleyed Procedure Call for handling interrupts from card
+ */
+
+void	DivaDoCardDpc(card_t *card)
+{
+	ADAPTER	*a;
+
+	a = &card->a;
+
+	if(UxInterlockedIncrement(card->hw, &card->dpc_reentered) > 1)
+	{
+		return;
+	}
+
+	do{
+		if((*(card->test_int))(a))
+		{
+			(*(card->dpc))(a);
+			(*(card->clear_int))(a);
+		}
+			(*(card->out))(a);
+	}while(UxInterlockedDecrement(card->hw, &card->dpc_reentered));
+			
+}
+
+void	DivasDoDpc(void *pData)
+{
+	card_t	*card = DivasCards;
+	int 	i = DivasCardNext;
+	
+	while(i--)
+	{
+		DivaDoCardDpc(card++);
+	}
+}
+
+void	DivasDoRequestDpc(void *pData)
+{
+	DivasDoDpc(pData);
+}
+
+/*
+ * DivasGetNum
+ * Returns the number of active adapters
+ */
+
+int DivasGetNum(void)
+{
+	return(DivasCardNext);
+}
+
+/*
+ * DivasGetList
+ * Returns a list of active adapters
+ */
+int DivasGetList(dia_card_list_t *card_list)
+{
+	int i;
+
+	bzero(card_list, sizeof(dia_card_list_t));
+
+	for(i = 0; i < DivasCardNext; i++)
+	{
+		card_list->card_type = DivasCards[i].cfg.card_type;
+		card_list->card_slot = DivasCards[i].cfg.slot;
+		card_list->state     = DivasCards[i].state;
+		card_list++;
+	}
+
+	return 0;
+
+}
+
+/*
+ * control logging for specified card
+ */
+
+void	DivasLog(dia_log_t *log)
+{
+	card_t *card;
+
+	card = get_card(log->card_id);
+	if (!card)
+	{
+		return;
+	}
+
+	card->log_types = log->log_types;
+
+	return;
+}
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/constant.h linux.19p18/drivers/isdn/eicon/constant.h
--- linux.vanilla/drivers/isdn/eicon/constant.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/eicon/constant.h	Mon Feb 19 18:28:19 2001
@@ -0,0 +1,176 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.0  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+
+/*------------------------------------------------------------------*/
+/* Q.931 information elements maximum length                        */
+/* excluding the identifier, including the length field             */
+/*------------------------------------------------------------------*/
+
+#define MAX_LEN_BC      13
+#define MAX_LEN_LLC     19 /* ctr3 */
+#define MAX_LEN_HLC     6  /* ctr3 */
+#define MAX_LEN_UUI     200 /* Hicom USBS req */
+#define MAX_LEN_NUM     24
+#define MAX_LEN_DSP     83 /* ctr3 */
+#define MAX_LEN_NI      4
+#define MAX_LEN_PI      5
+#define MAX_LEN_SIN     3
+#define MAX_LEN_CST     4
+#define MAX_LEN_SIG     2
+#define MAX_LEN_SPID    32
+#define MAX_LEN_EID     3
+#define MAX_LEN_CHI     35  /* ctr3 */
+#define MAX_LEN_CAU     33
+#define MAX_LEN_FTY     130
+#define MAX_LEN_KEY     83  /* ctr3 */
+#define MAX_LEN_RSI     4
+#define MAX_LEN_CAI     11
+#define MAX_NUM_SPID    4
+#define MAX_LEN_USERID  9
+#define MAX_LEN_APPLID  5
+#define MAX_LEN_NTTCIF  15
+
+/*------------------------------------------------------------------*/
+/* decision return values                                           */
+/*------------------------------------------------------------------*/
+
+#define YES             1
+#define NO              0
+
+
+/*-------------------------------------------------------------------*/
+/* w element coding                                                  */
+/*-------------------------------------------------------------------*/
+
+#define NTTCIF          0x01
+#define BC              0x04
+#define CAU             0x08
+#define CAD             0x0c
+#define CAI             0x10
+#define CST             0x14
+#define CHI             0x18
+#define LLI             0x19
+#define CHA             0x1a
+#define FTY             0x1c
+#define PI              0x1e
+#define NFAC            0x20
+#define TC              0x24
+#define ATT_EID         0x26
+#define NI              0x27
+#define DSP             0x28
+#define DT              0x29
+#define KEY             0x2c
+#define KP              0x2c
+#define UID             0x2d
+#define SIG             0x34
+#define FI              0x39
+#define SPID            0x3a
+#define EID             0x3b
+#define DSPF            0x3c
+#define ECAD            0x4c
+#define OAD             0x6c
+#define OSA             0x6d
+#define DAD             0x70
+#define CPN             0x70
+#define DSA             0x71
+#define RDX             0x73
+#define RAD             0x74
+#define RDN             0x74
+#define RSI             0x79
+#define SCR             0x7A   /* internal unscreened CPN          */
+#define MIE             0x7a   /* internal management info element */
+#define LLC             0x7c
+#define HLC             0x7d
+#define UUI             0x7e
+#define ESC             0x7f
+
+#define SHIFT           0x90
+#define MORE            0xa0
+#define CL              0xb0
+
+/* information elements used on the spid interface */
+#define SPID_CMD        0xc0
+#define SPID_LINK       0x10
+#define SPID_DN         0x70
+#define SPID_BC         0x04
+#define SPID_SWITCH     0x11
+
+/*------------------------------------------------------------------*/
+/* global configuration parameters, defined in exec.c               */
+/* these parameters are configured with program loading             */
+/*------------------------------------------------------------------*/
+
+#define PROT_1TR6       0
+#define PROT_ETSI       1
+#define PROT_FRANC      2
+#define PROT_BELG       3
+#define PROT_SWED       4
+#define PROT_NI         5
+#define PROT_5ESS       6
+#define PROT_JAPAN      7
+#define PROT_ATEL       8
+#define PROT_US         9
+#define PROT_ITALY      10
+#define PROT_TWAN       11
+#define PROT_AUSTRAL    12
+
+#define INIT_PROT_1TR6    0x80|PROT_1TR6
+#define INIT_PROT_ETSI    0x80|PROT_ETSI
+#define INIT_PROT_FRANC   0x80|PROT_FRANC
+#define INIT_PROT_BELG    0x80|PROT_BELG
+#define INIT_PROT_SWED    0x80|PROT_SWED
+#define INIT_PROT_NI      0x80|PROT_NI
+#define INIT_PROT_5ESS    0x80|PROT_5ESS
+#define INIT_PROT_JAPAN   0x80|PROT_JAPAN
+#define INIT_PROT_ATEL    0x80|PROT_ATEL
+#define INIT_PROT_ITALY   0x80|PROT_ITALY
+#define INIT_PROT_TWAN    0x80|PROT_TWAN
+#define INIT_PROT_AUSTRAL 0x80|PROT_AUSTRAL
+
+
+/* -----------------------------------------------------------**
+** The PROTOCOL_FEATURE_STRING in feature.h (included         **
+** in prstart.sx and astart.sx) defines capabilities and      **
+** features of the actual protocol code. It's used as a bit   **
+** mask.                                                      **
+** The following Bits are defined:                            **
+** -----------------------------------------------------------*/
+                                           
+#define PROTCAP_TELINDUS  0x0001  /* Telindus Variant of protocol code   */
+#define PROTCAP_MANIF     0x0002  /* Management interface implemented    */
+#define PROTCAP_V_42      0x0004  /* V42 implemented                     */
+#define PROTCAP_V90D      0x0008  /* V.90D (implies up to 384k DSP code) */
+#define PROTCAP_EXTD_FAX  0x0010  /* Extended FAX (ECM, 2D, T6, Polling) */
+#define PROTCAP_FREE4     0x0020  /* not used                            */
+#define PROTCAP_FREE5     0x0040  /* not used                            */
+#define PROTCAP_FREE6     0x0080  /* not used                            */
+#define PROTCAP_FREE7     0x0100  /* not used                            */
+#define PROTCAP_FREE8     0x0200  /* not used                            */
+#define PROTCAP_FREE9     0x0400  /* not used                            */
+#define PROTCAP_FREE10    0x0800  /* not used                            */
+#define PROTCAP_FREE11    0x1000  /* not used                            */
+#define PROTCAP_FREE12    0x2000  /* not used                            */
+#define PROTCAP_FREE13    0x4000  /* not used                            */
+#define PROTCAP_EXTENSION 0x8000  /* used for future extentions          */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/divalog.h linux.19p18/drivers/isdn/eicon/divalog.h
--- linux.vanilla/drivers/isdn/eicon/divalog.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/eicon/divalog.h	Mon Feb 19 18:28:19 2001
@@ -0,0 +1,54 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.0  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+/*
+ * Include file for defining the kernel loggger messages
+ * These definitions are shared between the klog driver and the
+ * klogd daemon process
+ */
+
+#if !defined(_KLOGMSG_H)
+#define _KLOGMSG_H
+
+/* define a type for a log entry */
+
+#define KLOG_TEXT_MSG   	(0)
+#define KLOG_XLOG_MSG   	(1)
+#define KLOG_XTXT_MSG   	(2)
+#define KLOG_IDI_REQ   		(4)
+#define KLOG_IDI_CALLBACK   (5)
+#define KLOG_CAPI_MSG   	(6)
+
+typedef struct
+{
+    unsigned long   time_stamp; /* in ms since last system boot */
+    int    			card;       /* card number (-1 for all) */
+    unsigned int    type;       /* type of log message (0 is text) */
+    unsigned int    length;     /* message length (non-text messages only) */
+    unsigned short  code;       /* message code (non-text messages only) */
+    char            buffer[110];/* text/data to log */
+} klog_t;
+
+void    DivasLogAdd(void *buffer, int length);
+#endif /* of _KLOGMSG_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/divas.h linux.19p18/drivers/isdn/eicon/divas.h
--- linux.vanilla/drivers/isdn/eicon/divas.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/eicon/divas.h	Tue Feb 20 13:44:47 2001
@@ -0,0 +1,229 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.5  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+/* External Diva Server driver include file */
+
+#if !defined(DIVAS_H)
+#define DIVAS_H
+
+#include "sys.h"
+
+
+/* IOCTL commands */
+
+#define	DIA_IOCTL_INIT				(0)
+#define	DIA_IOCTL_LOAD				(1)
+#define	DIA_IOCTL_CONFIG			(2)
+#define	DIA_IOCTL_START				(3)
+#define	DIA_IOCTL_GET_NUM			(4)
+#define	DIA_IOCTL_GET_LIST			(5)
+#define	DIA_IOCTL_LOG				(6)
+#define	DIA_IOCTL_DETECT			(7)
+#define	DIA_IOCTL_SPACE				(8)
+#define DIA_IOCTL_GET_MEM           (9)
+#define DIA_IOCTL_FLAVOUR			(10)
+#define	DIA_IOCTL_XLOG_REQ			(11)
+
+/* Error codes */
+
+#define XLOG_ERR_CARD_NUM	(13)
+#define XLOG_ERR_DONE		(14)
+#define XLOG_ERR_CMD		(15)
+#define XLOG_ERR_TIMEOUT	(16)
+#define XLOG_ERR_CARD_STATE	(17)
+#define XLOG_ERR_UNKNOWN	(18)
+#define XLOG_OK 			(0)
+
+/* Adapter states */
+
+#define DIA_UNKNOWN		(0)
+#define DIA_RESET		(1)
+#define DIA_LOADED		(2)
+#define DIA_CONFIGURED	(3)
+#define DIA_RUNNING		(4)
+
+/* Stucture for getting card specific information from active cad driver */
+
+typedef struct
+{
+	int card_type;
+	int card_slot;
+	int	state;
+} dia_card_list_t;
+
+/* use following to select which logging to have active */
+
+#define	DIVAS_LOG_DEBUG		(1 << 0)
+#define	DIVAS_LOG_XLOG		(1 << 1)
+#define	DIVAS_LOG_IDI		(1 << 2)
+#define	DIVAS_LOG_CAPI		(1 << 3)
+
+/* stucture for DIA_IOCTL_LOG to get information from adapter */
+
+typedef struct
+{
+	int		card_id;
+	int		log_types;	/* bit mask of log types: use DIVAS_LOG_XXX */
+} dia_log_t;
+
+/* list of cards supported by this driver */
+
+#define	DIA_CARD_TYPE_DIVA_SERVER	(0)	/* Diva Server PRI */
+#define	DIA_CARD_TYPE_DIVA_SERVER_B	(1)	/* Diva Server BRI */
+#define	DIA_CARD_TYPE_DIVA_SERVER_Q	(2)	/* Diva Server 4-BRI */
+
+/* bus types */
+
+#define	DIA_BUS_TYPE_ISA		(0)
+#define	DIA_BUS_TYPE_ISA_PNP	(1)
+#define	DIA_BUS_TYPE_PCI		(2)
+#define	DIA_BUS_TYPE_MCA		(3)
+
+/* types of memory used (index for memory array below) */
+
+#define DIVAS_RAM_MEMORY 	0
+#define DIVAS_REG_MEMORY 	1
+#define DIVAS_CFG_MEMORY 	2
+#define DIVAS_SHARED_MEMORY 3
+#define DIVAS_CTL_MEMORY	4
+/*
+ * card config information
+ * passed as parameter to DIA_IOCTL_INIT ioctl to initialise new card
+ */
+
+typedef struct
+{
+	int		card_id;	/* unique id assigned to this card */
+	int		card_type;	/* use DIA_CARD_TYPE_xxx above */
+	int		bus_type;	/* use DIA_BUS_TYPE_xxx above */
+	int		bus_num;	/* bus number (instance number of bus type) */
+	int		func_num;	/* adapter function number (PCI register) */
+	int		slot;		/* slot number in bus */
+	unsigned char	irq;		/* IRQ number */
+    int     reset_base; /* Reset register  for I/O mapped cards */
+	int		io_base;	/* I/O base for I/O mapped cards */
+	void	*memory[5];	/* memory base addresses for memory mapped cards */
+	char	name[9];	/* name of adapter */
+	int		serial;		/* serial number */
+	unsigned char	int_priority;	/* Interrupt priority */
+} dia_card_t;
+
+/*
+ * protocol configuration information
+ * passed as parameter to DIA_IOCTL_CONFIG ioctl to configure card
+ */
+
+typedef struct
+{
+	int				card_id;			/* to identify particular card */
+	unsigned char	tei;
+	unsigned char	nt2;
+	unsigned char	watchdog;
+	unsigned char	permanent;
+	unsigned char	x_interface;
+	unsigned char	stable_l2;
+	unsigned char	no_order_check;
+	unsigned char	handset_type;
+	unsigned char	sig_flags;
+	unsigned char	low_channel;
+	unsigned char	prot_version;
+	unsigned char	crc4;
+	struct
+	{
+		unsigned char oad[32];
+		unsigned char osa[32];
+		unsigned char spid[32];
+	}terminal[2];
+} dia_config_t;
+
+/*
+ * code configuration 
+ * passed as parameter to DIA_IOCTL_LOAD ioctl
+ * one of these ioctl per code file to load
+ */
+
+typedef struct
+{
+	int				card_id;	/* card to load */
+	enum
+	{
+		DIA_CPU_CODE,			/* CPU code */
+		DIA_DSP_CODE,			/* DSP code */
+		DIA_CONT_CODE,			/* continuation of code */
+		DIA_TABLE_CODE,			/* code table */
+	        DIA_DLOAD_CNT,           /* number of downloads*/
+		DIA_FPGA_CODE
+	}				code_type;	/* code for CPU or DSP ? */
+	int				length;		/* length of code */
+	unsigned char	*code;		/* pointer (in user-space) to code */
+} dia_load_t;
+
+/*
+ * start configuration 
+ * passed as parameter to DIA_IOCTL_START ioctl
+ */
+
+typedef struct
+{
+	int				card_id;	/* card to start */
+} dia_start_t;
+
+/* used for retrieving memory from the card */
+
+typedef struct {
+	word	card_id;
+	dword 	addr;
+	byte	data[16 * 8];
+} mem_block_t;
+
+/* DIVA Server specific addresses */
+
+#define DIVAS_CPU_START_ADDR    (0x0)
+#define	ORG_MAX_PROTOCOL_CODE_SIZE	0x000A0000
+#define	ORG_MAX_DSP_CODE_SIZE		(0x000F0000 - ORG_MAX_PROTOCOL_CODE_SIZE)
+#define	ORG_DSP_CODE_BASE		(0xBF7F0000 - ORG_MAX_DSP_CODE_SIZE)
+#define DIVAS_DSP_START_ADDR    (0xBF7A0000)
+#define DIVAS_SHARED_OFFSET     (0x1000)
+#define MP_DSP_CODE_BASE           0xa03a0000
+#define MQ_PROTCODE_OFFSET  0x100000
+#define MQ_SM_OFFSET		0X0f0000
+
+#define	V90D_MAX_PROTOCOL_CODE_SIZE	0x00090000
+#define V90D_MAX_DSP_CODE_SIZE		(0x000F0000 - V90D_MAX_PROTOCOL_CODE_SIZE)
+#define	V90D_DSP_CODE_BASE		(0xBF7F0000 - V90D_MAX_DSP_CODE_SIZE)
+
+#define MQ_ORG_MAX_PROTOCOL_CODE_SIZE   0x000a0000  /* max 640K Protocol-Code */
+#define MQ_ORG_MAX_DSP_CODE_SIZE        0x00050000  /* max 320K DSP-Code */
+#define MQ_ORG_DSP_CODE_BASE           (MQ_MAX_DSP_DOWNLOAD_ADDR \
+                                      - MQ_ORG_MAX_DSP_CODE_SIZE)
+#define MQ_V90D_MAX_PROTOCOL_CODE_SIZE  0x00090000  /* max 576K Protocol-Code */
+#define MQ_V90D_MAX_DSP_CODE_SIZE       0x00060000  /* max 384K DSP-Code if V.90D included */
+#define	MQ_MAX_DSP_DOWNLOAD_ADDR        0xa03f0000
+#define MQ_V90D_DSP_CODE_BASE          (MQ_MAX_DSP_DOWNLOAD_ADDR \
+                                      - MQ_V90D_MAX_DSP_CODE_SIZE)
+
+
+#define ALIGNMENT_MASK_MAESTRA        0xfffffffc
+
+#endif /* DIVAS_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/dsp_defs.h linux.19p18/drivers/isdn/eicon/dsp_defs.h
--- linux.vanilla/drivers/isdn/eicon/dsp_defs.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/eicon/dsp_defs.h	Mon Feb 19 18:28:19 2001
@@ -0,0 +1,300 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.0  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+#ifndef DSP_DEFS_H_
+#define DSP_DEFS_H_
+
+#ifndef DSPDIDS_H_
+#include "dspdids.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*---------------------------------------------------------------------------*/
+
+#ifndef NULL
+#define NULL 0
+#endif
+#ifndef TRUE
+#define TRUE (0 == 0)
+#endif
+#ifndef FALSE
+#define FALSE (0 != 0)
+#endif
+
+
+/*---------------------------------------------------------------------------*/
+
+#define DSP_MEMORY_TYPE_EXTERNAL_DM         0
+#define DSP_MEMORY_TYPE_EXTERNAL_PM         1
+#define DSP_MEMORY_TYPE_INTERNAL_DM         2
+#define DSP_MEMORY_TYPE_INTERNAL_PM         3
+
+#define DSP_DOWNLOAD_FLAG_BOOTABLE          0x0001
+#define DSP_DOWNLOAD_FLAG_2181              0x0002
+#define DSP_DOWNLOAD_FLAG_TIMECRITICAL      0x0004
+#define DSP_DOWNLOAD_FLAG_COMPAND           0x0008
+
+#define DSP_MEMORY_BLOCK_COUNT              16
+
+#define DSP_SEGMENT_PM_FLAG                 0x0001
+#define DSP_SEGMENT_SHARED_FLAG             0x0002
+
+#define DSP_SEGMENT_EXTERNAL_DM             DSP_MEMORY_TYPE_EXTERNAL_DM
+#define DSP_SEGMENT_EXTERNAL_PM             DSP_MEMORY_TYPE_EXTERNAL_PM
+#define DSP_SEGMENT_INTERNAL_DM             DSP_MEMORY_TYPE_INTERNAL_DM
+#define DSP_SEGMENT_INTERNAL_PM             DSP_MEMORY_TYPE_INTERNAL_PM
+#define DSP_SEGMENT_FIRST_RELOCATABLE       4
+
+#define DSP_DATA_BLOCK_PM_FLAG              0x0001
+#define DSP_DATA_BLOCK_DWORD_FLAG           0x0002
+#define DSP_DATA_BLOCK_RESOLVE_FLAG         0x0004
+
+#define DSP_RELOC_NONE                      0x00
+#define DSP_RELOC_SEGMENT_MASK              0x3f
+#define DSP_RELOC_TYPE_MASK                 0xc0
+#define DSP_RELOC_TYPE_0                    0x00  /* relocation of address in DM word / high part of PM word */
+#define DSP_RELOC_TYPE_1                    0x40  /* relocation of address in low part of PM data word */
+#define DSP_RELOC_TYPE_2                    0x80  /* relocation of address in standard command */
+#define DSP_RELOC_TYPE_3                    0xc0  /* relocation of address in call/jump on flag in */
+
+#define DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE 48
+#define DSP_COMBIFILE_FORMAT_VERSION_BCD    0x0100
+
+#define DSP_FILE_FORMAT_IDENTIFICATION_SIZE 48
+#define DSP_FILE_FORMAT_VERSION_BCD         0x0100
+
+
+typedef struct tag_dsp_combifile_header
+{
+  char                  format_identification[DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE];
+  word                  format_version_bcd;
+  word                  header_size;
+  word                  combifile_description_size;
+  word                  directory_entries;
+  word                  directory_size;
+  word                  download_count;
+  word                  usage_mask_size;
+} t_dsp_combifile_header;
+
+typedef struct tag_dsp_combifile_directory_entry
+{
+  word                  card_type_number;
+  word                  file_set_number;
+} t_dsp_combifile_directory_entry;
+
+typedef struct tag_dsp_file_header
+{
+  char                  format_identification[DSP_FILE_FORMAT_IDENTIFICATION_SIZE];
+  word                  format_version_bcd;
+  word                  download_id;
+  word                  download_flags;
+  word                  required_processing_power;
+  word                  interface_channel_count;
+  word                  header_size;
+  word                  download_description_size;
+  word                  memory_block_table_size;
+  word                  memory_block_count;
+  word                  segment_table_size;
+  word                  segment_count;
+  word                  symbol_table_size;
+  word                  symbol_count;
+  word                  total_data_size_dm;
+  word                  data_block_count_dm;
+  word                  total_data_size_pm;
+  word                  data_block_count_pm;
+} t_dsp_file_header;
+
+typedef struct tag_dsp_memory_block_desc
+{
+  word                  alias_memory_block;
+  word                  memory_type;
+  word                  address;
+  word                  size;             /* DSP words */
+} t_dsp_memory_block_desc;
+
+typedef struct tag_dsp_segment_desc
+{
+  word                  memory_block;
+  word                  attributes;
+  word                  base;
+  word                  size;
+  word                  alignment;        /* ==0 -> no other legal start address than base */
+} t_dsp_segment_desc;
+
+typedef struct tag_dsp_symbol_desc
+{
+  word                  symbol_id;
+  word                  segment;
+  word                  offset;
+  word                  size;             /* DSP words */
+} t_dsp_symbol_desc;
+
+typedef struct tag_dsp_data_block_header
+{
+  word                  attributes;
+  word                  segment;
+  word                  offset;
+  word                  size;             /* DSP words */
+} t_dsp_data_block_header;
+
+typedef struct tag_dsp_download_desc      /* be sure to keep native alignment for MAESTRA's */
+{
+  word                  download_id;
+  word                  download_flags;
+  word                  required_processing_power;
+  word                  interface_channel_count;
+  word                  excess_header_size;
+  word                  memory_block_count;
+  word                  segment_count;
+  word                  symbol_count;
+  word                  data_block_count_dm;
+  word                  data_block_count_pm;
+  byte              	*p_excess_header_data;
+  char 					*p_download_description;
+  t_dsp_memory_block_desc *p_memory_block_table;
+  t_dsp_segment_desc 	*p_segment_table;
+  t_dsp_symbol_desc 	*p_symbol_table;
+  word 					*p_data_blocks_dm;
+  word 					*p_data_blocks_pm;
+} t_dsp_download_desc;
+
+#define DSP_DOWNLOAD_INDEX_KERNEL               0
+#define DSP30TX_DOWNLOAD_INDEX_KERNEL           1
+#define DSP30RX_DOWNLOAD_INDEX_KERNEL           2
+#define DSP_MAX_DOWNLOAD_COUNT                  35
+
+
+#define DSP_DOWNLOAD_MAX_SEGMENTS         16
+
+#define DSP_UDATA_REQUEST_RECONFIGURE     0
+/*
+parameters:
+  <word> reconfigure delay (in 8kHz samples)
+  <word> reconfigure code
+  <byte> reconfigure hdlc preamble flags
+*/
+
+#define DSP_RECONFIGURE_TX_FLAG           0x8000
+#define DSP_RECONFIGURE_SHORT_TRAIN_FLAG  0x4000
+#define DSP_RECONFIGURE_ECHO_PROTECT_FLAG 0x2000
+#define DSP_RECONFIGURE_HDLC_FLAG         0x1000
+#define DSP_RECONFIGURE_SYNC_FLAG         0x0800
+#define DSP_RECONFIGURE_PROTOCOL_MASK     0x00ff
+#define DSP_RECONFIGURE_IDLE              0
+#define DSP_RECONFIGURE_V25               1
+#define DSP_RECONFIGURE_V21_CH2           2
+#define DSP_RECONFIGURE_V27_2400          3
+#define DSP_RECONFIGURE_V27_4800          4
+#define DSP_RECONFIGURE_V29_7200          5
+#define DSP_RECONFIGURE_V29_9600          6
+#define DSP_RECONFIGURE_V33_12000         7
+#define DSP_RECONFIGURE_V33_14400         8
+#define DSP_RECONFIGURE_V17_7200          9
+#define DSP_RECONFIGURE_V17_9600          10
+#define DSP_RECONFIGURE_V17_12000         11
+#define DSP_RECONFIGURE_V17_14400         12
+
+/*
+data indications if transparent framer
+  <byte> data 0
+  <byte> data 1
+  ...
+
+data indications if HDLC framer
+  <byte> data 0
+  <byte> data 1
+  ...
+  <byte> CRC 0
+  <byte> CRC 1
+  <byte> preamble flags
+*/
+
+#define DSP_UDATA_INDICATION_SYNC         0
+/*
+returns:
+  <word> time of sync (sampled from counter at 8kHz)
+*/
+
+#define DSP_UDATA_INDICATION_DCD_OFF      1
+/*
+returns:
+  <word> time of DCD off (sampled from counter at 8kHz)
+*/
+
+#define DSP_UDATA_INDICATION_DCD_ON       2
+/*
+returns:
+  <word> time of DCD on (sampled from counter at 8kHz)
+  <byte> connected norm
+  <word> connected options
+  <dword> connected speed (bit/s)
+*/
+
+#define DSP_UDATA_INDICATION_CTS_OFF      3
+/*
+returns:
+  <word> time of CTS off (sampled from counter at 8kHz)
+*/
+
+#define DSP_UDATA_INDICATION_CTS_ON       4
+/*
+returns:
+  <word> time of CTS on (sampled from counter at 8kHz)
+  <byte> connected norm
+  <word> connected options
+  <dword> connected speed (bit/s)
+*/
+
+#define DSP_CONNECTED_NORM_UNSPECIFIED      0
+#define DSP_CONNECTED_NORM_V21              1
+#define DSP_CONNECTED_NORM_V23              2
+#define DSP_CONNECTED_NORM_V22              3
+#define DSP_CONNECTED_NORM_V22_BIS          4
+#define DSP_CONNECTED_NORM_V32_BIS          5
+#define DSP_CONNECTED_NORM_V34              6
+#define DSP_CONNECTED_NORM_V8               7
+#define DSP_CONNECTED_NORM_BELL_212A        8
+#define DSP_CONNECTED_NORM_BELL_103         9
+#define DSP_CONNECTED_NORM_V29_LEASED_LINE  10
+#define DSP_CONNECTED_NORM_V33_LEASED_LINE  11
+#define DSP_CONNECTED_NORM_TFAST            12
+#define DSP_CONNECTED_NORM_V21_CH2          13
+#define DSP_CONNECTED_NORM_V27_TER          14
+#define DSP_CONNECTED_NORM_V29              15
+#define DSP_CONNECTED_NORM_V33              16
+#define DSP_CONNECTED_NORM_V17              17
+
+#define DSP_CONNECTED_OPTION_TRELLIS        0x0001
+
+
+/*---------------------------------------------------------------------------*/
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/*---------------------------------------------------------------------------*/
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/dspdids.h linux.19p18/drivers/isdn/eicon/dspdids.h
--- linux.vanilla/drivers/isdn/eicon/dspdids.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/eicon/dspdids.h	Mon Feb 19 18:28:19 2001
@@ -0,0 +1,81 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.0  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+#ifndef DSPDIDS_H_
+#define DSPDIDS_H_
+
+
+/*---------------------------------------------------------------------------*/
+
+#define DSP_DID_INVALID			0
+#define DSP_DID_DIVA			1
+#define DSP_DID_DIVA_PRO		2
+#define DSP_DID_DIVA_PRO_20		3
+#define DSP_DID_DIVA_PRO_PCCARD		4
+#define DSP_DID_DIVA_SERVER_BRI_1M	5
+#define DSP_DID_DIVA_SERVER_BRI_2M	6
+#define DSP_DID_DIVA_SERVER_PRI_2M_TX	7
+#define DSP_DID_DIVA_SERVER_PRI_2M_RX	8
+#define DSP_DID_DIVA_SERVER_PRI_30M	9
+#define DSP_DID_TASK_HSCX		100
+#define DSP_DID_TASK_HSCX_PRI_2M_TX	101
+#define DSP_DID_TASK_HSCX_PRI_2M_RX	102
+#define DSP_DID_TASK_V110KRNL		200
+#define DSP_DID_OVERLAY_V1100		201
+#define DSP_DID_OVERLAY_V1101		202
+#define DSP_DID_OVERLAY_V1102		203
+#define DSP_DID_OVERLAY_V1103		204
+#define DSP_DID_OVERLAY_V1104		205
+#define DSP_DID_OVERLAY_V1105		206
+#define DSP_DID_OVERLAY_V1106		207
+#define DSP_DID_OVERLAY_V1107		208
+#define DSP_DID_OVERLAY_V1108		209
+#define DSP_DID_OVERLAY_V1109		210
+#define DSP_DID_TASK_V110_PRI_2M_TX	220
+#define DSP_DID_TASK_V110_PRI_2M_RX	221
+#define DSP_DID_TASK_MODEM		300
+#define DSP_DID_TASK_FAX05		400
+#define DSP_DID_TASK_VOICE		500
+#define DSP_DID_TASK_TIKRNL81		600
+#define DSP_DID_OVERLAY_DIAL		601
+#define DSP_DID_OVERLAY_V22		602
+#define DSP_DID_OVERLAY_V32		603
+#define DSP_DID_OVERLAY_FSK		604
+#define DSP_DID_OVERLAY_FAX		605
+#define DSP_DID_OVERLAY_VXX		606
+#define DSP_DID_OVERLAY_V8		607
+#define DSP_DID_OVERLAY_INFO		608
+#define DSP_DID_OVERLAY_V34		609
+#define DSP_DID_OVERLAY_DFX		610
+#define DSP_DID_PARTIAL_OVERLAY_DIAL	611
+#define DSP_DID_PARTIAL_OVERLAY_FSK	612
+#define DSP_DID_PARTIAL_OVERLAY_FAX	613
+#define DSP_DID_TASK_TIKRNL05		700
+
+
+/*---------------------------------------------------------------------------*/
+
+#endif
+
+/*---------------------------------------------------------------------------*/
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/eicon.h linux.19p18/drivers/isdn/eicon/eicon.h
--- linux.vanilla/drivers/isdn/eicon/eicon.h	Fri Apr 21 23:23:24 2000
+++ linux.19p18/drivers/isdn/eicon/eicon.h	Sat Mar  3 22:59:57 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon.h,v 1.19 2000/01/23 21:21:23 armin Exp $
+/* $Id: eicon.h,v 1.23.6.2 2001/02/13 11:43:30 kai Exp $
  *
  * ISDN low-level module for Eicon active ISDN-Cards.
  *
@@ -20,86 +20,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
- * $Log: eicon.h,v $
- * Revision 1.19  2000/01/23 21:21:23  armin
- * Added new trace capability and some updates.
- * DIVA Server BRI now supports data for ISDNLOG.
- *
- * Revision 1.18  1999/11/25 11:43:27  armin
- * Fixed statectrl and connect message.
- * X.75 fix and HDLC/transparent with autoconnect.
- * Minor cleanup.
- *
- * Revision 1.17  1999/10/26 21:15:33  armin
- * using define for checking phone number len to avoid buffer overflow.
- *
- * Revision 1.16  1999/10/08 22:09:33  armin
- * Some fixes of cards interface handling.
- * Bugfix of NULL pointer occurence.
- * Changed a few log outputs.
- *
- * Revision 1.15  1999/09/26 14:17:53  armin
- * Improved debug and log via readstat()
- *
- * Revision 1.14  1999/09/08 20:17:31  armin
- * Added microchannel patch from Erik Weber.
- *
- * Revision 1.13  1999/09/06 07:29:35  fritz
- * Changed my mail-address.
- *
- * Revision 1.12  1999/09/04 06:20:05  keil
- * Changes from kernel set_current_state()
- *
- * Revision 1.11  1999/08/29 17:23:44  armin
- * New setup compat.
- * Bugfix if compile as not module.
- *
- * Revision 1.10  1999/08/22 20:26:41  calle
- * backported changes from kernel 2.3.14:
- * - several #include "config.h" gone, others come.
- * - "struct device" changed to "struct net_device" in 2.3.14, added a
- *   define in isdn_compat.h for older kernel versions.
- *
- * Revision 1.9  1999/08/18 20:16:57  armin
- * Added XLOG function for all cards.
- * Bugfix of alloc_skb NULL pointer.
- *
- * Revision 1.8  1999/07/25 15:12:01  armin
- * fix of some debug logs.
- * enabled ISA-cards option.
- *
- * Revision 1.7  1999/07/11 17:16:23  armin
- * Bugfixes in queue handling.
- * Added DSP-DTMF decoder functions.
- * Reorganized ack_handler.
- *
- * Revision 1.6  1999/06/09 19:31:24  armin
- * Wrong PLX size for request_region() corrected.
- * Added first MCA code from Erik Weber.
- *
- * Revision 1.5  1999/03/29 11:19:41  armin
- * I/O stuff now in seperate file (eicon_io.c)
- * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
- *
- * Revision 1.4  1999/03/02 12:37:42  armin
- * Added some important checks.
- * Analog Modem with DSP.
- * Channels will be added to Link-Level after loading firmware.
- *
- * Revision 1.3  1999/01/24 20:14:07  armin
- * Changed and added debug stuff.
- * Better data sending. (still problems with tty's flip buffer)
- *
- * Revision 1.2  1999/01/10 18:46:04  armin
- * Bug with wrong values in HLC fixed.
- * Bytes to send are counted and limited now.
- *
- * Revision 1.1  1999/01/01 18:09:41  armin
- * First checkin of new eicon driver.
- * DIVA-Server BRI/PCI and PRI/PCI are supported.
- * Old diehl code is obsolete.
- *
- *
  */
 
 
@@ -124,6 +44,8 @@
 #define EICON_IOCTL_TEST     98
 #define EICON_IOCTL_DEBUGVAR 99
 
+#define EICON_IOCTL_DIA_OFFSET	100
+
 /* Bus types */
 #define EICON_BUS_ISA          1
 #define EICON_BUS_MCA          2
@@ -185,39 +107,10 @@
 	unsigned char code[1]; /* Rest (bootstrap- and firmware code) will be allocated */
 } eicon_isa_codebuf;
 
-/* Struct for downloading protocol via ioctl for PCI cards */
-typedef struct {
-        /* start-up parameters */
-        unsigned char tei;
-        unsigned char nt2;
-        unsigned char WatchDog;
-        unsigned char Permanent;
-        unsigned char XInterface;
-        unsigned char StableL2;
-        unsigned char NoOrderCheck;
-        unsigned char HandsetType;
-        unsigned char LowChannel;
-        unsigned char ProtVersion;
-        unsigned char Crc4;
-        unsigned char NoHscx30Mode;  /* switch PRI into No HSCX30 test mode */
-        unsigned char Loopback;      /* switch card into Loopback mode */
-        struct q931_link_s
-        {
-          unsigned char oad[32];
-          unsigned char osa[32];
-          unsigned char spid[32];
-        } l[2];
-        unsigned long protocol_len;
-	unsigned int  dsp_code_num;
-        unsigned long dsp_code_len[9];
-        unsigned char code[1]; /* Rest (protocol- and dsp code) will be allocated */
-} eicon_pci_codebuf;
-
 /* Data for downloading protocol via ioctl */
 typedef union {
 	eicon_isa_codebuf isa;
 	eicon_isa_codebuf mca;
-	eicon_pci_codebuf pci;
 } eicon_codebuf;
 
 /* Data for Management interface */
@@ -228,6 +121,7 @@
 	unsigned char data[700]; 
 } eicon_manifbuf;
 
+#define TRACE_OK                 (1)
 
 #ifdef __KERNEL__
 
@@ -245,7 +139,7 @@
 #include <asm/io.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
 #include <linux/ioport.h>
@@ -257,7 +151,6 @@
 #include <linux/isdn.h>
 #include <linux/isdnif.h>
 
-
 typedef struct {
   __u16 length __attribute__ ((packed)); /* length of data/parameter field */
   __u8  P[1];                          /* data/parameter field */
@@ -265,206 +158,34 @@
 
 #include "eicon_isa.h"
 
+#include "idi.h"
+
+typedef struct {
+  __u16 NextReq  __attribute__ ((packed));  /* pointer to next Req Buffer */
+  __u16 NextRc   __attribute__ ((packed));  /* pointer to next Rc Buffer  */
+  __u16 NextInd  __attribute__ ((packed));  /* pointer to next Ind Buffer */
+  __u8 ReqInput  __attribute__ ((packed));  /* number of Req Buffers sent */
+  __u8 ReqOutput  __attribute__ ((packed)); /* number of Req Buffers returned */
+  __u8 ReqReserved  __attribute__ ((packed));/*number of Req Buffers reserved */
+  __u8 Int  __attribute__ ((packed));       /* ISDN-P interrupt           */
+  __u8 XLock  __attribute__ ((packed));     /* Lock field for arbitration */
+  __u8 RcOutput  __attribute__ ((packed));  /* number of Rc buffers received */
+  __u8 IndOutput  __attribute__ ((packed)); /* number of Ind buffers received */
+  __u8 IMask  __attribute__ ((packed));     /* Interrupt Mask Flag        */
+  __u8 Reserved1[2]  __attribute__ ((packed)); /* reserved field, do not use */
+  __u8 ReadyInt  __attribute__ ((packed));  /* request field for ready int */
+  __u8 Reserved2[12]  __attribute__ ((packed)); /* reserved field, do not use */
+  __u8 InterfaceType  __attribute__ ((packed)); /* interface type 1=16K    */
+  __u16 Signature  __attribute__ ((packed));    /* ISDN-P initialized ind  */
+  __u8 B[1];                            /* buffer space for Req,Ind and Rc */
+} eicon_pr_ram;
+
 /* Macro for delay via schedule() */
 #define SLEEP(j) {                     \
-  current->state = TASK_UNINTERRUPTIBLE; \
+  set_current_state(TASK_UNINTERRUPTIBLE); \
   schedule_timeout(j);                 \
 }
 
-#endif /* KERNEL */
-
-#define DIVAS_SHARED_OFFSET	(0x1000)
-
-#define MIPS_BUFFER_SZ  128
-#define MIPS_MAINT_OFFS 0xff00
-
-#define XLOG_ERR_CARD_NUM       (13)
-#define XLOG_ERR_DONE           (14)
-#define XLOG_ERR_CMD            (15)
-#define XLOG_ERR_TIMEOUT        (16)
-#define XLOG_ERR_CARD_STATE     (17)
-#define XLOG_ERR_UNKNOWN        (18)
-#define XLOG_OK                  (0)
-
-#define TRACE_OK                 (1)
-
-typedef struct {
-  __u8 Id	__attribute__ ((packed));
-  __u8 uX	__attribute__ ((packed));
-  __u8 listen	__attribute__ ((packed));
-  __u8 active	__attribute__ ((packed));
-  __u8 sin[3]	__attribute__ ((packed));
-  __u8 bc[6]	__attribute__ ((packed));
-  __u8 llc[6]	__attribute__ ((packed));
-  __u8 hlc[6]	__attribute__ ((packed));
-  __u8 oad[20]	__attribute__ ((packed));
-}DSigStruc;
-
-typedef struct {
-  __u32 cx_b1	__attribute__ ((packed));
-  __u32 cx_b2	__attribute__ ((packed));
-  __u32 cr_b1	__attribute__ ((packed));
-  __u32 cr_b2	__attribute__ ((packed));
-  __u32 px_b1	__attribute__ ((packed));
-  __u32 px_b2	__attribute__ ((packed));
-  __u32 pr_b1	__attribute__ ((packed));
-  __u32 pr_b2	__attribute__ ((packed));
-  __u16 er_b1	__attribute__ ((packed));
-  __u16 er_b2	__attribute__ ((packed));
-}BL1Struc;
-
-typedef struct {
-  __u32 XTotal	__attribute__ ((packed));
-  __u32 RTotal	__attribute__ ((packed));
-  __u16 XError	__attribute__ ((packed));
-  __u16 RError	__attribute__ ((packed));
-}L2Struc;
-
-typedef struct {
-  __u16 free_n;
-}OSStruc;
-
-typedef union
-{
-  DSigStruc DSigStats;
-  BL1Struc BL1Stats;
-  L2Struc L2Stats;
-  OSStruc OSStats;
-  __u8   b[MIPS_BUFFER_SZ];
-  __u16   w[MIPS_BUFFER_SZ>>1];
-  __u16   l[MIPS_BUFFER_SZ>>2]; /* word is wrong, do not use! Use 'd' instead. */
-  __u32  d[MIPS_BUFFER_SZ>>2];
-} MIPS_BUFFER;
-
-typedef struct
-{
-  __u8 req	__attribute__ ((packed));
-  __u8 rc	__attribute__ ((packed));
-  __u8 reserved[2]	__attribute__ ((packed));     /* R3000 alignment ... */
-  __u8 *mem	__attribute__ ((packed));
-  __u16 length	__attribute__ ((packed));		/* used to be short */
-  __u16 port	__attribute__ ((packed));
-  __u8 fill[4]	__attribute__ ((packed));         /* data at offset 16   */
-  MIPS_BUFFER data	__attribute__ ((packed));
-} mi_pc_maint_t;
-
-typedef struct
-{
-        __u16 command;
-        mi_pc_maint_t pcm;
-}xlogreq_t;
-
-typedef struct{
-        __u16 code	__attribute__ ((packed));	/* used to be short */
-        __u16 timeh	__attribute__ ((packed));
-        __u16 timel	__attribute__ ((packed));
-        char buffer[MIPS_BUFFER_SZ - 6];
-}xlog_entry_t;
-
-
-#define DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE 48
-#define DSP_COMBIFILE_FORMAT_VERSION_BCD    0x0100
-
-#define DSP_FILE_FORMAT_IDENTIFICATION_SIZE 48
-#define DSP_FILE_FORMAT_VERSION_BCD         0x0100
-
-typedef struct tag_dsp_combifile_header
-{
-  char                  format_identification[DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE] __attribute__ ((packed));
-  __u16                  format_version_bcd             __attribute__ ((packed));
-  __u16                  header_size                    __attribute__ ((packed));
-  __u16                  combifile_description_size     __attribute__ ((packed));
-  __u16                  directory_entries              __attribute__ ((packed));
-  __u16                  directory_size                 __attribute__ ((packed));
-  __u16                  download_count                 __attribute__ ((packed));
-  __u16                  usage_mask_size                __attribute__ ((packed));
-} t_dsp_combifile_header;
-
-typedef struct tag_dsp_combifile_directory_entry
-{
-  __u16                  card_type_number               __attribute__ ((packed));
-  __u16                  file_set_number                __attribute__ ((packed));
-} t_dsp_combifile_directory_entry;
-
-typedef struct tag_dsp_file_header
-{
-  char                  format_identification[DSP_FILE_FORMAT_IDENTIFICATION_SIZE] __attribute__ ((packed));
-  __u16                 format_version_bcd              __attribute__ ((packed));
-  __u16                 download_id                     __attribute__ ((packed));
-  __u16                 download_flags                  __attribute__ ((packed));
-  __u16                 required_processing_power       __attribute__ ((packed));
-  __u16                 interface_channel_count         __attribute__ ((packed));
-  __u16                 header_size                     __attribute__ ((packed));
-  __u16                 download_description_size       __attribute__ ((packed));
-  __u16                 memory_block_table_size         __attribute__ ((packed));
-  __u16                 memory_block_count              __attribute__ ((packed));
-  __u16                 segment_table_size              __attribute__ ((packed));
-  __u16                 segment_count                   __attribute__ ((packed));
-  __u16                 symbol_table_size               __attribute__ ((packed));
-  __u16                 symbol_count                    __attribute__ ((packed));
-  __u16                 total_data_size_dm              __attribute__ ((packed));
-  __u16                 data_block_count_dm             __attribute__ ((packed));
-  __u16                 total_data_size_pm              __attribute__ ((packed));
-  __u16                 data_block_count_pm             __attribute__ ((packed));
-} t_dsp_file_header;
-
-typedef struct tag_dsp_memory_block_desc
-{
-  __u16                 alias_memory_block;
-  __u16                 memory_type;
-  __u16                 address;
-  __u16                 size;             /* DSP words */
-} t_dsp_memory_block_desc;
-
-typedef struct tag_dsp_segment_desc
-{
-  __u16                 memory_block;
-  __u16                 attributes;
-  __u16                 base;
-  __u16                 size;
-  __u16                 alignment;        /* ==0 -> no other legal start address than base */
-} t_dsp_segment_desc;
-
-typedef struct tag_dsp_symbol_desc
-{
-  __u16                 symbol_id;
-  __u16                 segment;
-  __u16                 offset;
-  __u16                 size;             /* DSP words */
-} t_dsp_symbol_desc;
-
-typedef struct tag_dsp_data_block_header
-{
-  __u16                 attributes;
-  __u16                 segment;
-  __u16                 offset;
-  __u16                 size;             /* DSP words */
-} t_dsp_data_block_header;
-
-typedef struct tag_dsp_download_desc      /* be sure to keep native alignment for MAESTRA's */
-{
-  __u16                 download_id;
-  __u16                 download_flags;
-  __u16                 required_processing_power;
-  __u16                 interface_channel_count;
-  __u16                 excess_header_size;
-  __u16                 memory_block_count;
-  __u16                 segment_count;
-  __u16                 symbol_count;
-  __u16                 data_block_count_dm;
-  __u16                 data_block_count_pm;
-  __u8  *            p_excess_header_data               __attribute__ ((packed));
-  char  *            p_download_description             __attribute__ ((packed));
-  t_dsp_memory_block_desc  *p_memory_block_table        __attribute__ ((packed));
-  t_dsp_segment_desc  *p_segment_table                  __attribute__ ((packed));
-  t_dsp_symbol_desc  *p_symbol_table                    __attribute__ ((packed));
-  __u16 *            p_data_blocks_dm                   __attribute__ ((packed));
-  __u16 *            p_data_blocks_pm                   __attribute__ ((packed));
-} t_dsp_download_desc;
-
-
-#ifdef __KERNEL__
-
 typedef struct {
   __u8                  Req;            /* pending request          */
   __u8                  Rc;             /* return code received     */
@@ -508,6 +229,7 @@
 	unsigned short statectrl;	 /* State controling bits	*/
 	unsigned short eazmask;          /* EAZ-Mask for this Channel   */
 	int		queued;          /* User-Data Bytes in TX queue */
+	int		pqueued;         /* User-Data Packets in TX queue */
 	int		waitq;           /* User-Data Bytes in wait queue */
 	int		waitpq;          /* User-Data Bytes in packet queue */
 	struct sk_buff *tskb1;           /* temp skb 1			*/
@@ -518,7 +240,9 @@
 	T30_s		*fax;		 /* pointer to fax data in LL	*/
 	eicon_ch_fax_buf fax2;		 /* fax related struct		*/
 #endif
-	entity		e;		 /* Entity  			*/
+	entity		e;		 /* Native Entity		*/
+	ENTITY		de;		 /* Divas D Entity 		*/
+	ENTITY		be;		 /* Divas B Entity 		*/
 	char		cpn[32];	 /* remember cpn		*/
 	char		oad[32];	 /* remember oad		*/
 	char		dsa[32];	 /* remember dsa		*/
@@ -542,8 +266,6 @@
 #define EICON_FLAGS_MVALID   8 /* Cards membase is valid */
 #define EICON_FLAGS_LOADED   8 /* Firmware loaded        */
 
-#define EICON_BCH            2 /* # of channels per card */
-
 /* D-Channel states */
 #define EICON_STATE_NULL     0
 #define EICON_STATE_ICALL    1
@@ -565,9 +287,6 @@
 
 #define EICON_MAX_QUEUE  2138
 
-#define EICON_LOCK_TX 0
-#define EICON_LOCK_RX 1
-
 typedef union {
 	eicon_isa_card isa;
 	eicon_pci_card pci;
@@ -593,17 +312,12 @@
 	__u8 more;
 } eicon_indhdr;
 
-typedef struct msn_entry {
-	char eaz;
-        char msn[16];
-        struct msn_entry * next;
-} msn_entry;
-
 /*
  * Per card driver data
  */
 typedef struct eicon_card {
 	eicon_hwif hwif;                 /* Hardware dependant interface     */
+	DESCRIPTOR *d;			 /* IDI Descriptor		     */
         u_char ptype;                    /* Protocol type (1TR6 or Euro)     */
         u_char bus;                      /* Bustype (ISA, MCA, PCI)          */
         u_char type;                     /* Cardtype (EICON_CTYPE_...)       */
@@ -621,49 +335,23 @@
 	struct tq_struct snd_tq;         /* Task struct for xmit bh          */
 	struct tq_struct rcv_tq;         /* Task struct for rcv bh           */
 	struct tq_struct ack_tq;         /* Task struct for ack bh           */
-	msn_entry *msn_list;
 	eicon_chan*	IdTable[256];	 /* Table to find entity   */
 	__u16  ref_in;
 	__u16  ref_out;
 	int    nchannels;                /* Number of B-Channels             */
 	int    ReadyInt;		 /* Ready Interrupt		     */
 	eicon_chan *bch;                 /* B-Channel status/control         */
-	char   status_buf[256];          /* Buffer for status messages       */
-	char   *status_buf_read;
-	char   *status_buf_write;
-	char   *status_buf_end;
+	DBUFFER *dbuf;			 /* Dbuffer for Diva Server	     */
+	BUFFERS *sbuf;			 /* Buffer for Diva Server	     */
+	char *sbufp;			 /* Data Buffer for Diva Server	     */
         isdn_if interface;               /* Interface to upper layer         */
-        char regname[35];                /* Name used for request_region     */
+        char regname[35];                /* Drivers card name 		     */
 #ifdef CONFIG_MCA
         int	mca_slot;	 	 /* # of cards MCA slot              */
 	int	mca_io;			 /* MCA cards IO port		     */
 #endif /* CONFIG_MCA */
 } eicon_card;
 
-/* -----------------------------------------------------------**
-** The PROTOCOL_FEATURE_STRING                                **
-** defines capabilities and                                   **
-** features of the actual protocol code. It's used as a bit   **
-** mask.                                                      **
-** The following Bits are defined:                            **
-** -----------------------------------------------------------*/
-#define PROTCAP_TELINDUS  0x0001  /* Telindus Variant of protocol code   */
-#define PROTCAP_MANIF     0x0002  /* Management interface implemented    */
-#define PROTCAP_V_42      0x0004  /* V42 implemented                     */
-#define PROTCAP_V90D      0x0008  /* V.90D (implies up to 384k DSP code) */
-#define PROTCAP_EXTD_FAX  0x0010  /* Extended FAX (ECM, 2D, T6, Polling) */
-#define PROTCAP_FREE4     0x0020  /* not used                            */
-#define PROTCAP_FREE5     0x0040  /* not used                            */
-#define PROTCAP_FREE6     0x0080  /* not used                            */
-#define PROTCAP_FREE7     0x0100  /* not used                            */
-#define PROTCAP_FREE8     0x0200  /* not used                            */
-#define PROTCAP_FREE9     0x0400  /* not used                            */
-#define PROTCAP_FREE10    0x0800  /* not used                            */
-#define PROTCAP_FREE11    0x1000  /* not used                            */
-#define PROTCAP_FREE12    0x2000  /* not used                            */
-#define PROTCAP_FREE13    0x4000  /* not used                            */
-#define PROTCAP_EXTENSION 0x8000  /* used for future extentions          */
-
 #include "eicon_idi.h"
 
 extern eicon_card *cards;
@@ -688,13 +376,11 @@
         mark_bh(IMMEDIATE_BH);
 }
 
-extern char *eicon_find_eaz(eicon_card *, char);
-extern int eicon_addcard(int, int, int, char *);
+extern int eicon_addcard(int, int, int, char *, int);
 extern void eicon_io_transmit(eicon_card *card);
 extern void eicon_irq(int irq, void *dev_id, struct pt_regs *regs);
 extern void eicon_io_rcv_dispatch(eicon_card *ccard);
 extern void eicon_io_ack_dispatch(eicon_card *ccard);
-extern int eicon_get_xlog(eicon_card *card, xlogreq_t *xlogreq);
 #ifdef CONFIG_MCA
 extern int eicon_mca_find_card(int, int, int, char *);
 extern int eicon_mca_probe(int, int, int, int, char *);
@@ -704,6 +390,8 @@
 extern ulong DebugVar;
 extern void eicon_log(eicon_card * card, int level, const char *fmt, ...);
 extern void eicon_putstatus(eicon_card * card, char * buf);
+
+extern spinlock_t eicon_lock;
 
 #endif  /* __KERNEL__ */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/eicon_dsp.h linux.19p18/drivers/isdn/eicon/eicon_dsp.h
--- linux.vanilla/drivers/isdn/eicon/eicon_dsp.h	Fri Apr 21 12:46:08 2000
+++ linux.19p18/drivers/isdn/eicon/eicon_dsp.h	Mon Feb 19 18:28:19 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon_dsp.h,v 1.5 2000/01/23 21:21:23 armin Exp $
+/* $Id: eicon_dsp.h,v 1.7 2000/05/07 08:51:04 armin Exp $
  *
  * ISDN lowlevel-module for Eicon active cards.
  *        DSP definitions
@@ -20,75 +20,14 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * $Log: eicon_dsp.h,v $
- * Revision 1.5  2000/01/23 21:21:23  armin
- * Added new trace capability and some updates.
- * DIVA Server BRI now supports data for ISDNLOG.
- *
- * Revision 1.4  1999/07/25 15:12:02  armin
- * fix of some debug logs.
- * enabled ISA-cards option.
- *
- * Revision 1.3  1999/07/11 17:16:24  armin
- * Bugfixes in queue handling.
- * Added DSP-DTMF decoder functions.
- * Reorganized ack_handler.
- *
- * Revision 1.2  1999/03/29 11:19:42  armin
- * I/O stuff now in seperate file (eicon_io.c)
- * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
- *
- * Revision 1.1  1999/03/02 12:18:54  armin
- * First checkin of DSP defines for audio features.
- *
  *
  */
 
 #ifndef DSP_H 
 #define DSP_H
 
-#define DSP_UDATA_REQUEST_RECONFIGURE           0
-/*
-parameters:
-  <word> reconfigure delay (in 8kHz samples)
-  <word> reconfigure code
-  <byte> reconfigure hdlc preamble flags
-*/
-
-#define DSP_RECONFIGURE_TX_FLAG             0x8000
-#define DSP_RECONFIGURE_SHORT_TRAIN_FLAG    0x4000
-#define DSP_RECONFIGURE_ECHO_PROTECT_FLAG   0x2000
-#define DSP_RECONFIGURE_HDLC_FLAG           0x1000
-#define DSP_RECONFIGURE_SYNC_FLAG           0x0800
-#define DSP_RECONFIGURE_PROTOCOL_MASK       0x00ff
-#define DSP_RECONFIGURE_IDLE                0
-#define DSP_RECONFIGURE_V25                 1
-#define DSP_RECONFIGURE_V21_CH2             2
-#define DSP_RECONFIGURE_V27_2400            3
-#define DSP_RECONFIGURE_V27_4800            4
-#define DSP_RECONFIGURE_V29_7200            5
-#define DSP_RECONFIGURE_V29_9600            6
-#define DSP_RECONFIGURE_V33_12000           7
-#define DSP_RECONFIGURE_V33_14400           8
-#define DSP_RECONFIGURE_V17_7200            9
-#define DSP_RECONFIGURE_V17_9600            10
-#define DSP_RECONFIGURE_V17_12000           11
-#define DSP_RECONFIGURE_V17_14400           12
+#include "dsp_defs.h"
 
-/*
-data indications if transparent framer
-  <byte> data 0
-  <byte> data 1
-  ...
-
-data indications if HDLC framer
-  <byte> data 0
-  <byte> data 1
-  ...
-  <byte> CRC 0
-  <byte> CRC 1
-  <byte> preamble flags
-*/
 
 #define DSP_UDATA_REQUEST_SWITCH_FRAMER         1
 /*
@@ -122,49 +61,6 @@
   - none -
 */
 
-
-#define DSP_UDATA_INDICATION_SYNC               0
-/*
-returns:
-  <word> time of sync (sampled from counter at 8kHz)
-*/
-
-#define DSP_UDATA_INDICATION_DCD_OFF            1
-/*
-returns:
-  <word> time of DCD off (sampled from counter at 8kHz)
-*/
-
-#define DSP_UDATA_INDICATION_DCD_ON             2
-/*
-returns:
-  <word> time of DCD on (sampled from counter at 8kHz)
-  <byte> connected norm
-  <word> connected options
-  <dword> connected speed (bit/s, max of tx and rx speed)
-  <word> roundtrip delay (ms)
-  <dword> connected speed tx (bit/s)
-  <dword> connected speed rx (bit/s)
-*/
-
-#define DSP_UDATA_INDICATION_CTS_OFF            3
-/*
-returns:
-  <word> time of CTS off (sampled from counter at 8kHz)
-*/
-
-#define DSP_UDATA_INDICATION_CTS_ON             4
-/*
-returns:
-  <word> time of CTS on (sampled from counter at 8kHz)
-  <byte> connected norm
-  <word> connected options
-  <dword> connected speed (bit/s, max of tx and rx speed)
-  <word> roundtrip delay (ms)
-  <dword> connected speed tx (bit/s)
-  <dword> connected speed rx (bit/s)
-*/
-
 typedef struct eicon_dsp_ind {
 	__u16	time		__attribute__ ((packed));
 	__u8	norm		__attribute__ ((packed));
@@ -175,32 +71,11 @@
 	__u32	rxspeed		__attribute__ ((packed));
 } eicon_dsp_ind;
 
-#define DSP_CONNECTED_NORM_UNSPECIFIED      0
-#define DSP_CONNECTED_NORM_V21              1
-#define DSP_CONNECTED_NORM_V23              2
-#define DSP_CONNECTED_NORM_V22              3
-#define DSP_CONNECTED_NORM_V22_BIS          4
-#define DSP_CONNECTED_NORM_V32_BIS          5
-#define DSP_CONNECTED_NORM_V34              6
-#define DSP_CONNECTED_NORM_V8               7
-#define DSP_CONNECTED_NORM_BELL_212A        8
-#define DSP_CONNECTED_NORM_BELL_103         9
-#define DSP_CONNECTED_NORM_V29_LEASED_LINE  10
-#define DSP_CONNECTED_NORM_V33_LEASED_LINE  11
-#define DSP_CONNECTED_NORM_V90              12
-#define DSP_CONNECTED_NORM_V21_CH2          13
-#define DSP_CONNECTED_NORM_V27_TER          14
-#define DSP_CONNECTED_NORM_V29              15
-#define DSP_CONNECTED_NORM_V33              16
-#define DSP_CONNECTED_NORM_V17              17
-
-#define DSP_CONNECTED_OPTION_TRELLIS             0x0001
 #define DSP_CONNECTED_OPTION_V42_TRANS           0x0002
 #define DSP_CONNECTED_OPTION_V42_LAPM            0x0004
 #define DSP_CONNECTED_OPTION_SHORT_TRAIN         0x0008
 #define DSP_CONNECTED_OPTION_TALKER_ECHO_PROTECT 0x0010
 
-
 #define DSP_UDATA_INDICATION_DISCONNECT         5
 /*
 returns:
@@ -213,7 +88,6 @@
 #define DSP_DISCONNECT_CAUSE_INCOMPATIBILITY    0x03
 #define DSP_DISCONNECT_CAUSE_CLEARDOWN          0x04
 #define DSP_DISCONNECT_CAUSE_TRAINING_TIMEOUT   0x05
-
 
 #define DSP_UDATA_INDICATION_TX_CONFIRMATION    6
 /*
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/eicon_idi.c linux.19p18/drivers/isdn/eicon/eicon_idi.c
--- linux.vanilla/drivers/isdn/eicon/eicon_idi.c	Fri Apr 21 12:46:08 2000
+++ linux.19p18/drivers/isdn/eicon/eicon_idi.c	Mon Feb 19 18:28:19 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon_idi.c,v 1.33 2000/03/06 15:45:17 armin Exp $
+/* $Id: eicon_idi.c,v 1.41.6.1 2001/02/10 14:44:09 kai Exp $
  *
  * ISDN lowlevel-module for Eicon active cards.
  *        IDI interface 
@@ -25,135 +25,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
- * $Log: eicon_idi.c,v $
- * Revision 1.33  2000/03/06 15:45:17  armin
- * Fixed incomplete number handling with BRI PtP connection.
- *
- * Revision 1.32  2000/03/04 17:04:21  armin
- * Fix of statemachine, B-connect before D-connect,
- * thanks to Helmut Adams <adams@ipcon.de>
- * Minor change in send-data packet handling.
- *
- * Revision 1.31  2000/02/22 16:26:40  armin
- * Fixed membase error message.
- * Fixed missing log buffer struct.
- *
- * Revision 1.30  2000/02/16 16:08:46  armin
- * Fixed virtual channel handling of IDI.
- *
- * Revision 1.29  2000/01/23 21:21:23  armin
- * Added new trace capability and some updates.
- * DIVA Server BRI now supports data for ISDNLOG.
- *
- * Revision 1.28  2000/01/20 19:55:34  keil
- * Add FAX Class 1 support
- *
- * Revision 1.27  1999/11/29 13:12:03  armin
- * Autoconnect on L2_TRANS doesn't work with link_level correctly,
- * changed back to former mode.
- *
- * Revision 1.26  1999/11/25 11:43:27  armin
- * Fixed statectrl and connect message.
- * X.75 fix and HDLC/transparent with autoconnect.
- * Minor cleanup.
- *
- * Revision 1.25  1999/11/18 20:30:55  armin
- * removed old workaround for ISA cards.
- *
- * Revision 1.24  1999/10/26 21:15:33  armin
- * using define for checking phone number len to avoid buffer overflow.
- *
- * Revision 1.23  1999/10/11 18:13:25  armin
- * Added fax capabilities for Eicon Diva Server cards.
- *
- * Revision 1.22  1999/10/08 22:09:33  armin
- * Some fixes of cards interface handling.
- * Bugfix of NULL pointer occurence.
- * Changed a few log outputs.
- *
- * Revision 1.21  1999/09/26 14:17:53  armin
- * Improved debug and log via readstat()
- *
- * Revision 1.20  1999/09/21 20:35:43  armin
- * added more error checking.
- *
- * Revision 1.19  1999/09/21 20:06:40  armin
- * Added pointer checks.
- *
- * Revision 1.18  1999/09/07 12:48:05  armin
- * Prepared for sub-address usage.
- *
- * Revision 1.17  1999/09/07 12:35:39  armin
- * Better checking and channel Id handling.
- *
- * Revision 1.16  1999/09/04 13:44:19  armin
- * Fix of V.42 analog Modem negotiation handling.
- *
- * Revision 1.15  1999/08/28 21:32:50  armin
- * Prepared for fax related functions.
- * Now compilable without errors/warnings.
- *
- * Revision 1.14  1999/08/28 20:24:40  armin
- * Corrected octet 3/3a in CPN/OAD information element.
- * Thanks to John Simpson <xfl23@dial.pipex.com>
- *
- * Revision 1.13  1999/08/22 20:26:44  calle
- * backported changes from kernel 2.3.14:
- * - several #include "config.h" gone, others come.
- * - "struct device" changed to "struct net_device" in 2.3.14, added a
- *   define in isdn_compat.h for older kernel versions.
- *
- * Revision 1.12  1999/08/18 20:16:59  armin
- * Added XLOG function for all cards.
- * Bugfix of alloc_skb NULL pointer.
- *
- * Revision 1.11  1999/07/25 15:12:03  armin
- * fix of some debug logs.
- * enabled ISA-cards option.
- *
- * Revision 1.10  1999/07/11 17:16:24  armin
- * Bugfixes in queue handling.
- * Added DSP-DTMF decoder functions.
- * Reorganized ack_handler.
- *
- * Revision 1.9  1999/03/29 11:19:42  armin
- * I/O stuff now in seperate file (eicon_io.c)
- * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
- *
- * Revision 1.8  1999/03/02 12:37:43  armin
- * Added some important checks.
- * Analog Modem with DSP.
- * Channels will be added to Link-Level after loading firmware.
- *
- * Revision 1.7  1999/02/03 18:34:35  armin
- * Channel selection for outgoing calls w/o CHI.
- * Added channel # in debug messages.
- * L2 Transparent should work with 800 byte/packet now.
- *
- * Revision 1.6  1999/01/26 07:18:59  armin
- * Bug with wrong added CPN fixed.
- *
- * Revision 1.5  1999/01/24 20:14:11  armin
- * Changed and added debug stuff.
- * Better data sending. (still problems with tty's flip buffer)
- *
- * Revision 1.4  1999/01/10 18:46:05  armin
- * Bug with wrong values in HLC fixed.
- * Bytes to send are counted and limited now.
- *
- * Revision 1.3  1999/01/05 14:49:34  armin
- * Added experimental usage of full BC and HLC for
- * speech, 3.1kHz audio, fax gr.2/3
- *
- * Revision 1.2  1999/01/04 13:19:29  armin
- * Channel status with listen-request wrong - fixed.
- *
- * Revision 1.1  1999/01/01 18:09:41  armin
- * First checkin of new eicon driver.
- * DIVA-Server BRI/PCI and PRI/PCI are supported.
- * Old diehl code is obsolete.
- *
- *
  */
 
 #include <linux/config.h>
@@ -161,25 +32,14 @@
 #include "eicon.h"
 #include "eicon_idi.h"
 #include "eicon_dsp.h"
+#include "uxio.h"
 
 #undef EICON_FULL_SERVICE_OKTETT
 
-char *eicon_idi_revision = "$Revision: 1.33 $";
+char *eicon_idi_revision = "$Revision: 1.41.6.1 $";
 
 eicon_manifbuf *manbuf;
 
-static char BC_Speech[3] = 	{ 0x80, 0x90, 0xa3 };
-static char BC_31khz[3] =  	{ 0x90, 0x90, 0xa3 };
-static char BC_64k[2] =    	{ 0x88, 0x90 };
-static char BC_video[3] =  	{ 0x91, 0x90, 0xa5 };
-
-#ifdef EICON_FULL_SERVICE_OKTETT
-/* 
-static char HLC_telephony[2] =	{ 0x91, 0x81 }; 
-*/
-static char HLC_faxg3[2] =  	{ 0x91, 0x84 };
-#endif
-
 int eicon_idi_manage_assign(eicon_card *card);
 int eicon_idi_manage_remove(eicon_card *card);
 int idi_fill_in_T30(eicon_chan *chan, unsigned char *buffer);
@@ -209,7 +69,7 @@
 	reqbuf->XBuffer.P[l++] = 0; /* end */
 	reqbuf->Req = ASSIGN;
 	reqbuf->ReqCh = 0;
-	reqbuf->ReqId = 0;
+	reqbuf->ReqId = DSIG_ID;
 	reqbuf->XBuffer.length = l;
 	reqbuf->Reference = 0; /* Sig Entity */
   }
@@ -221,6 +81,9 @@
 	reqbuf->XBuffer.P[l++] = LLC;
 	reqbuf->XBuffer.P[l++] = 2;
 	switch(chan->l2prot) {
+		case ISDN_PROTO_L2_V11096:
+		case ISDN_PROTO_L2_V11019:
+		case ISDN_PROTO_L2_V11038:
 		case ISDN_PROTO_L2_TRANS:
 			reqbuf->XBuffer.P[l++] = 2; /* transparent */
 			break;
@@ -262,7 +125,7 @@
 	reqbuf->XBuffer.P[l++] = 0; /* end */
 	reqbuf->Req = ASSIGN;
 	reqbuf->ReqCh = 0;
-	reqbuf->ReqId = 0x20;
+	reqbuf->ReqId = NL_ID;
 	reqbuf->XBuffer.length = l;
 	reqbuf->Reference = 1; /* Net Entity */
   }
@@ -282,6 +145,21 @@
 }
 
 int
+idi_put_suspend_req(eicon_REQ *reqbuf, eicon_chan *chan)
+{
+	reqbuf->Req = SUSPEND;
+	reqbuf->ReqCh = 0;
+	reqbuf->ReqId = 1;
+	reqbuf->XBuffer.P[0] = CAI;
+	reqbuf->XBuffer.P[1] = 1;
+	reqbuf->XBuffer.P[2] = chan->No;
+	reqbuf->XBuffer.P[3] = 0;
+	reqbuf->XBuffer.length = 4;
+	reqbuf->Reference = 0; /* Sig Entity */
+   return(0);
+}
+
+int
 idi_call_res_req(eicon_REQ *reqbuf, eicon_chan *chan)
 {
 	int l = 9;
@@ -295,7 +173,7 @@
 	reqbuf->XBuffer.P[4] = 0;
 	reqbuf->XBuffer.P[5] = 0;
 	reqbuf->XBuffer.P[6] = 32;
-	reqbuf->XBuffer.P[7] = 3;
+	reqbuf->XBuffer.P[7] = 0;
 	switch(chan->l2prot) {
 		case ISDN_PROTO_L2_X75I:
 		case ISDN_PROTO_L2_X75UI:
@@ -391,6 +269,12 @@
 		case HANGUP:
 			idi_put_req(reqbuf, HANGUP, 0, 0);
 			break;
+		case SUSPEND:
+			idi_put_suspend_req(reqbuf, chan);
+			break;
+		case RESUME:
+			idi_put_req(reqbuf, RESUME, 0 ,0);
+			break;
 		case REJECT:
 			idi_put_req(reqbuf, REJECT, 0 ,0);
 			break;
@@ -400,17 +284,20 @@
 		case CALL_RES:
 			idi_call_res_req(reqbuf, chan);
 			break;
-		case IDI_N_CONNECT|0x700:
-			idi_put_req(reqbuf, IDI_N_CONNECT, 1, 0);
+		case CALL_HOLD:
+			idi_put_req(reqbuf, CALL_HOLD, 0, 0);
+			break;
+		case N_CONNECT|0x700:
+			idi_put_req(reqbuf, N_CONNECT, 1, 0);
 			break;
-		case IDI_N_CONNECT_ACK|0x700:
-			idi_put_req(reqbuf, IDI_N_CONNECT_ACK, 1, 0);
+		case N_CONNECT_ACK|0x700:
+			idi_put_req(reqbuf, N_CONNECT_ACK, 1, 0);
 			break;
-		case IDI_N_DISC|0x700:
-			idi_put_req(reqbuf, IDI_N_DISC, 1, chan->e.IndCh);
+		case N_DISC|0x700:
+			idi_put_req(reqbuf, N_DISC, 1, chan->e.IndCh);
 			break;
-		case IDI_N_DISC_ACK|0x700:
-			idi_put_req(reqbuf, IDI_N_DISC_ACK, 1, chan->e.IndCh);
+		case N_DISC_ACK|0x700:
+			idi_put_req(reqbuf, N_DISC_ACK, 1, chan->e.IndCh);
 			break;
 		default:
 			eicon_log(card, 1, "idi_req: Ch%d: Unknown request\n", chan->No);
@@ -492,7 +379,7 @@
 
 	if ((chan->fsm_state == EICON_STATE_ACTIVE) ||
 	    (chan->fsm_state == EICON_STATE_WMCONN)) {
-  		if (chan->e.B2Id) idi_do_req(card, chan, IDI_N_DISC, 1);
+  		if (chan->e.B2Id) idi_do_req(card, chan, N_DISC, 1);
 	}
 	if (chan->e.B2Id) idi_do_req(card, chan, REMOVE, 1);
 	if (chan->fsm_state != EICON_STATE_NULL) {
@@ -508,6 +395,32 @@
 }
 
 int
+capipmsg(eicon_card *card, eicon_chan *chan, capi_msg *cm)
+{
+	if ((cm->para[0] != 3) || (cm->para[1] != 0))
+		return -1;
+	if (cm->para[2] < 3)
+		return -1;
+	if (cm->para[4] != 0)
+		return -1;
+	switch(cm->para[3]) {
+		case 4: /* Suspend */
+			eicon_log(card, 8, "idi_req: Ch%d: Call Suspend\n", chan->No);
+			if (cm->para[5]) {
+				idi_do_req(card, chan, SUSPEND, 0);
+			} else {
+				idi_do_req(card, chan, CALL_HOLD, 0);
+			}
+			break;
+		case 5: /* Resume */
+			eicon_log(card, 8, "idi_req: Ch%d: Call Resume\n", chan->No);
+			idi_do_req(card, chan, RESUME, 0);
+			break;
+        }
+	return 0;
+}
+
+int
 idi_connect_res(eicon_card *card, eicon_chan *chan)
 {
 	if ((!card) || (!chan))
@@ -612,7 +525,14 @@
 			reqbuf->XBuffer.P[l++] = *sub++ & 0x7f;
 	}
 
-	if ((tmp = idi_si2bc(si1, si2, bc, hlc)) > 0) {
+	if (si2 > 2) {
+		reqbuf->XBuffer.P[l++] = SHIFT|6;
+		reqbuf->XBuffer.P[l++] = SIN;
+		reqbuf->XBuffer.P[l++] = 2;
+		reqbuf->XBuffer.P[l++] = si1;
+		reqbuf->XBuffer.P[l++] = si2;
+	}
+	else if ((tmp = idi_si2bc(si1, si2, bc, hlc)) > 0) {
 		reqbuf->XBuffer.P[l++] = BC;
 		reqbuf->XBuffer.P[l++] = tmp;
 		for(i=0; i<tmp;i++) 
@@ -632,7 +552,7 @@
 	reqbuf->XBuffer.P[l++] = 0;
 	reqbuf->XBuffer.P[l++] = 0;
 	reqbuf->XBuffer.P[l++] = 32;
-	reqbuf->XBuffer.P[l++] = 3;
+	reqbuf->XBuffer.P[l++] = 0;
         switch(chan->l2prot) {
 		case ISDN_PROTO_L2_X75I:
 		case ISDN_PROTO_L2_X75UI:
@@ -859,7 +779,7 @@
 				}
 				for(i=0; i < wlen; i++) 
 					message->llc[i] = buffer[pos++];
-				eicon_log(ccard, 4, "idi_inf: Ch%d: LLC=%d %d %d %d\n", chan->No, message->llc[0],
+				eicon_log(ccard, 4, "idi_inf: Ch%d: LLC=%d %d %d %d ...\n", chan->No, message->llc[0],
 					message->llc[1],message->llc[2],message->llc[3]);
 				break;
 			case HLC:
@@ -869,7 +789,7 @@
 				}
 				for(i=0; i < wlen; i++) 
 					message->hlc[i] = buffer[pos++];
-				eicon_log(ccard, 4, "idi_inf: Ch%d: HLC=%x %x %x %x %x\n", chan->No,
+				eicon_log(ccard, 4, "idi_inf: Ch%d: HLC=%x %x %x %x %x ...\n", chan->No,
 					message->hlc[0], message->hlc[1],
 					message->hlc[2], message->hlc[3], message->hlc[4]);
 				break;
@@ -1061,31 +981,55 @@
 }
 
 void
-idi_bc2si(unsigned char *bc, unsigned char *hlc, unsigned char *si1, unsigned char *si2)
+idi_bc2si(unsigned char *bc, unsigned char *hlc, unsigned char *sin, unsigned char *si1, unsigned char *si2)
 {
-  si1[0] = 0;
-  si2[0] = 0;
-  if (memcmp(bc, BC_Speech, 3) == 0) {		/* Speech */
-	si1[0] = 1;
+	si1[0] = 0;
+	si2[0] = 0;
+
+	switch (bc[0] & 0x7f) {
+		case 0x00: /* Speech */
+			si1[0] = 1;
 #ifdef EICON_FULL_SERVICE_OKTETT
-	si2[0] = 1;
+			si1[0] = sin[0];
+			si2[0] = sin[1];
 #endif
-  }
-  if (memcmp(bc, BC_31khz, 3) == 0) {		/* 3.1kHz audio */
-	si1[0] = 1;
+			break;
+		case 0x10: /* 3.1 Khz audio */
+			si1[0] = 1;
 #ifdef EICON_FULL_SERVICE_OKTETT
-	si2[0] = 2;
-  	if (memcmp(hlc, HLC_faxg3, 2) == 0) {	/* Fax Gr.2/3 */
-		si1[0] = 2;
-	}
+			si1[0] = sin[0];
+			si2[0] = sin[1];
 #endif
-  }
-  if (memcmp(bc, BC_64k, 2) == 0) {		/* unrestricted 64 kbits */
-	si1[0] = 7;
-  }
-  if (memcmp(bc, BC_video, 3) == 0) {		/* video */
-	si1[0] = 4;
-  }
+			break;
+		case 0x08: /* Unrestricted digital information */
+			si1[0] = 7;
+			si2[0] = sin[1];
+			break;
+		case 0x09: /* Restricted digital information */
+			si1[0] = 2;
+			break;
+		case 0x11:
+			/* Unrestr. digital information  with
+			 * tones/announcements ( or 7 kHz audio
+			 */
+			si1[0] = 3;
+			break;
+		case 0x18: /* Video */
+			si1[0] = 4;
+			break;
+	}
+	switch (bc[1] & 0x7f) {
+		case 0x40: /* packed mode */
+			si1[0] = 8;
+			break;
+		case 0x10: /* 64 kbit */
+		case 0x11: /* 2*64 kbit */
+		case 0x13: /* 384 kbit */
+		case 0x15: /* 1536 kbit */
+		case 0x17: /* 1920 kbit */
+			/* moderate = bc[1] & 0x7f; */
+			break;
+	}
 }
 
 /********************* FAX stuff ***************************/
@@ -1225,7 +1169,7 @@
 
 	reqbuf = (eicon_REQ *)skb_put(skb, sizeof(eicon_t30_s) + sizeof(eicon_REQ));
 
-	reqbuf->Req = IDI_N_EDATA;
+	reqbuf->Req = N_EDATA;
 	reqbuf->ReqCh = chan->e.IndCh;
 	reqbuf->ReqId = 1;
 
@@ -1359,7 +1303,7 @@
 			eicon_log(card, 128, "sSFF-Head: pagelength = %d\n", page->pagelength);
 			break;
 	}
-	idi_send_data(card, chan, 0, skb, 0);
+	idi_send_data(card, chan, 0, skb, 0, 0);
 }
 
 void
@@ -1913,7 +1857,7 @@
 	OutBuf->Len = 0;
 	OutBuf->Next = OutBuf->Data;
 
-	return(idi_send_data(ccard, chan, 0, skb, 1));
+	return(idi_send_data(ccard, chan, 0, skb, 1, 0));
 }
 
 int
@@ -1958,6 +1902,8 @@
 
         if (chan->queued + skb->len > 1200)
                 return 0;
+	if (chan->pqueued > 1)
+		return 0;
 
 	InBuf.Data = skb->data;
 	InBuf.Size = skb->len;
@@ -2183,6 +2129,7 @@
 	}
 	if ((chan->fax->code > 1) && (chan->fax->code < 120))
 		chan->fax->code += 120;
+	eicon_log(ccard, 8, "idi_fax: Ch%d: Hangup (code=%d)\n", chan->No, chan->fax->code);
 	chan->fax->r_code = ISDN_TTY_FAX_HNG;
 	cmd.driver = ccard->myid;
 	cmd.command = ISDN_STAT_FAXIND;
@@ -2224,7 +2171,7 @@
 
 	reqbuf = (eicon_REQ *)skb_put(skb, 1 + len + sizeof(eicon_REQ));
 
-	reqbuf->Req = IDI_N_UDATA;
+	reqbuf->Req = N_UDATA;
 	reqbuf->ReqCh = chan->e.IndCh;
 	reqbuf->ReqId = 1;
 
@@ -2418,12 +2365,12 @@
 		                while((skb2 = skb_dequeue(&chan->e.X))) {
 					dev_kfree_skb(skb2);
 				}
-				save_flags(flags);
-				cli();
+				spin_lock_irqsave(&eicon_lock, flags);
 				chan->queued = 0;
+				chan->pqueued = 0;
 				chan->waitq = 0;
 				chan->waitpq = 0;
-				restore_flags(flags);
+				spin_unlock_irqrestore(&eicon_lock, flags);
 				if (message.e_cau[0] & 0x7f) {
 					cmd.driver = ccard->myid;
 					cmd.arg = chan->No;
@@ -2433,10 +2380,6 @@
 					ccard->interface.statcallb(&cmd);
 				}
 				chan->cause[0] = 0; 
-#ifdef CONFIG_ISDN_TTY_FAX
-				if (!chan->e.B2Id)
-					chan->fax = 0;
-#endif
 				if (((chan->fsm_state == EICON_STATE_ACTIVE) ||
 				    (chan->fsm_state == EICON_STATE_WMCONN)) ||
 				    ((chan->l2prot == ISDN_PROTO_L2_FAX) &&
@@ -2446,6 +2389,7 @@
 					if (chan->e.B2Id)
 						idi_do_req(ccard, chan, REMOVE, 1);
 					chan->statectrl &= ~WAITING_FOR_HANGUP;
+					chan->statectrl &= ~IN_HOLD;
 					if (chan->statectrl & HAVE_CONN_REQ) {
 						eicon_log(ccard, 32, "idi_req: Ch%d: queueing delayed conn_req\n", chan->No);
 						chan->statectrl &= ~HAVE_CONN_REQ;
@@ -2463,6 +2407,9 @@
 						cmd.command = ISDN_STAT_DHUP;
 						ccard->interface.statcallb(&cmd);
 						eicon_idi_listen_req(ccard, chan);
+#ifdef CONFIG_ISDN_TTY_FAX
+						chan->fax = 0;
+#endif
 					}
 				}
 				break;
@@ -2475,7 +2422,7 @@
 					break;
 				}
 				chan->fsm_state = EICON_STATE_ICALL;
-				idi_bc2si(message.bc, message.hlc, &chan->si1, &chan->si2);
+				idi_bc2si(message.bc, message.hlc, message.sin, &chan->si1, &chan->si2);
 				strcpy(chan->cpn, message.cpn + 1);
 				strcpy(chan->oad, message.oad);
 				strcpy(chan->dsa, message.dsa);
@@ -2553,12 +2500,15 @@
 						case ISDN_PROTO_L2_MODEM:
 							/* do nothing, wait for connect */
 							break;
+						case ISDN_PROTO_L2_V11096:
+						case ISDN_PROTO_L2_V11019:
+						case ISDN_PROTO_L2_V11038:
 						case ISDN_PROTO_L2_TRANS:
-							idi_do_req(ccard, chan, IDI_N_CONNECT, 1);
+							idi_do_req(ccard, chan, N_CONNECT, 1);
 							break;
-						default:
+						default:;
 							/* On most incoming calls we use automatic connect */
-							/* idi_do_req(ccard, chan, IDI_N_CONNECT, 1); */
+							/* idi_do_req(ccard, chan, N_CONNECT, 1); */
 					}
 				} else {
 					if (chan->fsm_state != EICON_STATE_ACTIVE)
@@ -2568,33 +2518,50 @@
 			case CALL_CON:
 				eicon_log(ccard, 8, "idi_ind: Ch%d: Call_Con\n", chan->No);
 				if (chan->fsm_state == EICON_STATE_OCALL) {
-					chan->fsm_state = EICON_STATE_OBWAIT;
-					cmd.driver = ccard->myid;
-					cmd.command = ISDN_STAT_DCONN;
-					cmd.arg = chan->No;
-					ccard->interface.statcallb(&cmd);
-
 					/* check if old NetID has been removed */
 					if (chan->e.B2Id) {
 						eicon_log(ccard, 1, "eicon: Ch%d: old net_id %x still exist, removing.\n",
 							chan->No, chan->e.B2Id);
 						idi_do_req(ccard, chan, REMOVE, 1);
 					}
-
-					idi_do_req(ccard, chan, ASSIGN, 1); 
-					idi_do_req(ccard, chan, IDI_N_CONNECT, 1);
 #ifdef CONFIG_ISDN_TTY_FAX
 					if (chan->l2prot == ISDN_PROTO_L2_FAX) {
-						if (chan->fax)
+						if (chan->fax) {
 							chan->fax->phase = ISDN_FAX_PHASE_A;
+						} else {
+							eicon_log(ccard, 1, "idi_ind: Call_Con with NULL fax struct, ERROR\n");
+							idi_hangup(ccard, chan);
+							break;
+						}
 					}
 #endif
+					chan->fsm_state = EICON_STATE_OBWAIT;
+					cmd.driver = ccard->myid;
+					cmd.command = ISDN_STAT_DCONN;
+					cmd.arg = chan->No;
+					ccard->interface.statcallb(&cmd);
+
+					idi_do_req(ccard, chan, ASSIGN, 1); 
+					idi_do_req(ccard, chan, N_CONNECT, 1);
 				} else
-				idi_hangup(ccard, chan);
+					idi_hangup(ccard, chan);
 				break;
 			case AOC_IND:
 				eicon_log(ccard, 8, "idi_ind: Ch%d: Advice of Charge\n", chan->No);
 				break;
+			case CALL_HOLD_ACK:
+				chan->statectrl |= IN_HOLD;
+				eicon_log(ccard, 8, "idi_ind: Ch%d: Call Hold Ack\n", chan->No);
+				break;
+			case SUSPEND_REJ:
+				eicon_log(ccard, 8, "idi_ind: Ch%d: Suspend Rejected\n", chan->No);
+				break;
+			case SUSPEND:
+				eicon_log(ccard, 8, "idi_ind: Ch%d: Suspend Ack\n", chan->No);
+				break;
+			case RESUME:
+				eicon_log(ccard, 8, "idi_ind: Ch%d: Resume Ack\n", chan->No);
+				break;
 			default:
 				eicon_log(ccard, 8, "idi_ind: Ch%d: UNHANDLED SigIndication 0x%02x\n", chan->No, ind->Ind);
 		}
@@ -2613,7 +2580,7 @@
 		} 
 		else
 		switch(ind->Ind) {
-			case IDI_N_CONNECT_ACK:
+			case N_CONNECT_ACK:
 				eicon_log(ccard, 16, "idi_ind: Ch%d: N_Connect_Ack\n", chan->No);
 				if (chan->l2prot == ISDN_PROTO_L2_MODEM) {
 					chan->fsm_state = EICON_STATE_WMCONN;
@@ -2634,7 +2601,7 @@
 						}
 					}
 					else {
-						eicon_log(ccard, 1, "idi_ind: N_CONNECT_ACK with NULL fax struct, ERROR\n");
+						eicon_log(ccard, 1, "idi_ind: N_Connect_Ack with NULL fax struct, ERROR\n");
 					}
 #endif
 					break;
@@ -2646,10 +2613,10 @@
 				strcpy(cmd.parm.num, "64000");
 				ccard->interface.statcallb(&cmd);
 				break; 
-			case IDI_N_CONNECT:
+			case N_CONNECT:
 				eicon_log(ccard, 16,"idi_ind: Ch%d: N_Connect\n", chan->No);
 				chan->e.IndCh = ind->IndCh;
-				if (chan->e.B2Id) idi_do_req(ccard, chan, IDI_N_CONNECT_ACK, 1);
+				if (chan->e.B2Id) idi_do_req(ccard, chan, N_CONNECT_ACK, 1);
 				if (chan->l2prot == ISDN_PROTO_L2_FAX) {
 					break;
 				}
@@ -2664,43 +2631,47 @@
 				strcpy(cmd.parm.num, "64000");
 				ccard->interface.statcallb(&cmd);
 				break; 
-			case IDI_N_DISC:
-				eicon_log(ccard, 16, "idi_ind: Ch%d: N_DISC\n", chan->No);
+			case N_DISC:
+				eicon_log(ccard, 16, "idi_ind: Ch%d: N_Disc\n", chan->No);
 				if (chan->e.B2Id) {
 		                	while((skb2 = skb_dequeue(&chan->e.X))) {
 						dev_kfree_skb(skb2);
 					}
-					idi_do_req(ccard, chan, IDI_N_DISC_ACK, 1);
+					idi_do_req(ccard, chan, N_DISC_ACK, 1);
 					idi_do_req(ccard, chan, REMOVE, 1);
 				}
 #ifdef CONFIG_ISDN_TTY_FAX
-				if (chan->l2prot == ISDN_PROTO_L2_FAX) {
+				if ((chan->l2prot == ISDN_PROTO_L2_FAX) && (chan->fax)){
 					idi_parse_edata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
 					idi_fax_hangup(ccard, chan);
 				}
 #endif
 				chan->e.IndCh = 0;
-				save_flags(flags);
-				cli();
+				spin_lock_irqsave(&eicon_lock, flags);
 				chan->queued = 0;
+				chan->pqueued = 0;
 				chan->waitq = 0;
 				chan->waitpq = 0;
-				restore_flags(flags);
-				idi_do_req(ccard, chan, HANGUP, 0);
+				spin_unlock_irqrestore(&eicon_lock, flags);
+				if (!(chan->statectrl & IN_HOLD)) {
+					idi_do_req(ccard, chan, HANGUP, 0);
+				}
 				if (chan->fsm_state == EICON_STATE_ACTIVE) {
 					cmd.driver = ccard->myid;
 					cmd.command = ISDN_STAT_BHUP;
 					cmd.arg = chan->No;
 					ccard->interface.statcallb(&cmd);
 					chan->fsm_state = EICON_STATE_NULL;
-					chan->statectrl |= WAITING_FOR_HANGUP;
+					if (!(chan->statectrl & IN_HOLD)) {
+						chan->statectrl |= WAITING_FOR_HANGUP;
+					}
 				}
 #ifdef CONFIG_ISDN_TTY_FAX
 				chan->fax = 0;
 #endif
 				break; 
-			case IDI_N_DISC_ACK:
-				eicon_log(ccard, 16, "idi_ind: Ch%d: N_DISC_ACK\n", chan->No);
+			case N_DISC_ACK:
+				eicon_log(ccard, 16, "idi_ind: Ch%d: N_Disc_Ack\n", chan->No);
 #ifdef CONFIG_ISDN_TTY_FAX
 				if (chan->l2prot == ISDN_PROTO_L2_FAX) {
 					idi_parse_edata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
@@ -2708,10 +2679,10 @@
 				}
 #endif
 				break; 
-			case IDI_N_DATA_ACK:
-				eicon_log(ccard, 128, "idi_ind: Ch%d: N_DATA_ACK\n", chan->No);
+			case N_DATA_ACK:
+				eicon_log(ccard, 128, "idi_ind: Ch%d: N_Data_Ack\n", chan->No);
 				break;
-			case IDI_N_DATA:
+			case N_DATA:
 				skb_pull(skb, sizeof(eicon_IND) - 1);
 				eicon_log(ccard, 128, "idi_rcv: Ch%d: %d bytes\n", chan->No, skb->len);
 				if (chan->l2prot == ISDN_PROTO_L2_FAX) {
@@ -2723,11 +2694,11 @@
 					free_buff = 0; 
 				}
 				break; 
-			case IDI_N_UDATA:
+			case N_UDATA:
 				idi_parse_udata(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
 				break; 
 #ifdef CONFIG_ISDN_TTY_FAX
-			case IDI_N_EDATA:
+			case N_EDATA:
 				idi_edata_action(ccard, chan, ind->RBuffer.P, ind->RBuffer.length);
 				break; 
 #endif
@@ -2747,6 +2718,8 @@
 {
 	ulong flags;
 	isdn_ctrl cmd;
+	int tqueued = 0;
+	int twaitpq = 0;
 
 	if (ack->RcId != ((chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id)) {
 		/* I dont know why this happens, should not ! */
@@ -2770,16 +2743,15 @@
 			eicon_log(ccard, 16, "idi_ack: Ch%d: Rc-Ref %d not equal to stored %d\n", chan->No,
 				ack->Reference, chan->e.ref);
 		}
-		save_flags(flags);
-		cli();
+		spin_lock_irqsave(&eicon_lock, flags);
 		ccard->IdTable[ack->RcId] = NULL;
-		eicon_log(ccard, 16, "idi_ack: Ch%d: Removed : Id=%x Ch=%d (%s)\n", chan->No,
-			ack->RcId, ack->RcCh, (chan->e.ReqCh)? "Net":"Sig");
 		if (!chan->e.ReqCh) 
 			chan->e.D3Id = 0;
 		else
 			chan->e.B2Id = 0;
-		restore_flags(flags);
+		spin_unlock_irqrestore(&eicon_lock, flags);
+		eicon_log(ccard, 16, "idi_ack: Ch%d: Removed : Id=%x Ch=%d (%s)\n", chan->No,
+			ack->RcId, ack->RcCh, (chan->e.ReqCh)? "Net":"Sig");
 		return 1;
 	}
 
@@ -2790,25 +2762,21 @@
 	} else {
 	/* Network layer */
 		switch(chan->e.Req & 0x0f) {
-			case IDI_N_CONNECT:
+			case N_CONNECT:
 				chan->e.IndCh = ack->RcCh;
 				eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No,
 					ack->RcId, ack->RcCh, ack->Reference);
 				break;
-			case IDI_N_MDATA:
-			case IDI_N_DATA:
-				if ((chan->e.Req & 0x0f) == IDI_N_DATA) {
-					if (chan->queued) {
-						cmd.driver = ccard->myid;
-						cmd.command = ISDN_STAT_BSENT;
-						cmd.arg = chan->No;
-						cmd.parm.length = chan->waitpq;
-						ccard->interface.statcallb(&cmd);
-					}
-					save_flags(flags);
-					cli();
+			case N_MDATA:
+			case N_DATA:
+				tqueued = chan->queued;
+				twaitpq = chan->waitpq;
+				if ((chan->e.Req & 0x0f) == N_DATA) {
+					spin_lock_irqsave(&eicon_lock, flags);
 					chan->waitpq = 0;
-					restore_flags(flags);
+					if(chan->pqueued)
+						chan->pqueued--;
+					spin_unlock_irqrestore(&eicon_lock, flags);
 #ifdef CONFIG_ISDN_TTY_FAX
 					if (chan->l2prot == ISDN_PROTO_L2_FAX) {
 						if (((chan->queued - chan->waitq) < 1) &&
@@ -2828,11 +2796,17 @@
 					}
 #endif
 				}
-				save_flags(flags);
-				cli();
+				spin_lock_irqsave(&eicon_lock, flags);
 				chan->queued -= chan->waitq;
 				if (chan->queued < 0) chan->queued = 0;
-				restore_flags(flags);
+				spin_unlock_irqrestore(&eicon_lock, flags);
+				if (((chan->e.Req & 0x0f) == N_DATA) && (tqueued)) {
+					cmd.driver = ccard->myid;
+					cmd.command = ISDN_STAT_BSENT;
+					cmd.arg = chan->No;
+					cmd.parm.length = twaitpq;
+					ccard->interface.statcallb(&cmd);
+				}
 				break;
 			default:
 				eicon_log(ccard, 16, "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No,
@@ -2858,11 +2832,10 @@
 		return;
 	}
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&eicon_lock, flags);
 	if ((chan = ccard->IdTable[ack->RcId]) != NULL)
 		dCh = chan->No;
-	restore_flags(flags);
+	spin_unlock_irqrestore(&eicon_lock, flags);
 
 	switch (ack->Rc) {
 		case OK_FC:
@@ -2890,8 +2863,7 @@
 				eicon_log(ccard, 1, "idi_ack: Ch%d: ASSIGN-OK on chan already assigned (%x,%x)\n",
 					chan->No, chan->e.D3Id, chan->e.B2Id);
 			}
-			save_flags(flags);
-			cli();
+			spin_lock_irqsave(&eicon_lock, flags);
 			for(j = 0; j < ccard->nchannels + 1; j++) {
 				if ((ccard->bch[j].e.ref == ack->Reference) &&
 					(ccard->bch[j].e.Req == ASSIGN)) {
@@ -2901,12 +2873,12 @@
 						ccard->bch[j].e.B2Id  = ack->RcId;
 					ccard->IdTable[ack->RcId] = &ccard->bch[j];
 					chan = &ccard->bch[j];
-					eicon_log(ccard, 16, "idi_ack: Ch%d: Id %x assigned (%s)\n", j, 
-						ack->RcId, (ccard->bch[j].e.ReqCh)? "Net":"Sig");
 					break;
 				}
-			}		
-			restore_flags(flags);
+			}
+			spin_unlock_irqrestore(&eicon_lock, flags);
+			eicon_log(ccard, 16, "idi_ack: Ch%d: Id %x assigned (%s)\n", j, 
+				ack->RcId, (ccard->bch[j].e.ReqCh)? "Net":"Sig");
 			if (j > ccard->nchannels) {
 				eicon_log(ccard, 24, "idi_ack: Ch??: ref %d not found for Id %d\n", 
 					ack->Reference, ack->RcId);
@@ -2917,6 +2889,7 @@
 		case UNKNOWN_COMMAND:
 		case WRONG_COMMAND:
 		case WRONG_ID:
+		case ADAPTER_DEAD:
 		case WRONG_CH:
 		case UNKNOWN_IE:
 		case WRONG_IE:
@@ -2949,19 +2922,18 @@
 				ccard->interface.statcallb(&cmd);
 			}
 	}
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&eicon_lock, flags);
 	if (chan) {
 		chan->e.ref = 0;
 		chan->e.busy = 0;
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&eicon_lock, flags);
 	dev_kfree_skb(skb);
 	eicon_schedule_tx(ccard);
 }
 
 int
-idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que)
+idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que, int chk)
 {
         struct sk_buff *xmit_skb;
         struct sk_buff *skb2;
@@ -2985,13 +2957,14 @@
 		return -1;
         if (!len)
                 return 0;
-	if (chan->queued + len > EICON_MAX_QUEUE)
+
+	if ((chk) && (chan->pqueued > 1))
 		return 0;
 
-	eicon_log(card, 128, "idi_snd: Ch%d: %d bytes\n", chan->No, len);
+	eicon_log(card, 128, "idi_snd: Ch%d: %d bytes (Pqueue=%d)\n",
+		chan->No, len, chan->pqueued);
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&eicon_lock, flags);
 	while(offset < len) {
 
 		plen = ((len - offset) > 270) ? 270 : len - offset;
@@ -3000,7 +2973,7 @@
         	skb2 = alloc_skb(sizeof(eicon_chan_ptr), GFP_ATOMIC);
 
 	        if ((!xmit_skb) || (!skb2)) {
-			restore_flags(flags);
+			spin_unlock_irqrestore(&eicon_lock, flags);
         	        eicon_log(card, 1, "idi_err: Ch%d: alloc_skb failed in send_data()\n", chan->No);
 			if (xmit_skb) 
 				dev_kfree_skb(skb);
@@ -3013,13 +2986,10 @@
         	chan2->ptr = chan;
 
 	        reqbuf = (eicon_REQ *)skb_put(xmit_skb, plen + sizeof(eicon_REQ));
-		if (((len - offset) > 270) &&
-			(chan->l2prot != ISDN_PROTO_L2_MODEM) &&
-			(chan->l2prot != ISDN_PROTO_L2_FAX) &&
-			(chan->l2prot != ISDN_PROTO_L2_TRANS)) {
-		        reqbuf->Req = IDI_N_MDATA;
+		if ((len - offset) > 270) { 
+		        reqbuf->Req = N_MDATA;
 		} else {
-		        reqbuf->Req = IDI_N_DATA;
+		        reqbuf->Req = N_DATA;
 			/* if (ack) reqbuf->Req |= N_D_BIT; */
 		}	
         	reqbuf->ReqCh = chan->e.IndCh;
@@ -3033,9 +3003,11 @@
 
 		offset += plen;
 	}
-	if (que)
+	if (que) {
 		chan->queued += len;
-	restore_flags(flags);
+		chan->pqueued++;
+	}
+	spin_unlock_irqrestore(&eicon_lock, flags);
 	eicon_schedule_tx(card);
         dev_kfree_skb(skb);
         return len;
@@ -3073,7 +3045,7 @@
         reqbuf->XBuffer.P[0] = 0;
         reqbuf->Req = ASSIGN;
         reqbuf->ReqCh = 0;
-        reqbuf->ReqId = 0xe0;
+        reqbuf->ReqId = MAN_ID;
         reqbuf->XBuffer.length = 1;
         reqbuf->Reference = 2; /* Man Entity */
 
@@ -3199,7 +3171,7 @@
         reqbuf->XBuffer.P[1] = manbuf->length[0] + 1;
 
         reqbuf->XBuffer.P[l++] = 0;
-        reqbuf->Req = (manbuf->count) ? manbuf->count : 0x02; /* Request */
+        reqbuf->Req = (manbuf->count) ? manbuf->count : MAN_READ;
         reqbuf->ReqCh = 0;
         reqbuf->ReqId = 1;
         reqbuf->XBuffer.length = l;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/eicon_idi.h linux.19p18/drivers/isdn/eicon/eicon_idi.h
--- linux.vanilla/drivers/isdn/eicon/eicon_idi.h	Fri Apr 21 23:23:24 2000
+++ linux.19p18/drivers/isdn/eicon/eicon_idi.h	Tue Feb 20 13:44:53 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon_idi.h,v 1.9 2000/01/23 21:21:23 armin Exp $
+/* $Id: eicon_idi.h,v 1.11 2000/05/07 08:51:04 armin Exp $
  *
  * ISDN lowlevel-module for the Eicon active cards.
  * IDI-Interface
@@ -20,168 +20,30 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
- * $Log: eicon_idi.h,v $
- * Revision 1.9  2000/01/23 21:21:23  armin
- * Added new trace capability and some updates.
- * DIVA Server BRI now supports data for ISDNLOG.
- *
- * Revision 1.8  1999/11/25 11:43:27  armin
- * Fixed statectrl and connect message.
- * X.75 fix and HDLC/transparent with autoconnect.
- * Minor cleanup.
- *
- * Revision 1.7  1999/08/22 20:26:46  calle
- * backported changes from kernel 2.3.14:
- * - several #include "config.h" gone, others come.
- * - "struct device" changed to "struct net_device" in 2.3.14, added a
- *   define in isdn_compat.h for older kernel versions.
- *
- * Revision 1.6  1999/07/25 15:12:04  armin
- * fix of some debug logs.
- * enabled ISA-cards option.
- *
- * Revision 1.5  1999/07/11 17:16:26  armin
- * Bugfixes in queue handling.
- * Added DSP-DTMF decoder functions.
- * Reorganized ack_handler.
- *
- * Revision 1.4  1999/03/29 11:19:44  armin
- * I/O stuff now in seperate file (eicon_io.c)
- * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
- *
- * Revision 1.3  1999/03/02 12:37:45  armin
- * Added some important checks.
- * Analog Modem with DSP.
- * Channels will be added to Link-Level after loading firmware.
- *
- * Revision 1.2  1999/01/24 20:14:18  armin
- * Changed and added debug stuff.
- * Better data sending. (still problems with tty's flip buffer)
- *
- * Revision 1.1  1999/01/01 18:09:42  armin
- * First checkin of new eicon driver.
- * DIVA-Server BRI/PCI and PRI/PCI are supported.
- * Old diehl code is obsolete.
- *
  *
  */
 
-#ifndef IDI_H
-#define IDI_H
+#ifndef E_IDI_H
+#define E_IDI_H
 
 #include <linux/config.h>
 
-#define ASSIGN  0x01
-#define REMOVE  0xff
-	
-#define CALL_REQ 1      /* call request                             */
-#define CALL_CON 1      /* call confirmation                        */
-#define CALL_IND 2      /* incoming call connected                  */
-#define LISTEN_REQ 2    /* listen request                           */
-#define HANGUP 3        /* hangup request/indication                */
-#define SUSPEND 4       /* call suspend request/confirm             */
-#define RESUME 5        /* call resume request/confirm              */
-#define SUSPEND_REJ 6   /* suspend rejected indication              */
-#define USER_DATA 8     /* user data for user to user signaling     */
-#define CONGESTION 9    /* network congestion indication            */
-#define INDICATE_REQ 10 /* request to indicate an incoming call     */
-#define INDICATE_IND 10 /* indicates that there is an incoming call */
-#define CALL_RES 11     /* accept an incoming call                  */
-#define CALL_ALERT 12   /* send ALERT for incoming call             */
-#define INFO_REQ 13     /* INFO request                             */
-#define INFO_IND 13     /* INFO indication                          */
-#define REJECT 14       /* reject an incoming call                  */
-#define RESOURCES 15    /* reserve B-Channel hardware resources     */
-#define TEL_CTRL 16     /* Telephone control request/indication     */
-#define STATUS_REQ 17   /* Request D-State (returned in INFO_IND)   */
-#define FAC_REG_REQ 18  /* connection idependent fac registration   */
-#define FAC_REG_ACK 19  /* fac registration acknowledge             */
-#define FAC_REG_REJ 20  /* fac registration reject                  */
-#define CALL_COMPLETE 21/* send a CALL_PROC for incoming call       */
-#define AOC_IND       26/* Advice of Charge                         */
-
-#define IDI_N_MDATA         (0x01)
-#define IDI_N_CONNECT       (0x02)
-#define IDI_N_CONNECT_ACK   (0x03)
-#define IDI_N_DISC          (0x04)
-#define IDI_N_DISC_ACK      (0x05)
-#define IDI_N_RESET         (0x06)
-#define IDI_N_RESET_ACK     (0x07)
-#define IDI_N_DATA          (0x08)
-#define IDI_N_EDATA         (0x09)
-#define IDI_N_UDATA         (0x0a)
-#define IDI_N_BDATA         (0x0b)
-#define IDI_N_DATA_ACK      (0x0c)
-#define IDI_N_EDATA_ACK     (0x0d)
-
-#define N_Q_BIT         0x10    /* Q-bit for req/ind                */
-#define N_M_BIT         0x20    /* M-bit for req/ind                */
-#define N_D_BIT         0x40    /* D-bit for req/ind                */
-
-
-#define SHIFT 0x90              /* codeset shift                    */
-#define MORE 0xa0               /* more data                        */
-#define CL 0xb0                 /* congestion level                 */
-
-        /* codeset 0                                                */
-
-#define BC  0x04                /* Bearer Capability                */
-#define CAU 0x08                /* cause                            */
-#define CAD 0x0c                /* Connected address                */
-#define CAI 0x10                /* call identity                    */
-#define CHI 0x18                /* channel identification           */
-#define LLI 0x19                /* logical link id                  */
-#define CHA 0x1a                /* charge advice                    */
-#define FTY 0x1c
-#define PI  0x1e		/* Progress Indicator		    */
-#define NI  0x27		/* Notification Indicator	    */
-#define DT  0x29                /* ETSI date/time                   */
-#define KEY 0x2c                /* keypad information element       */
-#define DSP 0x28                /* display                          */
-#define OAD 0x6c                /* origination address              */
-#define OSA 0x6d                /* origination sub-address          */
-#define CPN 0x70                /* called party number              */
-#define DSA 0x71                /* destination sub-address          */
-#define RDN 0x74		/* redirecting number		    */
-#define LLC 0x7c                /* low layer compatibility          */
-#define HLC 0x7d                /* high layer compatibility         */
-#define UUI 0x7e                /* user user information            */
-#define ESC 0x7f                /* escape extension                 */
-
-#define DLC 0x20                /* data link layer configuration    */
-#define NLC 0x21                /* network layer configuration      */
-
-        /* codeset 6                                                */
-
-#define SIN 0x01                /* service indicator                */
-#define CIF 0x02                /* charging information             */
-#define DATE 0x03               /* date                             */
-#define CPS 0x07                /* called party status              */
-
-/*------------------------------------------------------------------*/
-/* return code coding                                               */
-/*------------------------------------------------------------------*/
-
-#define UNKNOWN_COMMAND         0x01    /* unknown command          */
-#define WRONG_COMMAND           0x02    /* wrong command            */
-#define WRONG_ID                0x03    /* unknown task/entity id   */
-#define WRONG_CH                0x04    /* wrong task/entity id     */
-#define UNKNOWN_IE              0x05    /* unknown information el.  */
-#define WRONG_IE                0x06    /* wrong information el.    */
-#define OUT_OF_RESOURCES        0x07    /* card out of res.         */
-#define N_FLOW_CONTROL          0x10    /* Flow-Control, retry      */
-#define ASSIGN_RC               0xe0    /* ASSIGN acknowledgement   */
-#define ASSIGN_OK               0xef    /* ASSIGN OK                */
-#define OK_FC                   0xfc    /* Flow-Control RC          */
-#define READY_INT               0xfd    /* Ready interrupt          */
-#define TIMER_INT               0xfe    /* timer interrupt          */
-#define OK                      0xff    /* command accepted         */
+#undef N_DATA
+#undef ID_MASK
+
+#include "pc.h"
 
-/*------------------------------------------------------------------*/
+#define AOC_IND  26		/* Advice of Charge                         */
+#define PI  0x1e                /* Progress Indicator               */
+#define NI  0x27                /* Notification Indicator           */
+
+#define CALL_HOLD	0x22
+#define CALL_HOLD_ACK	0x24
 
 /* defines for statectrl */
 #define WAITING_FOR_HANGUP	0x01
 #define HAVE_CONN_REQ		0x02
+#define IN_HOLD			0x04
 
 typedef struct {
 	char cpn[32];
@@ -242,26 +104,6 @@
 } eicon_IND;
 
 typedef struct {
-  __u16 NextReq  __attribute__ ((packed));  /* pointer to next Req Buffer */
-  __u16 NextRc   __attribute__ ((packed));  /* pointer to next Rc Buffer  */
-  __u16 NextInd  __attribute__ ((packed));  /* pointer to next Ind Buffer */
-  __u8 ReqInput  __attribute__ ((packed));  /* number of Req Buffers sent */
-  __u8 ReqOutput  __attribute__ ((packed)); /* number of Req Buffers returned */
-  __u8 ReqReserved  __attribute__ ((packed));/*number of Req Buffers reserved */
-  __u8 Int  __attribute__ ((packed));       /* ISDN-P interrupt           */
-  __u8 XLock  __attribute__ ((packed));     /* Lock field for arbitration */
-  __u8 RcOutput  __attribute__ ((packed));  /* number of Rc buffers received */
-  __u8 IndOutput  __attribute__ ((packed)); /* number of Ind buffers received */
-  __u8 IMask  __attribute__ ((packed));     /* Interrupt Mask Flag        */
-  __u8 Reserved1[2]  __attribute__ ((packed)); /* reserved field, do not use */
-  __u8 ReadyInt  __attribute__ ((packed));  /* request field for ready int */
-  __u8 Reserved2[12]  __attribute__ ((packed)); /* reserved field, do not use */
-  __u8 InterfaceType  __attribute__ ((packed)); /* interface type 1=16K    */
-  __u16 Signature  __attribute__ ((packed));    /* ISDN-P initialized ind  */
-  __u8 B[1];                            /* buffer space for Req,Ind and Rc */
-} eicon_pr_ram;
-
-typedef struct {
 	__u8		*Data;
 	unsigned int	Size;
 	unsigned int	Len;
@@ -278,8 +120,9 @@
 extern void idi_handle_ack(eicon_card *card, struct sk_buff *skb);
 extern void idi_handle_ind(eicon_card *card, struct sk_buff *skb);
 extern int eicon_idi_manage(eicon_card *card, eicon_manifbuf *mb);
-extern int idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que);
+extern int idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, int que, int chk);
 extern void idi_audio_cmd(eicon_card *ccard, eicon_chan *chan, int cmd, u_char *value);
+extern int capipmsg(eicon_card *card, eicon_chan *chan, capi_msg *cm);
 #ifdef CONFIG_ISDN_TTY_FAX
 extern void idi_fax_cmd(eicon_card *card, eicon_chan *chan);
 extern int idi_faxdata_send(eicon_card *ccard, eicon_chan *chan, struct sk_buff *skb);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/eicon_io.c linux.19p18/drivers/isdn/eicon/eicon_io.c
--- linux.vanilla/drivers/isdn/eicon/eicon_io.c	Fri Apr 21 12:46:08 2000
+++ linux.19p18/drivers/isdn/eicon/eicon_io.c	Mon Feb 19 18:28:19 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon_io.c,v 1.10 2000/01/23 21:21:23 armin Exp $
+/* $Id: eicon_io.c,v 1.13.6.1 2001/02/16 09:09:50 armin Exp $
  *
  * ISDN low-level module for Eicon active ISDN-Cards.
  * Code for communicating with hardware.
@@ -6,7 +6,7 @@
  * Copyright 1999,2000  by Armin Schindler (mac@melware.de)
  * Copyright 1999,2000  Cytronics & Melware (info@melware.de)
  *
- * Thanks to	Eicon Technology GmbH & Co. oHG for 
+ * Thanks to	Eicon Networks for 
  *		documents, informations and hardware. 
  *
  * This program is free software; you can redistribute it and/or modify
@@ -23,52 +23,12 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
- * $Log: eicon_io.c,v $
- * Revision 1.10  2000/01/23 21:21:23  armin
- * Added new trace capability and some updates.
- * DIVA Server BRI now supports data for ISDNLOG.
- *
- * Revision 1.9  1999/11/18 20:55:25  armin
- * Ready_Int fix of ISA cards.
- *
- * Revision 1.8  1999/10/08 22:09:34  armin
- * Some fixes of cards interface handling.
- * Bugfix of NULL pointer occurence.
- * Changed a few log outputs.
- *
- * Revision 1.7  1999/09/26 14:17:53  armin
- * Improved debug and log via readstat()
- *
- * Revision 1.6  1999/09/21 20:35:43  armin
- * added more error checking.
- *
- * Revision 1.5  1999/08/31 11:20:11  paul
- * various spelling corrections (new checksums may be needed, Karsten!)
- *
- * Revision 1.4  1999/08/22 20:26:47  calle
- * backported changes from kernel 2.3.14:
- * - several #include "config.h" gone, others come.
- * - "struct device" changed to "struct net_device" in 2.3.14, added a
- *   define in isdn_compat.h for older kernel versions.
- *
- * Revision 1.3  1999/08/18 20:17:01  armin
- * Added XLOG function for all cards.
- * Bugfix of alloc_skb NULL pointer.
- *
- * Revision 1.2  1999/07/25 15:12:05  armin
- * fix of some debug logs.
- * enabled ISA-cards option.
- *
- * Revision 1.1  1999/03/29 11:19:45  armin
- * I/O stuff now in seperate file (eicon_io.c)
- * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
- *
- *
  */
 
 
 #include <linux/config.h>
 #include "eicon.h"
+#include "uxio.h"
 
 void
 eicon_io_rcv_dispatch(eicon_card *ccard) {
@@ -85,12 +45,12 @@
 	while((skb = skb_dequeue(&ccard->rcvq))) {
         	ind = (eicon_IND *)skb->data;
 
-		save_flags(flags);
-		cli();
+		spin_lock_irqsave(&eicon_lock, flags);
         	if ((chan = ccard->IdTable[ind->IndId]) == NULL) {
+			spin_unlock_irqrestore(&eicon_lock, flags);
 			if (DebugVar & 1) {
 				switch(ind->Ind) {
-					case IDI_N_DISC_ACK: 
+					case N_DISC_ACK: 
 						/* doesn't matter if this happens */ 
 						break;
 					default: 
@@ -99,11 +59,10 @@
 							ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length);
 				}
 			}
-			restore_flags(flags);
 	                dev_kfree_skb(skb);
 	                continue;
 	        }
-		restore_flags(flags);
+		spin_unlock_irqrestore(&eicon_lock, flags);
 
 		if (chan->e.complete) { /* check for rec-buffer chaining */
 			if (ind->MLength == ind->RBuffer.length) {
@@ -119,12 +78,9 @@
 			}
 		}
 		else {
-			save_flags(flags);
-			cli();
 			if (!(skb2 = skb_dequeue(&chan->e.R))) {
 				chan->e.complete = 1;
                 		eicon_log(ccard, 1, "eicon: buffer incomplete, but 0 in queue\n");
-				restore_flags(flags);
 	                	dev_kfree_skb(skb);
 				continue;	
 			}
@@ -133,7 +89,6 @@
 					GFP_ATOMIC);
 			if (!skb_new) {
                 		eicon_log(ccard, 1, "eicon_io: skb_alloc failed in rcv_dispatch()\n");
-				restore_flags(flags);
 	                	dev_kfree_skb(skb);
 	                	dev_kfree_skb(skb2);
 				continue;	
@@ -152,14 +107,12 @@
                 	dev_kfree_skb(skb2);
 			if (ind->MLength == ind->RBuffer.length) {
 				chan->e.complete = 2;
-				restore_flags(flags);
 				idi_handle_ind(ccard, skb_new);
 				continue;
 			}
 			else {
 				chan->e.complete = 0;
 				skb_queue_tail(&chan->e.R, skb_new);
-				restore_flags(flags);
 				continue;
 			}
 		}
@@ -181,242 +134,120 @@
 
 
 /*
- *  IO-Functions for different card-types
+ *  IO-Functions for ISA cards
  */
 
 u8 ram_inb(eicon_card *card, void *adr) {
-        eicon_pci_card *pcard;
-        eicon_isa_card *icard;
         u32 addr = (u32) adr;
 	
-	pcard = &card->hwif.pci;
-	icard = &card->hwif.isa;
-
-        switch(card->type) {
-                case EICON_CTYPE_MAESTRA:
-                        outw((u16)addr, (u16)pcard->PCIreg + M_ADDR);
-                        return(inb((u16)pcard->PCIreg + M_DATA));
-                case EICON_CTYPE_MAESTRAP:
-                case EICON_CTYPE_S2M:
-		case EICON_CTYPE_S:
-		case EICON_CTYPE_SX:
-		case EICON_CTYPE_SCOM:
-		case EICON_CTYPE_QUADRO:
-                        return(readb(addr));
-        }
- return(0);
+	return(readb(addr));
 }
 
 u16 ram_inw(eicon_card *card, void *adr) {
-        eicon_pci_card *pcard;
-        eicon_isa_card *icard;
         u32 addr = (u32) adr;
-	
-	pcard = &card->hwif.pci;
-	icard = &card->hwif.isa;
 
-        switch(card->type) {
-                case EICON_CTYPE_MAESTRA:
-                        outw((u16)addr, (u16)pcard->PCIreg + M_ADDR);
-                        return(inw((u16)pcard->PCIreg + M_DATA));
-                case EICON_CTYPE_MAESTRAP:
-                case EICON_CTYPE_S2M:
-		case EICON_CTYPE_S:
-		case EICON_CTYPE_SX:
-		case EICON_CTYPE_SCOM:
-		case EICON_CTYPE_QUADRO:
-                        return(readw(addr));
-        }
- return(0);
+	return(readw(addr));
 }
 
 void ram_outb(eicon_card *card, void *adr, u8 data) {
-        eicon_pci_card *pcard;
-        eicon_isa_card *icard;
         u32 addr = (u32) adr;
 
-	pcard = &card->hwif.pci;
-	icard = &card->hwif.isa;
-
-        switch(card->type) {
-                case EICON_CTYPE_MAESTRA:
-                        outw((u16)addr, (u16)pcard->PCIreg + M_ADDR);
-                        outb((u8)data, (u16)pcard->PCIreg + M_DATA);
-                        break;
-                case EICON_CTYPE_MAESTRAP:
-                case EICON_CTYPE_S2M:
-		case EICON_CTYPE_S:
-		case EICON_CTYPE_SX:
-		case EICON_CTYPE_SCOM:
-		case EICON_CTYPE_QUADRO:
-                        writeb(data, addr);
-                        break;
-        }
+	writeb(data, addr);
 }
 
 void ram_outw(eicon_card *card, void *adr , u16 data) {
-        eicon_pci_card *pcard;
-        eicon_isa_card *icard;
         u32 addr = (u32) adr;
 
-	pcard = &card->hwif.pci;
-	icard = &card->hwif.isa;
-
-        switch(card->type) {
-                case EICON_CTYPE_MAESTRA:
-                        outw((u16)addr, (u16)pcard->PCIreg + M_ADDR);
-                        outw((u16)data, (u16)pcard->PCIreg + M_DATA);
-                        break;
-                case EICON_CTYPE_MAESTRAP:
-                case EICON_CTYPE_S2M:
-		case EICON_CTYPE_S:
-		case EICON_CTYPE_SX:
-		case EICON_CTYPE_SCOM:
-		case EICON_CTYPE_QUADRO:
-                        writew(data, addr);
-                        break;
-        }
+	writew(data, addr);
 }
 
 void ram_copyfromcard(eicon_card *card, void *adrto, void *adr, int len) {
-        int i;
-        switch(card->type) {
-                case EICON_CTYPE_MAESTRA:
-                        for(i = 0; i < len; i++) {
-                                writeb(ram_inb(card, adr + i), adrto + i);
-                        }
-                        break;
-                case EICON_CTYPE_MAESTRAP:
-                        memcpy(adrto, adr, len);
-                        break;
-                case EICON_CTYPE_S2M:
-		case EICON_CTYPE_S:
-		case EICON_CTYPE_SX:
-		case EICON_CTYPE_SCOM:
-		case EICON_CTYPE_QUADRO:
-                        memcpy_fromio(adrto, adr, len);
-                        break;
-        }
+	memcpy_fromio(adrto, adr, len);
 }
 
 void ram_copytocard(eicon_card *card, void *adrto, void *adr, int len) {
-        int i;
-        switch(card->type) {
-                case EICON_CTYPE_MAESTRA:
-                        for(i = 0; i < len; i++) {
-                                ram_outb(card, adrto + i, readb(adr + i));
-                        }
-                        break;
-                case EICON_CTYPE_MAESTRAP:
-                        memcpy(adrto, adr, len);
-                        break;
-                case EICON_CTYPE_S2M:
-		case EICON_CTYPE_S:
-		case EICON_CTYPE_SX:
-		case EICON_CTYPE_SCOM:
-		case EICON_CTYPE_QUADRO:
-                        memcpy_toio(adrto, adr, len);
-                        break;
-        }
+	memcpy_toio(adrto, adr, len);
 }
 
+
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
 /*
- * XLOG
+ *  IDI-Callback function
  */
-int
-eicon_get_xlog(eicon_card *card, xlogreq_t *xlogreq)
+void
+eicon_idi_callback(ENTITY *de)
 {
-	int timeout, i;
-	int divas_shared_offset = 0;
+	eicon_card *ccard = (eicon_card *)de->R;
+	struct sk_buff *skb;
+	eicon_RC *ack;
+	eicon_IND *ind;
 	int len = 0;
-	int stype = 0;
-	__u32 time = 0;
-	mi_pc_maint_t	*pcm = &xlogreq->pcm;
-        eicon_pci_card *pci_card = &card->hwif.pci;
-        eicon_isa_card *isa_card = &card->hwif.isa;
-	eicon_pr_ram  *prram = 0;
-        char *ram;
 
-	switch(card->type) {
-		case EICON_CTYPE_MAESTRAP:
-			ram = (char *)pci_card->PCIram;
-			prram = (eicon_pr_ram *)ram;
-			divas_shared_offset = DIVAS_SHARED_OFFSET;
-			len = sizeof(mi_pc_maint_t);
-			break;
-		case EICON_CTYPE_MAESTRA:
-			prram = 0;
-			divas_shared_offset = 0;
-			len = sizeof(mi_pc_maint_t);
-			break;
-		case EICON_CTYPE_S:
-		case EICON_CTYPE_SX:
-		case EICON_CTYPE_SCOM:
-		case EICON_CTYPE_QUADRO:
-		case EICON_CTYPE_S2M:
-			prram = (eicon_pr_ram *)isa_card->shmem;
-			divas_shared_offset = 0xfb80;
-			len = sizeof(mi_pc_maint_t) - 78;
-			stype = 1;
-			break;
-		default:
-			return -ENODEV;
-	}
-
-        memset(&(xlogreq->pcm), 0, sizeof(mi_pc_maint_t));
-
-        xlogreq->pcm.rc = 0;
-        xlogreq->pcm.req = 1; /* DO_LOG */
-
-        ram = ((char *)prram) + MIPS_MAINT_OFFS - divas_shared_offset;
-
-	ram_outb(card, ram+1, pcm->rc); 
-	ram_outb(card, ram+0, pcm->req); 
-
-        timeout = jiffies + 50;
-        while (timeout > jiffies) {
-		pcm->rc = ram_inb(card, ram+1);
-		pcm->req = ram_inb(card, ram+0);
-                if (!pcm->req) break;
-                SLEEP(10);
-        }
-
-	if (pcm->req) {
-		return XLOG_ERR_TIMEOUT;
-	}
-
-	if (pcm->rc != OK) {
-		return XLOG_ERR_DONE;
-	}
-	
-	ram_copyfromcard(card, pcm, ram, len);
-
-	if (stype) {
-		for (i=0; i<8; i++)
-			((__u8 *)pcm)[11-i] = ((__u8 *)pcm)[9-i];
-		time =	(__u32)pcm->data.w[2] * 3600 	* 1000 +
-			(__u32)pcm->data.w[1] 		* 1000 +
-			(__u32)pcm->data.b[1] 		* 20 +
-			(__u32)pcm->data.b[0]		;
-		pcm->data.w[1] = (__u16) (time >> 16);
-		pcm->data.w[2] = (__u16) (time & 0x0000ffff);
-		pcm->data.w[0] = 2;
+	if (de->complete == 255) {
+		/* Return Code */
+		skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC);
+		if (!skb) {
+			eicon_log(ccard, 1, "eicon_io: skb_alloc failed in _idi_callback()\n");
+		} else {
+			ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC));
+			ack->Rc = de->Rc;
+			if (de->Rc == ASSIGN_OK) {
+				ack->RcId = de->Id;
+				de->user[1] = de->Id;
+			} else {
+				ack->RcId = de->user[1];
+			}
+			ack->RcCh = de->RcCh;
+			ack->Reference = de->user[0];
+			skb_queue_tail(&ccard->rackq, skb);
+			eicon_schedule_ack(ccard);
+			eicon_log(ccard, 128, "idi_cbk: Ch%d: Rc=%x Id=%x RLen=%x compl=%x\n",
+				de->user[0], de->Rc, ack->RcId, de->RLength, de->complete);
+		}
+	} else {
+		/* Indication */
+		if (de->complete) {
+			len = de->RLength;
+		} else {
+			len = 270;
+			if (de->RLength <= 270)
+				eicon_log(ccard, 1, "eicon_cbk: ind not complete but <= 270\n");
+		}
+		skb = alloc_skb((sizeof(eicon_IND) + len - 1), GFP_ATOMIC);
+		if (!skb) {
+			eicon_log(ccard, 1, "eicon_io: skb_alloc failed in _idi_callback()\n");
+		} else {
+			ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1));
+			ind->Ind = de->Ind;
+			ind->IndId = de->user[1];
+			ind->IndCh = de->IndCh;
+			ind->MInd  = de->Ind;
+			ind->RBuffer.length = len;
+			ind->MLength = de->RLength;
+			memcpy(&ind->RBuffer.P, &de->RBuffer->P, len);
+			skb_queue_tail(&ccard->rcvq, skb);
+			eicon_schedule_rx(ccard);
+			eicon_log(ccard, 128, "idi_cbk: Ch%d: Ind=%x Id=%x RLen=%x compl=%x\n",
+				de->user[0], de->Ind, ind->IndId, de->RLength, de->complete);
+		}
 	}
 
-	return XLOG_OK;
+	de->RNum = 0;
+	de->RNR = 0;
+	de->Rc = 0;
+	de->Ind = 0;
 }
+#endif /* CONFIG_ISDN_DRV_EICON_PCI */
 
 /*
  *  Transmit-Function
  */
 void
 eicon_io_transmit(eicon_card *ccard) {
-        eicon_pci_card *pci_card;
         eicon_isa_card *isa_card;
         struct sk_buff *skb;
         struct sk_buff *skb2;
         unsigned long flags;
-        char *ram, *reg, *cfg;
 	eicon_pr_ram  *prram = 0;
 	eicon_isa_com	*com = 0;
 	eicon_REQ *ReqOut = 0;
@@ -426,10 +257,11 @@
 	int ReqCount;
 	int scom = 0;
 	int tmp = 0;
+	int tmpid = 0;
 	int quloop = 1;
 	int dlev = 0;
+	ENTITY *ep = 0;
 
-	pci_card = &ccard->hwif.pci;
 	isa_card = &ccard->hwif.isa;
 
         if (!ccard) {
@@ -451,20 +283,17 @@
 			prram = (eicon_pr_ram *)isa_card->shmem;
 			break;
 #endif
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
 		case EICON_CTYPE_MAESTRAP:
-			scom = 0;
-        		ram = (char *)pci_card->PCIram;
-		        reg = (char *)pci_card->PCIreg;
-        		cfg = (char *)pci_card->PCIcfg;
-			prram = (eicon_pr_ram *)ram;
+			scom = 2;
+			break;
+		case EICON_CTYPE_MAESTRAQ:
+			scom = 2;
 			break;
 		case EICON_CTYPE_MAESTRA:
-			scom = 0;
-        		ram = (char *)pci_card->PCIram;
-		        reg = (char *)pci_card->PCIreg;
-        		cfg = (char *)pci_card->PCIcfg;
-			prram = 0;
+			scom = 2;
 			break;
+#endif
 		default:
                 	eicon_log(ccard, 1, "eicon_transmit: unsupported card-type!\n");
 			return;
@@ -474,69 +303,91 @@
 	if (!(skb2 = skb_dequeue(&ccard->sndq)))
 		quloop = 0; 
 	while(quloop) { 
-                save_flags(flags);
-                cli();
-		if (scom) {
+		spin_lock_irqsave(&eicon_lock, flags);
+		switch (scom) {
+		  case 1:
 			if ((ram_inb(ccard, &com->Req)) || (ccard->ReadyInt)) {
 				if (!ccard->ReadyInt) {
 					tmp = ram_inb(ccard, &com->ReadyInt) + 1;
 					ram_outb(ccard, &com->ReadyInt, tmp);
 					ccard->ReadyInt++;
 				}
-        	                restore_flags(flags);
+				spin_unlock_irqrestore(&eicon_lock, flags);
                 	        skb_queue_head(&ccard->sndq, skb2);
        	                	eicon_log(ccard, 32, "eicon: transmit: Card not ready\n");
 	                        return;
 			}
-		} else {
+			break;
+		  case 0:
 	                if (!(ram_inb(ccard, &prram->ReqOutput) - ram_inb(ccard, &prram->ReqInput))) {
-        	                restore_flags(flags);
+				spin_unlock_irqrestore(&eicon_lock, flags);
                 	        skb_queue_head(&ccard->sndq, skb2);
        	                	eicon_log(ccard, 32, "eicon: transmit: Card not ready\n");
 	                        return;
         	        }
+			break;
 		}
-		restore_flags(flags);
+		spin_unlock_irqrestore(&eicon_lock, flags);
+
 		chan2 = (eicon_chan_ptr *)skb2->data;
 		chan = chan2->ptr;
 		if (!chan->e.busy) {
 		 if((skb = skb_dequeue(&chan->e.X))) { 
-		  save_flags(flags);
-		  cli();
+
 		  reqbuf = (eicon_REQ *)skb->data;
 		  if ((reqbuf->Reference) && (chan->e.B2Id == 0) && (reqbuf->ReqId & 0x1f)) {
 			eicon_log(ccard, 16, "eicon: transmit: error Id=0 on %d (Net)\n", chan->No); 
 		  } else {
-			if (scom) {
+			spin_lock_irqsave(&eicon_lock, flags);
+
+			switch (scom) {
+			  case 1:
 				ram_outw(ccard, &com->XBuffer.length, reqbuf->XBuffer.length);
 				ram_copytocard(ccard, &com->XBuffer.P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length);
 				ram_outb(ccard, &com->ReqCh, reqbuf->ReqCh);
-				
-			} else {
+				break;	
+			  case 0:
 				/* get address of next available request buffer */
 				ReqOut = (eicon_REQ *)&prram->B[ram_inw(ccard, &prram->NextReq)];
 				ram_outw(ccard, &ReqOut->XBuffer.length, reqbuf->XBuffer.length);
 				ram_copytocard(ccard, &ReqOut->XBuffer.P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length);
 				ram_outb(ccard, &ReqOut->ReqCh, reqbuf->ReqCh);
 				ram_outb(ccard, &ReqOut->Req, reqbuf->Req); 
+				break;
 			}
+
 			dlev = 160;
+
 			if (reqbuf->ReqId & 0x1f) { /* if this is no ASSIGN */
 
 				if (!reqbuf->Reference) { /* Signal Layer */
-					if (scom)
+					switch (scom) {
+					  case 1:
 						ram_outb(ccard, &com->ReqId, chan->e.D3Id); 
-					else
+						break;
+					  case 0:
 						ram_outb(ccard, &ReqOut->ReqId, chan->e.D3Id); 
-
+						break;
+					  case 2:
+						ep = &chan->de;
+						break;
+					}
+					tmpid = chan->e.D3Id;
 					chan->e.ReqCh = 0; 
 				}
 				else {			/* Net Layer */
-					if (scom)
+					switch(scom) {
+					  case 1:
 						ram_outb(ccard, &com->ReqId, chan->e.B2Id); 
-					else
+						break;
+					  case 0:
 						ram_outb(ccard, &ReqOut->ReqId, chan->e.B2Id); 
-
+						break;
+					  case 2:
+						ep = &chan->be;
+						break;
+					}
+					tmpid = chan->e.B2Id;
 					chan->e.ReqCh = 1;
 					if (((reqbuf->Req & 0x0f) == 0x08) ||
 					   ((reqbuf->Req & 0x0f) == 0x01)) { /* Send Data */
@@ -548,51 +399,106 @@
 
 			} else {	/* It is an ASSIGN */
 
-				if (scom)
+				switch(scom) {
+				  case 1:
 					ram_outb(ccard, &com->ReqId, reqbuf->ReqId); 
-				else
+					break;
+				  case 0:
 					ram_outb(ccard, &ReqOut->ReqId, reqbuf->ReqId); 
+					break;
+				  case 2:
+					if (!reqbuf->Reference) 
+						ep = &chan->de;
+					else
+						ep = &chan->be;
+					ep->Id = reqbuf->ReqId;
+					break;
+				}
+				tmpid = reqbuf->ReqId;
 
 				if (!reqbuf->Reference) 
 					chan->e.ReqCh = 0; 
 				 else
 					chan->e.ReqCh = 1; 
 			} 
-			if (scom)
+
+			switch(scom) {
+			  case 1:
 			 	chan->e.ref = ccard->ref_out++;
-			else
+				break;
+			  case 0:
 			 	chan->e.ref = ram_inw(ccard, &ReqOut->Reference);
+				break;
+			  case 2:
+				chan->e.ref = chan->No;
+				break;
+			}
 
 			chan->e.Req = reqbuf->Req;
 			ReqCount++; 
-			if (scom)
+
+			switch (scom) {
+			  case 1:
 				ram_outb(ccard, &com->Req, reqbuf->Req); 
-			else
+				break;
+			  case 0:
 				ram_outw(ccard, &prram->NextReq, ram_inw(ccard, &ReqOut->next)); 
+				break;
+			  case 2:
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
+				if (!ep) break;
+				ep->callback = eicon_idi_callback;
+				ep->R = (BUFFERS *)ccard;
+				ep->user[0] = (word)chan->No;
+				ep->user[1] = (word)tmpid;
+				ep->XNum = 1;
+				ep->RNum = 0;
+				ep->RNR = 0;
+				ep->Rc = 0;
+				ep->Ind = 0;
+				ep->X->PLength = reqbuf->XBuffer.length;
+				memcpy(ep->X->P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length);
+				ep->ReqCh = reqbuf->ReqCh;
+				ep->Req = reqbuf->Req;
+#endif
+				break;
+			}
 
 			chan->e.busy = 1;
+			spin_unlock_irqrestore(&eicon_lock, flags);
 	               	eicon_log(ccard, dlev, "eicon: Req=%d Id=%x Ch=%d Len=%d Ref=%d\n", 
-					reqbuf->Req, 
-					(scom) ? ram_inb(ccard, &com->ReqId) :
-						ram_inb(ccard, &ReqOut->ReqId),
+					reqbuf->Req, tmpid, 
 					reqbuf->ReqCh, reqbuf->XBuffer.length,
 					chan->e.ref); 
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
+			if (scom == 2) {
+				if (ep) {
+					ccard->d->request(ep);
+					if (ep->Rc)
+						eicon_idi_callback(ep);
+				}
+			}
+#endif
 		  }
-		  restore_flags(flags);
 		  dev_kfree_skb(skb);
 		 }
 		 dev_kfree_skb(skb2);
 		} 
 		else {
-		skb_queue_tail(&ccard->sackq, skb2);
-               	eicon_log(ccard, 128, "eicon: transmit: busy chan %d\n", chan->No); 
+			skb_queue_tail(&ccard->sackq, skb2);
+        	       	eicon_log(ccard, 128, "eicon: transmit: busy chan %d\n", chan->No); 
 		}
 
-		if (scom)
-			quloop = 0;
-		else
-			if (!(skb2 = skb_dequeue(&ccard->sndq)))
+		switch(scom) {
+			case 1:
 				quloop = 0;
+				break;
+			case 0:
+			case 2:
+				if (!(skb2 = skb_dequeue(&ccard->sndq)))
+					quloop = 0;
+				break;
+		}
 
 	}
 	if (!scom)
@@ -603,18 +509,14 @@
 	}
 }
 
-
+#ifdef CONFIG_ISDN_DRV_EICON_ISA
 /*
  * IRQ handler 
  */
 void
 eicon_irq(int irq, void *dev_id, struct pt_regs *regs) {
 	eicon_card *ccard = (eicon_card *)dev_id;
-        eicon_pci_card *pci_card;
         eicon_isa_card *isa_card;
-    	char *ram = 0;
-	char *reg = 0;
-	char *cfg = 0;	
 	eicon_pr_ram  *prram = 0;
 	eicon_isa_com	*com = 0;
         eicon_RC *RcIn;
@@ -646,11 +548,9 @@
 		}
 	}
 
-	pci_card = &ccard->hwif.pci;
 	isa_card = &ccard->hwif.isa;
 
 	switch(ccard->type) {
-#ifdef CONFIG_ISDN_DRV_EICON_ISA
 		case EICON_CTYPE_S:
 		case EICON_CTYPE_SX:
 		case EICON_CTYPE_SCOM:
@@ -664,23 +564,6 @@
 			prram = (eicon_pr_ram *)isa_card->shmem;
 			irqprobe = &isa_card->irqprobe;
 			break;
-#endif
-		case EICON_CTYPE_MAESTRAP:
-			scom = 0;
-			ram = (char *)pci_card->PCIram;
-			reg = (char *)pci_card->PCIreg;
-			cfg = (char *)pci_card->PCIcfg;
-			irqprobe = &pci_card->irqprobe;
-			prram = (eicon_pr_ram *)ram;
-			break;
-		case EICON_CTYPE_MAESTRA:
-			scom = 0;
-			ram = (char *)pci_card->PCIram;
-			reg = (char *)pci_card->PCIreg;
-			cfg = (char *)pci_card->PCIcfg;
-			irqprobe = &pci_card->irqprobe;
-			prram = 0;
-			break;
 		default:
                 	eicon_log(ccard, 1, "eicon_irq: unsupported card-type!\n");
 			return;
@@ -688,7 +571,6 @@
 
 	if (*irqprobe) {
 		switch(ccard->type) {
-#ifdef CONFIG_ISDN_DRV_EICON_ISA
 			case EICON_CTYPE_S:
 			case EICON_CTYPE_SX:
 			case EICON_CTYPE_SCOM:
@@ -706,26 +588,11 @@
 				}
 				(*irqprobe)++;
 				break;
-#endif
-			case EICON_CTYPE_MAESTRAP:
-	        		if (readb(&ram[0x3fe])) { 
-        		               	writeb(0, &prram->RcOutput);
-				        writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]);
-				        writew(0, &cfg[MP_IRQ_RESET + 2]);
-					writeb(0, &ram[0x3fe]);
-       			        } 
-				*irqprobe = 0;
-				break;
-			case EICON_CTYPE_MAESTRA:
-				outb(0x08, pci_card->PCIreg + M_RESET);
-				*irqprobe = 0;
-				break;
 		}
 		return;
 	}
 
 	switch(ccard->type) {
-#ifdef CONFIG_ISDN_DRV_EICON_ISA
 		case EICON_CTYPE_S:
 		case EICON_CTYPE_SX:
 		case EICON_CTYPE_SCOM:
@@ -736,20 +603,6 @@
 				return;
 			} 
 			break;
-#endif
-		case EICON_CTYPE_MAESTRAP:
-			if (!(readb(&ram[0x3fe]))) { /* card did not interrupt */
-				eicon_log(ccard, 1, "eicon: IRQ: card reports no interrupt!\n");
-				return;
-			} 
-			break;
-		case EICON_CTYPE_MAESTRA:
-			outw(0x3fe, pci_card->PCIreg + M_ADDR);
-			if (!(inb(pci_card->PCIreg + M_DATA))) { /* card did not interrupt */
-				eicon_log(ccard, 1, "eicon: IRQ: card reports no interrupt!\n");
-				return;
-			} 
-			break;
 	}
 
     if (scom) {
@@ -891,7 +744,6 @@
 
 	/* clear interrupt */
 	switch(ccard->type) {
-#ifdef CONFIG_ISDN_DRV_EICON_ISA
 		case EICON_CTYPE_QUADRO:
 			writeb(0, isa_card->intack);
 			writeb(0, &com[0x401]);
@@ -902,19 +754,8 @@
 		case EICON_CTYPE_S2M:
 			writeb(0, isa_card->intack);
 			break;
-#endif
-		case EICON_CTYPE_MAESTRAP:
-			writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]);
-			writew(0, &cfg[MP_IRQ_RESET + 2]); 
-			writeb(0, &ram[0x3fe]); 
-			break;
-		case EICON_CTYPE_MAESTRA:
-			outb(0x08, pci_card->PCIreg + M_RESET);
-			outw(0x3fe, pci_card->PCIreg + M_ADDR);
-			outb(0, pci_card->PCIreg + M_DATA);
-			break;
 	}
 
   return;
 }
-
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/eicon_isa.c linux.19p18/drivers/isdn/eicon/eicon_isa.c
--- linux.vanilla/drivers/isdn/eicon/eicon_isa.c	Fri Apr 21 12:46:08 2000
+++ linux.19p18/drivers/isdn/eicon/eicon_isa.c	Mon Feb 19 18:28:19 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon_isa.c,v 1.14 2000/02/22 16:26:40 armin Exp $
+/* $Id: eicon_isa.c,v 1.16 2000/06/12 12:44:02 armin Exp $
  *
  * ISDN low-level module for Eicon active ISDN-Cards.
  * Hardware-specific code for old ISA cards.
@@ -21,62 +21,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
- * $Log: eicon_isa.c,v $
- * Revision 1.14  2000/02/22 16:26:40  armin
- * Fixed membase error message.
- * Fixed missing log buffer struct.
- *
- * Revision 1.13  2000/01/23 21:21:23  armin
- * Added new trace capability and some updates.
- * DIVA Server BRI now supports data for ISDNLOG.
- *
- * Revision 1.12  1999/11/27 12:56:19  armin
- * Forgot some iomem changes for last ioremap compat.
- *
- * Revision 1.11  1999/11/25 11:33:09  armin
- * Microchannel fix from Erik Weber (exrz73@ibm.net).
- *
- * Revision 1.10  1999/11/18 21:14:30  armin
- * New ISA memory mapped IO
- *
- * Revision 1.9  1999/09/08 20:17:31  armin
- * Added microchannel patch from Erik Weber (exrz73@ibm.net).
- *
- * Revision 1.8  1999/09/06 07:29:35  fritz
- * Changed my mail-address.
- *
- * Revision 1.7  1999/08/22 20:26:48  calle
- * backported changes from kernel 2.3.14:
- * - several #include "config.h" gone, others come.
- * - "struct device" changed to "struct net_device" in 2.3.14, added a
- *   define in isdn_compat.h for older kernel versions.
- *
- * Revision 1.6  1999/07/25 15:12:06  armin
- * fix of some debug logs.
- * enabled ISA-cards option.
- *
- * Revision 1.5  1999/04/01 12:48:33  armin
- * Changed some log outputs.
- *
- * Revision 1.4  1999/03/29 11:19:46  armin
- * I/O stuff now in seperate file (eicon_io.c)
- * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
- *
- * Revision 1.3  1999/03/02 12:37:45  armin
- * Added some important checks.
- * Analog Modem with DSP.
- * Channels will be added to Link-Level after loading firmware.
- *
- * Revision 1.2  1999/01/24 20:14:19  armin
- * Changed and added debug stuff.
- * Better data sending. (still problems with tty's flip buffer)
- *
- * Revision 1.1  1999/01/01 18:09:43  armin
- * First checkin of new eicon driver.
- * DIVA-Server BRI/PCI and PRI/PCI are supported.
- * Old diehl code is obsolete.
- *
- *
  */
 
 #include <linux/config.h>
@@ -87,7 +31,7 @@
 #define release_shmem release_region
 #define request_shmem request_region
 
-char *eicon_isa_revision = "$Revision: 1.14 $";
+char *eicon_isa_revision = "$Revision: 1.16 $";
 
 #undef EICON_MCA_DEBUG
 
@@ -354,7 +298,7 @@
 	printk(KERN_INFO "%s: startup-code loaded\n", eicon_ctype_name[card->type]); 
 	if ((card->type == EICON_CTYPE_QUADRO) && (card->master)) {
 		tmp = eicon_addcard(card->type, card->physmem, card->irq, 
-					((eicon_card *)card->card)->regname);
+				((eicon_card *)card->card)->regname, 0);
 		printk(KERN_INFO "Eicon: %d adapters added\n", tmp);
 	}
 	return 0;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/eicon_isa.h linux.19p18/drivers/isdn/eicon/eicon_isa.h
--- linux.vanilla/drivers/isdn/eicon/eicon_isa.h	Fri Apr 21 23:23:24 2000
+++ linux.19p18/drivers/isdn/eicon/eicon_isa.h	Mon Feb 19 18:28:19 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon_isa.h,v 1.8 2000/01/23 21:21:23 armin Exp $
+/* $Id: eicon_isa.h,v 1.10 2000/05/07 08:51:04 armin Exp $
  *
  * ISDN low-level module for Eicon active ISDN-Cards.
  *
@@ -20,38 +20,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
- * $Log: eicon_isa.h,v $
- * Revision 1.8  2000/01/23 21:21:23  armin
- * Added new trace capability and some updates.
- * DIVA Server BRI now supports data for ISDNLOG.
- *
- * Revision 1.7  1999/11/18 21:14:30  armin
- * New ISA memory mapped IO
- *
- * Revision 1.6  1999/11/15 19:37:04  keil
- * need config.h
- *
- * Revision 1.5  1999/09/08 20:17:31  armin
- * Added microchannel patch from Erik Weber.
- *
- * Revision 1.4  1999/09/06 07:29:35  fritz
- * Changed my mail-address.
- *
- * Revision 1.3  1999/03/29 11:19:47  armin
- * I/O stuff now in seperate file (eicon_io.c)
- * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
- *
- * Revision 1.2  1999/03/02 12:37:46  armin
- * Added some important checks.
- * Analog Modem with DSP.
- * Channels will be added to Link-Level after loading firmware.
- *
- * Revision 1.1  1999/01/01 18:09:44  armin
- * First checkin of new eicon driver.
- * DIVA-Server BRI/PCI and PRI/PCI are supported.
- * Old diehl code is obsolete.
- *
- *
  */
 
 #ifndef eicon_isa_h
@@ -138,7 +106,6 @@
 	unsigned char     mvalid;   /* Flag: Memory is valid      */
 	unsigned char     ivalid;   /* Flag: IRQ is valid         */
 	unsigned char     master;   /* Flag: Card ist Quadro 1/4  */
-	void*             generic;  /* Ptr to generic card struct */
 } eicon_isa_card;
 
 /* Offsets for special locations on standard cards */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/eicon_mod.c linux.19p18/drivers/isdn/eicon/eicon_mod.c
--- linux.vanilla/drivers/isdn/eicon/eicon_mod.c	Fri Apr 21 12:46:08 2000
+++ linux.19p18/drivers/isdn/eicon/eicon_mod.c	Mon Feb 19 18:28:19 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon_mod.c,v 1.25 2000/02/22 16:26:40 armin Exp $
+/* $Id: eicon_mod.c,v 1.37.6.4 2001/02/16 09:09:50 armin Exp $
  *
  * ISDN lowlevel-module for Eicon active cards.
  * 
@@ -6,11 +6,9 @@
  * Copyright 1998-2000 by Armin Schindler (mac@melware.de) 
  * Copyright 1999,2000 Cytronics & Melware (info@melware.de)
  * 
- * Thanks to    Eicon Technology GmbH & Co. oHG for
+ * Thanks to    Eicon Networks for
  *              documents, informations and hardware.
  *
- *              Deutsche Telekom AG for S2M support.
- *
  *		Deutsche Mailbox Saar-Lor-Lux GmbH
  *		for sponsoring and testing fax
  *		capabilities with Diva Server cards.
@@ -30,105 +28,12 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
- * $Log: eicon_mod.c,v $
- * Revision 1.25  2000/02/22 16:26:40  armin
- * Fixed membase error message.
- * Fixed missing log buffer struct.
- *
- * Revision 1.24  2000/01/23 21:21:23  armin
- * Added new trace capability and some updates.
- * DIVA Server BRI now supports data for ISDNLOG.
- *
- * Revision 1.23  2000/01/20 19:55:34  keil
- * Add FAX Class 1 support
- *
- * Revision 1.22  1999/11/27 12:56:19  armin
- * Forgot some iomem changes for last ioremap compat.
- *
- * Revision 1.21  1999/11/25 11:35:10  armin
- * Microchannel fix from Erik Weber (exrz73@ibm.net).
- * Minor cleanup.
- *
- * Revision 1.20  1999/11/18 21:14:30  armin
- * New ISA memory mapped IO
- *
- * Revision 1.19  1999/11/12 13:21:44  armin
- * Bugfix of undefined reference with CONFIG_MCA
- *
- * Revision 1.18  1999/10/11 18:13:25  armin
- * Added fax capabilities for Eicon Diva Server cards.
- *
- * Revision 1.17  1999/10/08 22:09:34  armin
- * Some fixes of cards interface handling.
- * Bugfix of NULL pointer occurence.
- * Changed a few log outputs.
- *
- * Revision 1.16  1999/09/26 14:17:53  armin
- * Improved debug and log via readstat()
- *
- * Revision 1.15  1999/09/08 20:17:31  armin
- * Added microchannel patch from Erik Weber (exrz73@ibm.net).
- *
- * Revision 1.14  1999/09/06 07:29:35  fritz
- * Changed my mail-address.
- *
- * Revision 1.13  1999/09/04 17:37:59  armin
- * Removed not used define, did not work and caused error
- * in 2.3.16
- *
- * Revision 1.12  1999/08/31 11:20:14  paul
- * various spelling corrections (new checksums may be needed, Karsten!)
- *
- * Revision 1.11  1999/08/29 17:23:45  armin
- * New setup compat.
- * Bugfix if compile as not module.
- *
- * Revision 1.10  1999/08/28 21:32:53  armin
- * Prepared for fax related functions.
- * Now compilable without errors/warnings.
- *
- * Revision 1.9  1999/08/18 20:17:02  armin
- * Added XLOG function for all cards.
- * Bugfix of alloc_skb NULL pointer.
- *
- * Revision 1.8  1999/07/25 15:12:08  armin
- * fix of some debug logs.
- * enabled ISA-cards option.
- *
- * Revision 1.7  1999/07/11 17:16:27  armin
- * Bugfixes in queue handling.
- * Added DSP-DTMF decoder functions.
- * Reorganized ack_handler.
- *
- * Revision 1.6  1999/06/09 19:31:26  armin
- * Wrong PLX size for request_region() corrected.
- * Added first MCA code from Erik Weber.
- *
- * Revision 1.5  1999/04/01 12:48:35  armin
- * Changed some log outputs.
- *
- * Revision 1.4  1999/03/29 11:19:47  armin
- * I/O stuff now in seperate file (eicon_io.c)
- * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
- *
- * Revision 1.3  1999/03/02 12:37:47  armin
- * Added some important checks.
- * Analog Modem with DSP.
- * Channels will be added to Link-Level after loading firmware.
- *
- * Revision 1.2  1999/01/24 20:14:21  armin
- * Changed and added debug stuff.
- * Better data sending. (still problems with tty's flip buffer)
- *
- * Revision 1.1  1999/01/01 18:09:44  armin
- * First checkin of new eicon driver.
- * DIVA-Server BRI/PCI and PRI/PCI are supported.
- * Old diehl code is obsolete.
- *
- *
  */
 
-#define DRIVERPATCH ""
+#define DRIVERNAME "Eicon active ISDN driver"
+#define DRIVERRELEASE "2.0"
+#define DRIVERPATCH ".16"
+
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -139,17 +44,27 @@
 
 #include "eicon.h"
 
+#include "../avmb1/capicmd.h"  /* this should be moved in a common place */
+
+#undef N_DATA
+#include "adapter.h"
+#include "uxio.h"
+
 #define INCLUDE_INLINE_FUNCS
 
 static eicon_card *cards = (eicon_card *) NULL;   /* glob. var , contains
                                                      start of card-list   */
 
-static char *eicon_revision = "$Revision: 1.25 $";
+static char *eicon_revision = "$Revision: 1.37.6.4 $";
 
 extern char *eicon_pci_revision;
 extern char *eicon_isa_revision;
 extern char *eicon_idi_revision;
 
+extern int do_ioctl(struct inode *pDivasInode, struct file *pDivasFile,
+			unsigned int command, unsigned long arg);
+extern void eicon_pci_init_conf(eicon_card *card);
+
 #ifdef MODULE
 #define MOD_USE_COUNT (GET_USE_COUNT (&__this_module))
 #endif
@@ -158,6 +73,10 @@
 
 ulong DebugVar;
 
+spinlock_t eicon_lock;
+
+DESCRIPTOR idi_d[32];
+
 /* Parameters to be set by insmod */
 #ifdef CONFIG_ISDN_DRV_EICON_ISA
 static int   membase      = -1;
@@ -189,23 +108,6 @@
         "DIVA Server PRI/PCI"
 };
 
-static int
-getrel(char *p)
-{
-        int v = 0;
-	char *tmp = 0;
-
-	if ((tmp = strchr(p, '.')))
-		p = tmp + 1;
-        while (p[0] >= '0' && p[0] <= '9') {
-                v = ((v < 0) ? 0 : (v * 10)) + (int) (p[0] - '0');
-		p++;
-	}
-        return v;
-
-
-}
-
 static char *
 eicon_getrev(const char *revision)
 {
@@ -229,68 +131,26 @@
 	return NULL;
 }
 
+#ifdef CONFIG_PCI
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
 /*
- * Free MSN list
+ * Find pcicard with given card number 
  */
-static void
-eicon_clear_msn(eicon_card *card)
+static inline eicon_card *
+eicon_findnpcicard(int driverid)
 {
-        struct msn_entry *p = card->msn_list;
-        struct msn_entry *q;
-	unsigned long flags;
+        eicon_card *p = cards;
 
-	save_flags(flags);
-	cli();
-        card->msn_list = NULL;
-	restore_flags(flags);
         while (p) {
-                q  = p->next;
-                kfree(p);
-                p = q;
+                if ((p->regname[strlen(p->regname)-1] == (driverid + '0')) &&
+			(p->bus == EICON_BUS_PCI))
+                        return p;
+                p = p->next;
         }
+        return (eicon_card *) 0;
 }
-
-/*
- * Find an MSN entry in the list.
- * If ia5 != 0, return IA5-encoded EAZ, else
- * return a bitmask with corresponding bit set.
- */
-static __u16
-eicon_find_msn(eicon_card *card, char *msn, int ia5)
-{
-        struct msn_entry *p = card->msn_list;
-	__u8 eaz = '0';
-
-	while (p) {
-		if (!strcmp(p->msn, msn)) {
-			eaz = p->eaz;
-			break;
-		}
-		p = p->next;
-	}
-	if (!ia5)
-		return (1 << (eaz - '0'));
-	else
-		return eaz;
-}
-
-/*
- * Find an EAZ entry in the list.
- * return a string with corresponding msn.
- */
-char *
-eicon_find_eaz(eicon_card *card, char eaz)
-{
-        struct msn_entry *p = card->msn_list;
-
-	while (p) {
-		if (p->eaz == eaz)
-			return(p->msn);
-		p = p->next;
-	}
-	return("\0");
-}
-
+#endif
+#endif /* CONFIG_PCI */
 
 static void
 eicon_rcv_dispatch(struct eicon_card *card)
@@ -337,39 +197,19 @@
 	}
 }
 
-static int eicon_xlog(eicon_card *card, xlogreq_t *xlogreq)
-{
-	xlogreq_t *xlr;
-	int ret_val;
-
-	if (!(xlr = kmalloc(sizeof(xlogreq_t), GFP_KERNEL))) {
-		eicon_log(card, 1, "idi_err: alloc_xlogreq_t failed\n");
-		return -ENOMEM;
-	}
-	if (copy_from_user(xlr, xlogreq, sizeof(xlogreq_t))) {
-		kfree(xlr);
-		return -EFAULT;
-	}
-
-	ret_val = eicon_get_xlog(card, xlr);
-
-	if (copy_to_user(xlogreq, xlr, sizeof(xlogreq_t))) {
-		kfree(xlr);
-		return -EFAULT;
-	}
-	kfree(xlr);
-
-	return ret_val;
-}
-
 static int
 eicon_command(eicon_card * card, isdn_ctrl * c)
 {
         ulong a;
         eicon_chan *chan;
 	eicon_cdef cdef;
+#ifdef CONFIG_PCI
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
+	dia_start_t dstart;
+        int idi_length = 0;
+#endif
+#endif
 	isdn_ctrl cmd;
-	char tmp[17];
 	int ret = 0;
 	unsigned long flags;
  
@@ -383,16 +223,15 @@
 				case EICON_IOCTL_GETVER:
 					return(EICON_CTRL_VERSION);
 				case EICON_IOCTL_GETTYPE:
+					if (card->bus == EICON_BUS_PCI) {
+						copy_to_user((char *)a, &card->hwif.pci.master, sizeof(int));
+					}
 					return(card->type);
 				case EICON_IOCTL_GETMMIO:
 					switch (card->bus) {
 						case EICON_BUS_ISA:
 						case EICON_BUS_MCA:
 							return (int)card->hwif.isa.shmem;
-#if CONFIG_PCI
-						case EICON_BUS_PCI:
-							return card->hwif.pci.PCIram;
-#endif
 						default:
 							eicon_log(card, 1,
 							       "eicon: Illegal BUS type %d\n",
@@ -433,10 +272,6 @@
 						case EICON_BUS_ISA:
 						case EICON_BUS_MCA:
 							return card->hwif.isa.irq;
-#if CONFIG_PCI
-						case EICON_BUS_PCI:
-							return card->hwif.pci.irq;
-#endif
 						default:
 							eicon_log(card, 1,
 							       "eicon: Illegal BUS type %d\n",
@@ -514,7 +349,9 @@
 				case EICON_IOCTL_MANIF:
 					if (!card->flags & EICON_FLAGS_RUNNING)
 						return -ENODEV;
-					if (!card->Feature & PROTCAP_MANIF)
+					if (!card->d)
+						return -ENODEV;
+					if (!card->d->features & DI_MANAGE)
 						return -ENODEV;
 					ret = eicon_idi_manage(
 						card, 
@@ -522,49 +359,12 @@
 					return ret;
 
 				case EICON_IOCTL_GETXLOG:
-					if (!card->flags & EICON_FLAGS_RUNNING)
-						return XLOG_ERR_CARD_STATE;
-					ret = eicon_xlog(card, (xlogreq_t *)a);
-					return ret;
-#if CONFIG_PCI 
-				case EICON_IOCTL_LOADPCI:
-						if (card->flags & EICON_FLAGS_RUNNING)
-							return -EBUSY;  
-                                                if (card->bus == EICON_BUS_PCI) {
-							switch(card->type) {
-								case EICON_CTYPE_MAESTRA:
-                                                		        ret = eicon_pci_load_bri(
-		                                                                &(card->hwif.pci),
-                		                                                &(((eicon_codebuf *)a)->pci)); 
-									break;
-
-								case EICON_CTYPE_MAESTRAP:
-		                                                        ret = eicon_pci_load_pri(
-                		                                                &(card->hwif.pci),
-                                		                                &(((eicon_codebuf *)a)->pci)); 
-									break;
-							}
-                                                        if (!ret) {
-                                                                card->flags |= EICON_FLAGS_LOADED;
-                                                                card->flags |= EICON_FLAGS_RUNNING;
-								if (card->hwif.pci.channels > 1) {
-									cmd.command = ISDN_STAT_ADDCH;
-									cmd.driver = card->myid;
-									cmd.arg = card->hwif.pci.channels - 1;
-									card->interface.statcallb(&cmd);
-								}
-								cmd.command = ISDN_STAT_RUN;    
-								cmd.driver = card->myid;        
-								cmd.arg = 0;                    
-								card->interface.statcallb(&cmd);
-							} 
-                                                        return ret;
-						} else return -ENODEV;
-#endif
+					return -ENODEV;
+
 				case EICON_IOCTL_ADDCARD:
 					if ((ret = copy_from_user(&cdef, (char *)a, sizeof(cdef))))
 						return -EFAULT;
-					if (!(eicon_addcard(0, cdef.membase, cdef.irq, cdef.id)))
+					if (!(eicon_addcard(0, cdef.membase, cdef.irq, cdef.id, 0)))
 						return -EIO;
 					return 0;
 				case EICON_IOCTL_DEBUGVAR:
@@ -577,8 +377,87 @@
 					MOD_INC_USE_COUNT;
 					return 0;
 #endif
-				default:
+				case EICON_IOCTL_LOADPCI:
+					eicon_log(card, 1, "Eicon: Wrong version of load-utility,\n");
+					eicon_log(card, 1, "Eicon: re-compile eiconctrl !\n");
+					eicon_log(card, 1, "Eicon: Maybe update of utility is necessary !\n");
 					return -EINVAL;
+				default:	
+#ifdef CONFIG_PCI
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
+					if (c->arg < EICON_IOCTL_DIA_OFFSET)
+						return -EINVAL;
+					if (copy_from_user(&dstart, (char *)a, sizeof(dstart)))
+						return -1;
+					if (!(card = eicon_findnpcicard(dstart.card_id)))
+						return -EINVAL;
+					ret = do_ioctl(NULL, NULL,
+						c->arg - EICON_IOCTL_DIA_OFFSET,
+						(unsigned long) a);
+					if (((c->arg - EICON_IOCTL_DIA_OFFSET)==DIA_IOCTL_START) && (!ret)) {
+						if (card->type != EICON_CTYPE_MAESTRAQ) {
+							DIVA_DIDD_Read(idi_d, sizeof(idi_d));
+                                                        for(idi_length = 0; idi_length < 32; idi_length++) {
+                                                          if (idi_d[idi_length].type == 0) break;
+                                                        }
+                                                        if ((idi_length < 1) || (idi_length >= 32)) {
+					                  eicon_log(card, 1, "eicon: invalid idi table length.\n");
+                                                          break;
+                                                        }
+							card->d = &idi_d[idi_length - 1];
+							card->flags |= EICON_FLAGS_LOADED;
+							card->flags |= EICON_FLAGS_RUNNING;
+							eicon_pci_init_conf(card);
+							if (card->d->channels > 1) {
+								cmd.command = ISDN_STAT_ADDCH;
+								cmd.driver = card->myid;
+								cmd.arg = card->d->channels - 1;
+								card->interface.statcallb(&cmd);
+							}
+							cmd.command = ISDN_STAT_RUN;    
+							cmd.driver = card->myid;        
+							cmd.arg = 0;                    
+							card->interface.statcallb(&cmd);
+							eicon_log(card, 1, "Eicon: %s started, %d channels (feat. 0x%x)\n",
+								(card->type == EICON_CTYPE_MAESTRA) ? "BRI" : "PRI",
+								card->d->channels, card->d->features);
+						} else {
+							int i;
+							DIVA_DIDD_Read(idi_d, sizeof(idi_d));
+                                                        for(idi_length = 0; idi_length < 32; idi_length++)
+                                                          if (idi_d[idi_length].type == 0) break;
+                                                        if ((idi_length < 1) || (idi_length >= 32)) {
+					                  eicon_log(card, 1, "eicon: invalid idi table length.\n");
+                                                          break;
+                                                        }
+        						for(i = 3; i >= 0; i--) {
+								if (!(card = eicon_findnpcicard(dstart.card_id - i)))
+									return -EINVAL;
+	
+								card->flags |= EICON_FLAGS_LOADED;
+								card->flags |= EICON_FLAGS_RUNNING;
+								card->d = &idi_d[idi_length - (i+1)];
+								eicon_pci_init_conf(card);
+								if (card->d->channels > 1) {
+									cmd.command = ISDN_STAT_ADDCH;
+									cmd.driver = card->myid;
+									cmd.arg = card->d->channels - 1;
+									card->interface.statcallb(&cmd);
+								}
+								cmd.command = ISDN_STAT_RUN;    
+								cmd.driver = card->myid;        
+								cmd.arg = 0;                    
+								card->interface.statcallb(&cmd);
+								eicon_log(card, 1, "Eicon: %d/4BRI started, %d channels (feat. 0x%x)\n",
+									4-i, card->d->channels, card->d->features);
+							}
+						}
+					}
+					return ret;
+#else
+					return -EINVAL;
+#endif
+#endif /* CONFIG_PCI */
 			}
 			break;
 		case ISDN_CMD_DIAL:
@@ -586,20 +465,15 @@
 				return -ENODEV;
 			if (!(chan = find_channel(card, c->arg & 0x1f)))
 				break;
-			save_flags(flags);
-			cli();
+			spin_lock_irqsave(&eicon_lock, flags);
 			if ((chan->fsm_state != EICON_STATE_NULL) && (chan->fsm_state != EICON_STATE_LISTEN)) {
-				restore_flags(flags);
+				spin_unlock_irqrestore(&eicon_lock, flags);
 				eicon_log(card, 1, "Dial on channel %d with state %d\n",
 					chan->No, chan->fsm_state);
 				return -EBUSY;
 			}
-			if (card->ptype == ISDN_PTYPE_EURO)
-				tmp[0] = eicon_find_msn(card, c->parm.setup.eazmsn, 1);
-			else
-				tmp[0] = c->parm.setup.eazmsn[0];
 			chan->fsm_state = EICON_STATE_OCALL;
-			restore_flags(flags);
+			spin_unlock_irqrestore(&eicon_lock, flags);
 			
 			ret = idi_connect_req(card, chan, c->parm.setup.phone,
 						     c->parm.setup.eazmsn,
@@ -637,19 +511,7 @@
 				return -ENODEV;
 			if (!(chan = find_channel(card, c->arg & 0x1f)))
 				break;
-			if (strlen(c->parm.num)) {
-				if (card->ptype == ISDN_PTYPE_EURO) {
-					chan->eazmask = eicon_find_msn(card, c->parm.num, 0);
-				}
-				if (card->ptype == ISDN_PTYPE_1TR6) {
-					int i;
-					chan->eazmask = 0;
-					for (i = 0; i < strlen(c->parm.num); i++)
-						if (isdigit(c->parm.num[i]))
-							chan->eazmask |= (1 << (c->parm.num[i] - '0'));
-				}
-			} else
-				chan->eazmask = 0x3ff;
+			chan->eazmask = 0x3ff;
 			eicon_idi_listen_req(card, chan);
 			return 0;
 		case ISDN_CMD_CLREAZ:
@@ -680,8 +542,10 @@
 				break;
 			chan->l3prot = (c->arg >> 8);
 #ifdef CONFIG_ISDN_TTY_FAX
-			if (chan->l3prot == ISDN_PROTO_L3_FCLASS2)
+			if (chan->l3prot == ISDN_PROTO_L3_FCLASS2) {
 				chan->fax = c->parm.fax;
+				eicon_log(card, 128, "idi_cmd: Ch%d: SETL3 struct fax=0x%x\n",chan->No, chan->fax);
+			}
 #endif
 			return 0;
 		case ISDN_CMD_GETL3:
@@ -729,6 +593,23 @@
 				break;
 			idi_audio_cmd(card, chan, c->arg >> 8, c->parm.num);
 			return 0;
+		case CAPI_PUT_MESSAGE:
+			if (!card->flags & EICON_FLAGS_RUNNING)
+				return -ENODEV;
+			if (!(chan = find_channel(card, c->arg & 0x1f)))
+				break;
+			if (c->parm.cmsg.Length < 8)
+				break;
+			switch(c->parm.cmsg.Command) {
+				case CAPI_FACILITY:
+					if (c->parm.cmsg.Subcommand == CAPI_REQ)
+						return(capipmsg(card, chan, &c->parm.cmsg));
+					break;
+				case CAPI_MANUFACTURER:
+				default:
+					break;
+			}
+			return 0;
         }
 	
         return -EINVAL;
@@ -787,8 +668,7 @@
                 if (!card->flags & EICON_FLAGS_RUNNING)
                         return -ENODEV;
 	
-		save_flags(flags);
-		cli();
+		spin_lock_irqsave(&eicon_lock, flags);
 		while((skb = skb_dequeue(&card->statq))) {
 
 			if ((skb->len + count) > len)
@@ -811,12 +691,12 @@
 			} else {
 				skb_pull(skb, cnt);
 				skb_queue_head(&card->statq, skb);
-				restore_flags(flags);
+				spin_unlock_irqrestore(&eicon_lock, flags);
 				return count;
 			}
 		}
 		card->statq_entries = 0;
-		restore_flags(flags);
+		spin_unlock_irqrestore(&eicon_lock, flags);
 		return count;
         }
         printk(KERN_ERR
@@ -848,7 +728,7 @@
 			}
 			else
 #endif
-				ret = idi_send_data(card, chan, ack, skb, 1);
+				ret = idi_send_data(card, chan, ack, skb, 1, 1);
 			return (ret);
 		} else {
 			return -ENODEV;
@@ -895,12 +775,11 @@
 			return;
 	}
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&eicon_lock, flags);
 	count = strlen(buf);
 	skb = alloc_skb(count, GFP_ATOMIC);
 	if (!skb) {
-		restore_flags(flags);
+		spin_unlock_irqrestore(&eicon_lock, flags);
 		printk(KERN_ERR "eicon: could not alloc skb in putstatus\n");
 		return;
 	}
@@ -918,7 +797,7 @@
 	} else
 		card->statq_entries++;
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&eicon_lock, flags);
         if (count) {
                 cmd.command = ISDN_STAT_STAVAIL;
                 cmd.driver = card->myid;
@@ -967,7 +846,7 @@
  * link it into cards-list.
  */
 static void
-eicon_alloccard(int Type, int membase, int irq, char *id)
+eicon_alloccard(int Type, int membase, int irq, char *id, int card_id)
 {
 	int i;
 	int j;
@@ -976,9 +855,6 @@
 	char qid[5];
 #endif
         eicon_card *card;
-#if CONFIG_PCI
-	eicon_pci_card *pcic;
-#endif
 
 	qloop = (Type == EICON_CTYPE_QUADRO)?2:0;
 	for (i = 0; i <= qloop; i++) {
@@ -1088,9 +964,9 @@
 				card->interface.channels = 1;
 				break;
 #endif
-#if CONFIG_PCI
+#ifdef CONFIG_PCI
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
 			case EICON_CTYPE_MAESTRA:
-				(eicon_pci_card *)pcic = (eicon_pci_card *)membase;
                                 card->bus = EICON_BUS_PCI;
 				card->interface.features |=
 					ISDN_FEATURE_L2_V11096 |
@@ -1101,11 +977,26 @@
 					ISDN_FEATURE_L3_TRANSDSP |
 					ISDN_FEATURE_L3_FCLASS2;
                                 card->hwif.pci.card = (void *)card;
-				card->hwif.pci.PCIreg = pcic->PCIreg;
-				card->hwif.pci.PCIcfg = pcic->PCIcfg;
-                                card->hwif.pci.master = 1;
-                                card->hwif.pci.mvalid = pcic->mvalid;
-                                card->hwif.pci.ivalid = 0;
+                                card->hwif.pci.master = card_id;
+                                card->hwif.pci.irq = irq;
+                                card->hwif.pci.type = Type;
+				card->flags = 0;
+                                card->nchannels = 2;
+				card->interface.channels = 1;
+				break;
+
+			case EICON_CTYPE_MAESTRAQ:
+                                card->bus = EICON_BUS_PCI;
+				card->interface.features |=
+					ISDN_FEATURE_L2_V11096 |
+					ISDN_FEATURE_L2_V11019 |
+					ISDN_FEATURE_L2_V11038 |
+					ISDN_FEATURE_L2_MODEM |
+					ISDN_FEATURE_L2_FAX | 
+					ISDN_FEATURE_L3_TRANSDSP |
+					ISDN_FEATURE_L3_FCLASS2;
+                                card->hwif.pci.card = (void *)card;
+                                card->hwif.pci.master = card_id;
                                 card->hwif.pci.irq = irq;
                                 card->hwif.pci.type = Type;
 				card->flags = 0;
@@ -1114,7 +1005,6 @@
 				break;
 
 			case EICON_CTYPE_MAESTRAP:
-				(eicon_pci_card *)pcic = (eicon_pci_card *)membase;
                                 card->bus = EICON_BUS_PCI;
 				card->interface.features |=
 					ISDN_FEATURE_L2_V11096 |
@@ -1125,13 +1015,7 @@
 					ISDN_FEATURE_L3_TRANSDSP |
 					ISDN_FEATURE_L3_FCLASS2;
                                 card->hwif.pci.card = (void *)card;
-                                card->hwif.pci.shmem = (eicon_pci_shmem *)pcic->shmem;
-				card->hwif.pci.PCIreg = pcic->PCIreg;
-				card->hwif.pci.PCIram = pcic->PCIram;
-				card->hwif.pci.PCIcfg = pcic->PCIcfg;
-                                card->hwif.pci.master = 1;
-                                card->hwif.pci.mvalid = pcic->mvalid;
-                                card->hwif.pci.ivalid = 0;
+                                card->hwif.pci.master = card_id;
                                 card->hwif.pci.irq = irq;
                                 card->hwif.pci.type = Type;
 				card->flags = 0;
@@ -1139,6 +1023,7 @@
 				card->interface.channels = 1;
 				break;
 #endif
+#endif
 #ifdef CONFIG_ISDN_DRV_EICON_ISA
 			case EICON_CTYPE_ISABRI:
 				if (membase == -1)
@@ -1197,6 +1082,53 @@
 			skb_queue_head_init(&card->bch[j].e.X);
 			skb_queue_head_init(&card->bch[j].e.R);
 		}
+
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
+		/* *** Diva Server *** */
+		if (!(card->dbuf = (DBUFFER *) kmalloc((sizeof(DBUFFER) * (card->nchannels + 1))*2
+							 , GFP_KERNEL))) {
+			eicon_log(card, 1,
+			       "eicon: (%s) Could not allocate DBUFFER-struct.\n", id);
+			kfree(card);
+			kfree(card->bch);
+			return;
+		}
+		if (!(card->sbuf = (BUFFERS *) kmalloc((sizeof(BUFFERS) * (card->nchannels + 1)) * 2, GFP_KERNEL))) {
+			eicon_log(card, 1,
+			       "eicon: (%s) Could not allocate BUFFERS-struct.\n", id);
+			kfree(card);
+			kfree(card->bch);
+			kfree(card->dbuf);
+			return;
+		}
+		if (!(card->sbufp = (char *) kmalloc((270 * (card->nchannels + 1)) * 2, GFP_KERNEL))) {
+			eicon_log(card, 1,
+			       "eicon: (%s) Could not allocate BUFFERSP-struct.\n", id);
+			kfree(card);
+			kfree(card->bch);
+			kfree(card->dbuf);
+			kfree(card->sbuf);
+			return;
+		}
+		for (j=0; j< (card->nchannels + 1); j++) {
+			memset((char *)&card->dbuf[j], 0, sizeof(DBUFFER));
+			card->bch[j].de.RBuffer = (DBUFFER *)&card->dbuf[j];
+			memset((char *)&card->dbuf[j+(card->nchannels+1)], 0, sizeof(BUFFERS));
+			card->bch[j].be.RBuffer = (DBUFFER *)&card->dbuf[j+(card->nchannels+1)];
+
+			memset((char *)&card->sbuf[j], 0, sizeof(BUFFERS));
+			card->bch[j].de.X = (BUFFERS *)&card->sbuf[j];
+			memset((char *)&card->sbuf[j+(card->nchannels+1)], 0, sizeof(BUFFERS));
+			card->bch[j].be.X = (BUFFERS *)&card->sbuf[j+(card->nchannels+1)];
+
+			memset((char *)&card->sbufp[j], 0, 270);
+			card->bch[j].de.X->P = (char *)&card->sbufp[j * 270];
+			memset((char *)&card->sbufp[j+(card->nchannels+1)], 0, 270);
+			card->bch[j].be.X->P = (char *)&card->sbufp[(j+(card->nchannels+1)) * 270];
+		}
+		/* *** */
+#endif /* CONFIG_ISDN_DRV_EICON_PCI */
+
 		card->next = cards;
 		cards = card;
 	}
@@ -1220,10 +1152,7 @@
 #endif /* CONFIG_MCA */
 #endif
 		case EICON_BUS_PCI:
-#if CONFIG_PCI
-			eicon_pci_printpar(&card->hwif.pci); 
 			break;
-#endif
 		default:
 			eicon_log(card, 1,
 			       "eicon_registercard: Illegal BUS type %d\n",
@@ -1241,8 +1170,7 @@
         return 0;
 }
 
-#ifdef MODULE
-static void
+static void 
 unregister_card(eicon_card * card)
 {
         isdn_ctrl cmd;
@@ -1260,10 +1188,7 @@
 			break;
 #endif
 		case EICON_BUS_PCI:
-#if CONFIG_PCI
-			eicon_pci_release(&card->hwif.pci);
 			break;
-#endif
 		default:
 			eicon_log(card, 1,
 			       "eicon: Invalid BUS type %d\n",
@@ -1271,7 +1196,6 @@
 			break;
         }
 }
-#endif /* MODULE */
 
 static void
 eicon_freecard(eicon_card *card) {
@@ -1295,13 +1219,17 @@
 	while((skb = skb_dequeue(&card->statq)))
 		dev_kfree_skb(skb);
 
-	eicon_clear_msn(card);
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
+	kfree(card->sbufp);
+	kfree(card->sbuf);
+	kfree(card->dbuf);
+#endif
 	kfree(card->bch);
 	kfree(card);
 }
 
 int
-eicon_addcard(int Type, int membase, int irq, char *id)
+eicon_addcard(int Type, int membase, int irq, char *id, int card_id)
 {
 	eicon_card *p;
 	eicon_card *q = NULL;
@@ -1314,7 +1242,7 @@
 		if ((Type = eicon_isa_find_card(membase, irq, id)) < 0)
 			return 0;
 #endif
-	eicon_alloccard(Type, membase, irq, id);
+	eicon_alloccard(Type, membase, irq, id, card_id);
         p = cards;
         while (p) {
 		registered = 0;
@@ -1333,12 +1261,14 @@
 					break;
 #endif
 				case EICON_BUS_PCI:
-#if CONFIG_PCI
+#ifdef CONFIG_PCI
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
 					if (eicon_registercard(p))
 						break;
 					registered = 1;
 					break;
 #endif
+#endif
 				default:
 					printk(KERN_ERR
 					       "eicon: addcard: Invalid BUS type %d\n",
@@ -1371,46 +1301,35 @@
         return (added - failed);
 }
 
-#define DRIVERNAME "Eicon active ISDN driver"
-#define DRIVERRELEASE "1"
 
-#ifdef MODULE
-#define eicon_init init_module
-#endif
-
-int
+static int __init
 eicon_init(void)
 {
 	int card_count = 0;
-	int release = 0;
 	char tmprev[50];
 
 	DebugVar = 1;
+	eicon_lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
 
         printk(KERN_INFO "%s Rev: ", DRIVERNAME);
 	strcpy(tmprev, eicon_revision);
 	printk("%s/", eicon_getrev(tmprev));
-	release += getrel(tmprev);
 	strcpy(tmprev, eicon_pci_revision);
-#if CONFIG_PCI
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
 	printk("%s/", eicon_getrev(tmprev));
 #else
 	printk("---/");
 #endif
-	release += getrel(tmprev);
 	strcpy(tmprev, eicon_isa_revision);
 #ifdef CONFIG_ISDN_DRV_EICON_ISA
 	printk("%s/", eicon_getrev(tmprev));
 #else
 	printk("---/");
 #endif
-	release += getrel(tmprev);
 	strcpy(tmprev, eicon_idi_revision);
 	printk("%s\n", eicon_getrev(tmprev));
-	release += getrel(tmprev);
-	sprintf(tmprev,"%d", release);
-        printk(KERN_INFO "%s Release: %s.%s%s\n", DRIVERNAME,
-		DRIVERRELEASE, tmprev, DRIVERPATCH);
+        printk(KERN_INFO "%s Release: %s%s\n", DRIVERNAME,
+		DRIVERRELEASE, DRIVERPATCH);
 
 #ifdef CONFIG_ISDN_DRV_EICON_ISA
 #ifdef CONFIG_MCA
@@ -1427,18 +1346,23 @@
                        card_count++;
         };
 #else
-	card_count = eicon_addcard(0, membase, irq, id);
+	card_count = eicon_addcard(0, membase, irq, id, 0);
 #endif /* CONFIG_MCA */
 #endif /* CONFIG_ISDN_DRV_EICON_ISA */
  
-#if CONFIG_PCI
+#ifdef CONFIG_PCI
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
+	DivasCardsDiscover();
 	card_count += eicon_pci_find_card(id);
 #endif
+#endif
+
         if (!cards) {
 #ifdef MODULE
-#ifndef CONFIG_PCI
+#ifndef CONFIG_ISDN_DRV_EICON_PCI
 #ifndef CONFIG_ISDN_DRV_EICON_ISA
                 printk(KERN_INFO "Eicon: Driver is neither ISA nor PCI compiled !\n");
+                printk(KERN_INFO "Eicon: Driver not loaded !\n");
 #else
                 printk(KERN_INFO "Eicon: No cards defined, driver not loaded !\n");
 #endif
@@ -1451,17 +1375,34 @@
 	} else
 		printk(KERN_INFO "Eicon: %d card%s added\n", card_count, 
                        (card_count>1)?"s":"");
-        /* No symbols to export, hide all symbols */
-        EXPORT_NO_SYMBOLS;
         return 0;
 }
 
-#ifdef MODULE
-void
-cleanup_module(void)
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
+void DIVA_DIDD_Write(DESCRIPTOR *, int);
+EXPORT_SYMBOL_NOVERS(DIVA_DIDD_Read);
+EXPORT_SYMBOL_NOVERS(DIVA_DIDD_Write);
+EXPORT_SYMBOL_NOVERS(DivasPrintf);
+#else
+int DivasCardNext;
+card_t DivasCards[1];
+#endif
+
+static void 
+eicon_exit(void)
 {
+#if CONFIG_PCI	
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
+	card_t *pCard;
+	word wCardIndex;
+	extern int Divas_major;
+	int iTmp = 0;
+#endif
+#endif
+	
         eicon_card *card = cards;
         eicon_card *last;
+
         while (card) {
 #ifdef CONFIG_ISDN_DRV_EICON_ISA
 #ifdef CONFIG_MCA
@@ -1481,10 +1422,58 @@
                 card = card->next;
 		eicon_freecard(last);
         }
+
+#if CONFIG_PCI	
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
+	pCard = DivasCards;
+	for (wCardIndex = 0; wCardIndex < MAX_CARDS; wCardIndex++)
+	{
+		if ((pCard->hw) && (pCard->hw->in_use))
+		{
+			(*pCard->card_reset)(pCard);
+			
+			UxIsrRemove(pCard->hw, pCard);
+			UxCardHandleFree(pCard->hw);
+
+			if(pCard->e_tbl != NULL)
+			{
+				kfree(pCard->e_tbl);
+			}
+
+			if(pCard->hw->card_type == DIA_CARD_TYPE_DIVA_SERVER_B)
+			{
+				release_region(pCard->hw->io_base,0x20);
+				release_region(pCard->hw->reset_base,0x80);
+			}
+
+                        // If this is a 4BRI ...
+                        if (pCard->hw->card_type == DIA_CARD_TYPE_DIVA_SERVER_Q)
+                        {
+                                // Skip over the next 3 virtual adapters
+                                wCardIndex += 3;
+
+                                // But free their handles
+				for (iTmp = 0; iTmp < 3; iTmp++)
+				{
+					pCard++;
+					UxCardHandleFree(pCard->hw);
+
+					if(pCard->e_tbl != NULL)
+					{
+						kfree(pCard->e_tbl);
+					}
+				}
+                        }
+		}
+		pCard++;
+	}
+	unregister_chrdev(Divas_major, "Divas");
+#endif
+#endif /* CONFIG_PCI */
         printk(KERN_INFO "%s unloaded\n", DRIVERNAME);
 }
 
-#else /* no module */
+#ifndef MODULE
 
 void
 eicon_setup(char *str, int *ints)
@@ -1669,7 +1658,7 @@
 			return  ENODEV;
 	};
 	/* matching membase & irq */
-	if ( 1 == eicon_addcard(type, membase, irq, id)) { 
+	if ( 1 == eicon_addcard(type, membase, irq, id, 0)) { 
 		mca_set_adapter_name(slot, eicon_mca_adapters[a_idx].name);
   		mca_set_adapter_procfn(slot, (MCA_ProcFn) eicon_info, cards);
 
@@ -1691,3 +1680,5 @@
 #endif /* CONFIG_MCA */
 #endif /* CONFIG_ISDN_DRV_EICON_ISA */
 
+module_init(eicon_init);
+module_exit(eicon_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/eicon_pci.c linux.19p18/drivers/isdn/eicon/eicon_pci.c
--- linux.vanilla/drivers/isdn/eicon/eicon_pci.c	Fri Apr 21 12:46:09 2000
+++ linux.19p18/drivers/isdn/eicon/eicon_pci.c	Mon Feb 19 18:28:19 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon_pci.c,v 1.11 2000/01/23 21:21:23 armin Exp $
+/* $Id: eicon_pci.c,v 1.15.6.2 2001/02/16 09:09:50 armin Exp $
  *
  * ISDN low-level module for Eicon active ISDN-Cards.
  * Hardware-specific code for PCI cards.
@@ -6,11 +6,9 @@
  * Copyright 1998-2000 by Armin Schindler (mac@melware.de)
  * Copyright 1999,2000 Cytronics & Melware (info@melware.de)
  *
- * Thanks to	Eicon Technology GmbH & Co. oHG for 
+ * Thanks to	Eicon Networks for 
  *		documents, informations and hardware. 
  *
- *		Deutsche Telekom AG for S2M support.
- *
  * 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, or (at your option)
@@ -25,53 +23,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
- * $Log: eicon_pci.c,v $
- * Revision 1.11  2000/01/23 21:21:23  armin
- * Added new trace capability and some updates.
- * DIVA Server BRI now supports data for ISDNLOG.
- *
- * Revision 1.10  1999/08/22 20:26:49  calle
- * backported changes from kernel 2.3.14:
- * - several #include "config.h" gone, others come.
- * - "struct device" changed to "struct net_device" in 2.3.14, added a
- *   define in isdn_compat.h for older kernel versions.
- *
- * Revision 1.9  1999/08/11 21:01:11  keil
- * new PCI codefix
- *
- * Revision 1.8  1999/08/10 16:02:20  calle
- * struct pci_dev changed in 2.3.13. Made the necessary changes.
- *
- * Revision 1.7  1999/06/09 19:31:29  armin
- * Wrong PLX size for request_region() corrected.
- * Added first MCA code from Erik Weber.
- *
- * Revision 1.6  1999/04/01 12:48:37  armin
- * Changed some log outputs.
- *
- * Revision 1.5  1999/03/29 11:19:49  armin
- * I/O stuff now in seperate file (eicon_io.c)
- * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
- *
- * Revision 1.4  1999/03/02 12:37:48  armin
- * Added some important checks.
- * Analog Modem with DSP.
- * Channels will be added to Link-Level after loading firmware.
- *
- * Revision 1.3  1999/01/24 20:14:24  armin
- * Changed and added debug stuff.
- * Better data sending. (still problems with tty's flip buffer)
- *
- * Revision 1.2  1999/01/10 18:46:06  armin
- * Bug with wrong values in HLC fixed.
- * Bytes to send are counted and limited now.
- *
- * Revision 1.1  1999/01/01 18:09:45  armin
- * First checkin of new eicon driver.
- * DIVA-Server BRI/PCI and PRI/PCI are supported.
- * Old diehl code is obsolete.
- *
- *
  */
 
 #include <linux/config.h>
@@ -80,894 +31,90 @@
 #include "eicon.h"
 #include "eicon_pci.h"
 
+#undef N_DATA
+#include "adapter.h"
+#include "uxio.h"
 
-char *eicon_pci_revision = "$Revision: 1.11 $";
+char *eicon_pci_revision = "$Revision: 1.15.6.2 $";
 
 #if CONFIG_PCI	         /* intire stuff is only for PCI */
-
-#undef EICON_PCI_DEBUG 
+#ifdef CONFIG_ISDN_DRV_EICON_PCI
 
 int eicon_pci_find_card(char *ID)
 {
-  if (pci_present()) { 
-    struct pci_dev *pdev = NULL;  
-    int pci_nextindex=0, pci_cards=0, pci_akt=0; 
-    int pci_type = PCI_MAESTRA;
-    int NoMorePCICards = FALSE;
-    char *ram, *reg, *cfg;	
-    unsigned int pram=0, preg=0, pcfg=0;
-    char did[12];
-    eicon_pci_card *aparms;
-
-   if (!(aparms = (eicon_pci_card *) kmalloc(sizeof(eicon_pci_card), GFP_KERNEL))) {
-                  printk(KERN_WARNING
-                      "eicon_pci: Could not allocate card-struct.\n");
-                  return 0;
-   }
-
-  for (pci_cards = 0; pci_cards < 0x0f; pci_cards++)
-  {
-  do {
-      if ((pdev = pci_find_device(PCI_VENDOR_EICON,          
-                                  pci_type,                  
-                                  pdev)))                    
-	{
-              pci_nextindex++;
-              break;
-	}
-	else {
-              pci_nextindex = 0;
-              switch (pci_type) /* switch to next card type */
-               {
-               case PCI_MAESTRA:
-                 pci_type = PCI_MAESTRAQ; break;
-               case PCI_MAESTRAQ:
-                 pci_type = PCI_MAESTRAQ_U; break;
-               case PCI_MAESTRAQ_U:
-                 pci_type = PCI_MAESTRAP; break;
-               default:
-               case PCI_MAESTRAP:
-                 NoMorePCICards = TRUE;
-               }
-	}
-     }
-     while (!NoMorePCICards);
-     if (NoMorePCICards)
-        {
-           if (pci_cards < 1) {
-           printk(KERN_INFO "Eicon: No supported PCI cards found.\n");
-	   kfree(aparms);	
-           return 0;
-           }
-           else
-           {
-           printk(KERN_INFO "Eicon: %d PCI card%s registered.\n",
-			pci_cards, (pci_cards > 1) ? "s":"");
-	   kfree(aparms);	
-           return (pci_cards);
-           }
-        }
-
-   pci_akt = 0;
-   switch(pci_type)
-   {
-    case PCI_MAESTRA:
-         printk(KERN_INFO "Eicon: DIVA Server BRI/PCI detected !\n");
-          aparms->type = EICON_CTYPE_MAESTRA;
-
-          aparms->irq = pdev->irq;
-          preg = pdev->base_address[ 2] & 0xfffffffc;
-          pcfg = pdev->base_address[ 1] & 0xffffff80;
-
-#ifdef EICON_PCI_DEBUG
-          printk(KERN_DEBUG "eicon_pci: irq=%d\n", aparms->irq);
-          printk(KERN_DEBUG "eicon_pci: reg=0x%x\n", preg);
-          printk(KERN_DEBUG "eicon_pci: cfg=0x%x\n", pcfg);
-#endif
-	 pci_akt = 1;
-         break;
+	int pci_cards = 0;
+	int card_id = 0;
+	int had_q = 0;
+	int ctype = 0;
+	char did[20];
+	card_t *pCard;
+	word wCardIndex;
 
-    case PCI_MAESTRAQ:
-    case PCI_MAESTRAQ_U:
-         printk(KERN_ERR "Eicon: DIVA Server 4BRI/PCI detected but not supported !\n");
-         pci_cards--;
-	 pci_akt = 0;
-         break;
-
-    case PCI_MAESTRAP:
-         printk(KERN_INFO "Eicon: DIVA Server PRI/PCI detected !\n");
-          aparms->type = EICON_CTYPE_MAESTRAP; /*includes 9M,30M*/
-          aparms->irq = pdev->irq;
-          pram = pdev->base_address[ 0] & 0xfffff000;
-          preg = pdev->base_address[ 2] & 0xfffff000;
-          pcfg = pdev->base_address[ 4] & 0xfffff000;
-
-#ifdef EICON_PCI_DEBUG
-          printk(KERN_DEBUG "eicon_pci: irq=%d\n", aparms->irq);
-          printk(KERN_DEBUG "eicon_pci: ram=0x%x\n",
-               (pram));
-          printk(KERN_DEBUG "eicon_pci: reg=0x%x\n",
-               (preg));
-          printk(KERN_DEBUG "eicon_pci: cfg=0x%x\n",
-               (pcfg));
-#endif
-	  pci_akt = 1;
-	  break;	
-    default:
-         printk(KERN_ERR "eicon_pci: Unknown PCI card detected !\n");
-         pci_cards--;
-	 pci_akt = 0;
-	 break;
-   }
-
-	if (pci_akt) {
-		/* remapping memory */
-		switch(pci_type)
+	pCard = DivasCards;
+	for (wCardIndex = 0; wCardIndex < MAX_CARDS; wCardIndex++)
+	{
+	if ((pCard->hw) && (pCard->hw->in_use))
 		{
-    		case PCI_MAESTRA:
-			aparms->PCIreg = (unsigned int) preg;
-			aparms->PCIcfg = (unsigned int) pcfg;
-			if (check_region((aparms->PCIreg), 0x20)) {
-				printk(KERN_WARNING "eicon_pci: reg port already in use !\n");
-				aparms->PCIreg = 0;
-				break;	
-			} else {
-				request_region(aparms->PCIreg, 0x20, "eicon reg");
-			}
-			if (check_region((aparms->PCIcfg), 0x80)) {
-				printk(KERN_WARNING "eicon_pci: cfg port already in use !\n");
-				aparms->PCIcfg = 0;
-				release_region(aparms->PCIreg, 0x20);
-				break;	
-			} else {
-				request_region(aparms->PCIcfg, 0x80, "eicon cfg");
+			switch(pCard->hw->card_type) {
+				case DIA_CARD_TYPE_DIVA_SERVER:
+					ctype = EICON_CTYPE_MAESTRAP;
+					card_id++;
+					had_q = 0;
+					break;
+				case DIA_CARD_TYPE_DIVA_SERVER_B:
+					ctype = EICON_CTYPE_MAESTRA;
+					card_id++;
+					had_q = 0;
+					break;
+				case DIA_CARD_TYPE_DIVA_SERVER_Q:
+					ctype = EICON_CTYPE_MAESTRAQ;
+					if (!had_q)
+						card_id++;
+					if (++had_q >=4)
+						had_q = 0;
+					break;
+				default:
+					printk(KERN_ERR "eicon_pci: unknown card type %d !\n",
+						pCard->hw->card_type);
+					goto err;
 			}
-			break;
-    		case PCI_MAESTRAQ:
-		case PCI_MAESTRAQ_U:
-		case PCI_MAESTRAP:
-			aparms->shmem = (eicon_pci_shmem *) ioremap(pram, 0x10000);
-			ram = (u8 *) ((u32)aparms->shmem + MP_SHARED_RAM_OFFSET);
-			reg =  ioremap(preg, 0x4000);
-			cfg =  ioremap(pcfg, 0x1000);	
-			aparms->PCIram = (unsigned int) ram;
-			aparms->PCIreg = (unsigned int) reg;
-			aparms->PCIcfg = (unsigned int) cfg;
-			break;
-		 }
-		if ((!aparms->PCIreg) || (!aparms->PCIcfg)) {
-			printk(KERN_ERR "eicon_pci: Card could not be added !\n");
-			pci_cards--;
-		} else {
-			aparms->mvalid = 1;
-	
 			sprintf(did, "%s%d", (strlen(ID) < 1) ? "eicon":ID, pci_cards);
-
-			printk(KERN_INFO "%s: DriverID: '%s'\n",eicon_ctype_name[aparms->type] , did);
-
-			if (!(eicon_addcard(aparms->type, (int) aparms, aparms->irq, did))) {
+			if ((!ctype) || (!(eicon_addcard(ctype, 0, pCard->hw->irq, did, card_id)))) {
 				printk(KERN_ERR "eicon_pci: Card could not be added !\n");
-				pci_cards--;
+			} else {
+				pci_cards++;
+				printk(KERN_INFO "%s: DriverID='%s' CardID=%d\n",
+					eicon_ctype_name[ctype], did, card_id);
 			}
+err:;
 		}
+		pCard++;
 	}
-
-  }
- } else
-	printk(KERN_ERR "eicon_pci: Kernel compiled with PCI but no PCI-bios found !\n");
- return 0;
-}
-
-/*
- * Checks protocol file id for "F#xxxx" string fragment to
- * extract the features, supported by this protocol version.
- * binary representation of the feature string value is returned
- * in *value. The function returns 0 if feature string was not
- * found or has a wrong format, else 1.
- */
-static int GetProtFeatureValue(char *sw_id, int *value)
-{
-  __u8 i, offset;
-
-  while (*sw_id)
-  {
-    if ((sw_id[0] == 'F') && (sw_id[1] == '#'))
-    {
-      sw_id = &sw_id[2];
-      for (i=0, *value=0; i<4; i++, sw_id++)
-      {
-        if ((*sw_id >= '0') && (*sw_id <= '9'))
-        {
-          offset = '0';
-        }
-        else if ((*sw_id >= 'A') && (*sw_id <= 'F'))
-        {
-          offset = 'A' + 10;
-        }
-        else if ((*sw_id >= 'a') && (*sw_id <= 'f'))
-        {
-          offset = 'a' + 10;
-        }
-        else
-        {
-          return 0;
-        }
-        *value |= (*sw_id - offset) << (4*(3-i));
-      }
-      return 1;
-    }
-    else
-    {
-      sw_id++;
-    }
-  }
-  return 0;
-}
-
-
-void
-eicon_pci_printpar(eicon_pci_card *card) {
-        switch (card->type) {
-                case EICON_CTYPE_MAESTRA:
-			printk(KERN_INFO "%s at 0x%x / 0x%x, irq %d\n",
-				eicon_ctype_name[card->type],
-				(unsigned int)card->PCIreg,
-				(unsigned int)card->PCIcfg,
-				card->irq); 
-			break;
-                case EICON_CTYPE_MAESTRAQ:
-                case EICON_CTYPE_MAESTRAQ_U:
-                case EICON_CTYPE_MAESTRAP:
-			printk(KERN_INFO "%s at 0x%x, irq %d\n",
-				eicon_ctype_name[card->type],
-				(unsigned int)card->shmem,
-				card->irq); 
-#ifdef EICON_PCI_DEBUG
-		        printk(KERN_INFO "eicon_pci: remapped ram= 0x%x\n",(unsigned int)card->PCIram);
-		        printk(KERN_INFO "eicon_pci: remapped reg= 0x%x\n",(unsigned int)card->PCIreg);
-		        printk(KERN_INFO "eicon_pci: remapped cfg= 0x%x\n",(unsigned int)card->PCIcfg); 
-#endif
-			break;
-	}
-}
-
-
-static void
-eicon_pci_release_shmem(eicon_pci_card *card) {
-	if (!card->master)
-		return;
-	if (card->mvalid) {
-        	switch (card->type) {
-                	case EICON_CTYPE_MAESTRA:
-			        /* reset board */
-				outb(0, card->PCIcfg + 0x4c);	/* disable interrupts from PLX */
-				outb(0, card->PCIreg + M_RESET);
-				SLEEP(20);
-				outb(0, card->PCIreg + M_ADDRH);
-				outw(0, card->PCIreg + M_ADDR);
-				outw(0, card->PCIreg + M_DATA);
-
-				release_region(card->PCIreg, 0x20);
-				release_region(card->PCIcfg, 0x80);
-				break;
-                	case EICON_CTYPE_MAESTRAQ:
-	                case EICON_CTYPE_MAESTRAQ_U:
-	                case EICON_CTYPE_MAESTRAP:
-			        /* reset board */
-		        	writeb(_MP_RISC_RESET | _MP_LED1 | _MP_LED2, card->PCIreg + MP_RESET);
-			        SLEEP(20);
-			        writeb(0, card->PCIreg + MP_RESET);
-			        SLEEP(20);
-
-				iounmap((void *)card->shmem);
-				iounmap((void *)card->PCIreg);
-				iounmap((void *)card->PCIcfg);
-				break;
-		}
-	}
-	card->mvalid = 0;
-}
-
-static void
-eicon_pci_release_irq(eicon_pci_card *card) {
-	if (!card->master)
-		return;
-	if (card->ivalid)
-		free_irq(card->irq, card);
-	card->ivalid = 0;
+	return pci_cards;
 }
 
 void
-eicon_pci_release(eicon_pci_card *card) {
-        eicon_pci_release_irq(card);
-        eicon_pci_release_shmem(card);
-}
-
-/*
- * Upload buffer content to adapters shared memory
- * on verify error, 1 is returned and a message is printed on screen
- * else 0 is returned
- * Can serve IO-Type and Memory type adapters
- */
-int eicon_upload(t_dsp_download_space   *p_para,
-            __u16                 length,   /* byte count */
-            __u8                  *buffer,
-            int                   verify)
-{
-  __u32               i, dwdata = 0, val = 0, timeout;
-  __u16               data;
-  eicon_pci_boot *boot = 0;
-
-  switch (p_para->type) /* actions depend on type of union */
-  {
-    case DL_PARA_IO_TYPE:
-      for (i=0; i<length; i+=2)
-      {
-	outb ((u8) ((p_para->dat.io.r3addr + i) >> 16), p_para->dat.io.ioADDRH);
-	outw ((u16) (p_para->dat.io.r3addr + i), p_para->dat.io.ioADDR); 
-	/* outw (((u16 *)code)[i >> 1], p_para->dat.io.ioDATA); */
-	outw (*(u16 *)&buffer[i], p_para->dat.io.ioDATA); 
-      }
-      if (verify) /* check written block */
-      {
-        for (i=0; i<length; i+=2)
-        {
-	  outb ((u8) ((p_para->dat.io.r3addr + i) >> 16), p_para->dat.io.ioADDRH);
-          outw ((u16) (p_para->dat.io.r3addr + i), p_para->dat.io.ioADDR); 
-          data = inw(p_para->dat.io.ioDATA);
-          if (data != *(u16 *)&buffer[i])
-          {
-            p_para->dat.io.r3addr  += i;
-            p_para->dat.io.BadData  = data;
-            p_para->dat.io.GoodData = *(u16 *)&buffer[i];
-            return 1;
-          }
-        }
-      }
-      break;
-
-    case DL_PARA_MEM_TYPE:
-      boot = p_para->dat.mem.boot;
-      writel(p_para->dat.mem.r3addr, &boot->addr);
-      for (i=0; i<length; i+=4)
-      {
-        writel(((u32 *)buffer)[i >> 2], &boot->data[i]);
-      }
-      if (verify) /* check written block */
-      {
-        for (i=0; i<length; i+=4)
-        {
-          dwdata = readl(&boot->data[i]);
-          if (((u32 *)buffer)[i >> 2] != dwdata)
-          {
-            p_para->dat.mem.r3addr  += i;
-            p_para->dat.mem.BadData  = dwdata;
-            p_para->dat.mem.GoodData = ((u32 *)buffer)[i >> 2];
-            return 1;
-          }
-        }
-      }
-      writel(((length + 3) / 4), &boot->len);  /* len in dwords */
-      writel(2, &boot->cmd);
-
-	timeout = jiffies + 20;
-	while (timeout > jiffies) {
-		val = readl(&boot->cmd);
-		if (!val) break;
-		SLEEP(2);
-	}
-	if (val)
-         {
-		p_para->dat.mem.timeout = 1;
-		return 1;
-	 }
-      break;
-  }
-  return 0;
-}
-
-
-/* show header information of code file */
-static
-int eicon_pci_print_hdr(unsigned char *code, int offset)
+eicon_pci_init_conf(eicon_card *card)
 {
-  unsigned char hdr[80];
-  int i, fvalue = 0;
-
-  i = 0;
-  while ((i < (sizeof(hdr) -1))
-          && (code[offset + i] != '\0')
-          && (code[offset + i] != '\r')
-          && (code[offset + i] != '\n'))
-   {
-     hdr[i] = code[offset + i];
-     i++;
-   }
-   hdr[i] = '\0';
-   printk(KERN_DEBUG "Eicon: loading %s\n", hdr);
-   if (GetProtFeatureValue(hdr, &fvalue)) return(fvalue);
-    else return(0);
-}
-
+	int j;
 
-/*
- * Configure a card, download code into BRI card,
- * check if we get interrupts and return 0 on succes.
- * Return -ERRNO on failure.
- */
-int
-eicon_pci_load_bri(eicon_pci_card *card, eicon_pci_codebuf *cb) {
-        int               i,j;
-        int               timeout;
-	unsigned int	  offset, offp=0, size, length;
-	int		  signature = 0;
-	int		  FeatureValue = 0;
-        eicon_pci_codebuf cbuf;
-	t_dsp_download_space dl_para;
-	t_dsp_download_desc  dsp_download_table;
-        unsigned char     *code;
-	unsigned int	  reg;
-	unsigned int	  cfg;
-
-        if (copy_from_user(&cbuf, cb, sizeof(eicon_pci_codebuf)))
-                return -EFAULT;
-
-	reg = card->PCIreg;
-	cfg = card->PCIcfg;
-
-	/* reset board */
-	outb(0, reg + M_RESET);
-	SLEEP(10);
-	outb(0, reg + M_ADDRH);
-	outw(0, reg + M_ADDR);
-	outw(0, reg + M_DATA);
-
-#ifdef EICON_PCI_DEBUG
-	 printk(KERN_DEBUG "eicon_pci: reset card\n");
-#endif
+	/* initializing some variables */
+	card->ReadyInt = 0;
 
-	/* clear shared memory */
-	outb(0xff, reg + M_ADDRH);
-	outw(0, reg + M_ADDR);
-	for(i = 0; i < 0xffff; i++) outw(0, reg + M_DATA);
-	SLEEP(10);
+	for(j = 0; j < 256; j++)
+		card->IdTable[j] = NULL;
 
-#ifdef EICON_PCI_DEBUG
-	 printk(KERN_DEBUG "eicon_pci: clear shared memory\n");
-#endif
-
-	/* download protocol and dsp file */
-
-#ifdef EICON_PCI_DEBUG
-	printk(KERN_DEBUG "eicon_pci: downloading firmware...\n");
-#endif
-
-       	/* Allocate code-buffer */
-       	if (!(code = kmalloc(400, GFP_KERNEL))) {
-                printk(KERN_WARNING "eicon_pci_boot: Couldn't allocate code buffer\n");
-       	        return -ENOMEM;
-        }
-
-	/* prepare protocol upload */
-	dl_para.type		= DL_PARA_IO_TYPE;
-	dl_para.dat.io.ioADDR	= reg + M_ADDR;
-	dl_para.dat.io.ioADDRH	= reg + M_ADDRH;
-	dl_para.dat.io.ioDATA	= reg + M_DATA;
-
-	for (j = 0; j <= cbuf.dsp_code_num; j++) 
-	 {	
-	   if (j == 0)  size = cbuf.protocol_len;
-	           else size = cbuf.dsp_code_len[j];
-
-        	offset = 0;
-
-		if (j == 0) dl_para.dat.io.r3addr = 0;
-		if (j == 1) dl_para.dat.io.r3addr = M_DSP_CODE_BASE +
-					((sizeof(__u32) + (sizeof(dsp_download_table) * 35) + 3) &0xfffffffc);
-		if (j == 2) dl_para.dat.io.r3addr = M_DSP_CODE_BASE;
-		if (j == 3) dl_para.dat.io.r3addr = M_DSP_CODE_BASE + sizeof(__u32);
-
-           do  /* download block of up to 400 bytes */
-            {
-              length = ((size - offset) >= 400) ? 400 : (size - offset);
-
-        	if (copy_from_user(code, (&cb->code) + offp + offset, length)) {
-                	kfree(code);
-	                return -EFAULT;
-        	}
-
-		if ((offset == 0) && (j < 2)) {
-		       	FeatureValue = eicon_pci_print_hdr(code, j ? 0x00 : 0x80); 
-#ifdef EICON_PCI_DEBUG
-	if (FeatureValue) printk(KERN_DEBUG "eicon_pci: Feature Value : 0x%04x.\n", FeatureValue);
-#endif
-			if ((j==0) && (!(FeatureValue & PROTCAP_TELINDUS))) {
-                  		printk(KERN_ERR "eicon_pci: Protocol Code cannot handle Telindus\n");
-				kfree(code);
-		                return -EFAULT;
-			}
-                	((eicon_card *)card->card)->Feature = FeatureValue;
-		}
-
-		if (eicon_upload(&dl_para, length, code, 1))
-		{
-                  printk(KERN_ERR "eicon_pci: code block check failed at 0x%x !\n",dl_para.dat.io.r3addr);
-		  kfree(code);
-                  return -EIO;
-		}
-              /* move onto next block */
-              offset += length;
-	      dl_para.dat.io.r3addr += length;
-            } while (offset < size);
-
-#ifdef EICON_PCI_DEBUG
-	printk(KERN_DEBUG "Eicon: %d bytes loaded.\n", offset);
-#endif
-	offp += size;
+	for(j = 0; j < (card->d->channels + 1); j++) {
+		card->bch[j].e.busy = 0;
+		card->bch[j].e.D3Id = 0;
+		card->bch[j].e.B2Id = 0;
+		card->bch[j].e.ref = 0;
+		card->bch[j].e.Req = 0;
+		card->bch[j].e.complete = 1;
+		card->bch[j].fsm_state = EICON_STATE_NULL;
 	}
-	kfree(code);	
-
-	/* clear signature */
-	outb(0xff, reg + M_ADDRH);
-	outw(0x1e, reg + M_ADDR);
-	outw(0, reg + M_DATA);
-
-#ifdef EICON_PCI_DEBUG
-	printk(KERN_DEBUG "eicon_pci: copy configuration data into shared memory...\n");
-#endif
-	/* copy configuration data into shared memory */
-	outw(8, reg + M_ADDR); outb(cbuf.tei, reg + M_DATA);
-	outw(9, reg + M_ADDR); outb(cbuf.nt2, reg + M_DATA);
-	outw(10,reg + M_ADDR); outb(0, reg + M_DATA);
-	outw(11,reg + M_ADDR); outb(cbuf.WatchDog, reg + M_DATA);
-	outw(12,reg + M_ADDR); outb(cbuf.Permanent, reg + M_DATA);
-	outw(13,reg + M_ADDR); outb(0, reg + M_DATA);                 /* XInterface */
-	outw(14,reg + M_ADDR); outb(cbuf.StableL2, reg + M_DATA);
-	outw(15,reg + M_ADDR); outb(cbuf.NoOrderCheck, reg + M_DATA);
-	outw(16,reg + M_ADDR); outb(0, reg + M_DATA);                 /* HandsetType */
-	outw(17,reg + M_ADDR); outb(0, reg + M_DATA);                 /* SigFlags */
-	outw(18,reg + M_ADDR); outb(cbuf.LowChannel, reg + M_DATA);
-	outw(19,reg + M_ADDR); outb(cbuf.ProtVersion, reg + M_DATA);
-	outw(20,reg + M_ADDR); outb(cbuf.Crc4, reg + M_DATA);
-	outw(21,reg + M_ADDR); outb((cbuf.Loopback) ? 2:0, reg + M_DATA);
-
-	for (i=0;i<32;i++)
-	{
-		outw( 32+i, reg + M_ADDR); outb(cbuf.l[0].oad[i], reg + M_DATA);
-		outw( 64+i, reg + M_ADDR); outb(cbuf.l[0].osa[i], reg + M_DATA);
-		outw( 96+i, reg + M_ADDR); outb(cbuf.l[0].spid[i], reg + M_DATA);
-		outw(128+i, reg + M_ADDR); outb(cbuf.l[1].oad[i], reg + M_DATA);
-		outw(160+i, reg + M_ADDR); outb(cbuf.l[1].osa[i], reg + M_DATA);
-		outw(192+i, reg + M_ADDR); outb(cbuf.l[1].spid[i], reg + M_DATA);
-	}
-
-#ifdef EICON_PCI_DEBUG
-           printk(KERN_ERR "eicon_pci: starting CPU...\n");
-#endif
-	/* let the CPU run */
-	outw(0x08, reg + M_RESET);
-
-        timeout = jiffies + (5*HZ);
-        while (timeout > jiffies) {
-	   outw(0x1e, reg + M_ADDR);	
-           signature = inw(reg + M_DATA);
-           if (signature == DIVAS_SIGNATURE) break;
-           SLEEP(2);
-         }
-        if (signature != DIVAS_SIGNATURE)
-         {
-#ifdef EICON_PCI_DEBUG
-           printk(KERN_ERR "eicon_pci: signature 0x%x expected 0x%x\n",signature,DIVAS_SIGNATURE);
-#endif
-           printk(KERN_ERR "eicon_pci: Timeout, protocol code not running !\n");
-           return -EIO; 
-         }
-#ifdef EICON_PCI_DEBUG
-        printk(KERN_DEBUG "eicon_pci: Protocol code running, signature OK\n");
-#endif
-
-        /* get serial number and number of channels supported by card */
-	outb(0xff, reg + M_ADDRH);
-	outw(0x3f6, reg + M_ADDR);
-        card->channels = inw(reg + M_DATA);
-        card->serial = (u32)inw(cfg + 0x22) << 16 | (u32)inw(cfg + 0x26);
-        printk(KERN_INFO "Eicon: Supported channels : %d\n", card->channels);
-        printk(KERN_INFO "Eicon: Card serial no. = %lu\n", card->serial);
-
-        /* test interrupt */
-        card->irqprobe = 1;
-
-        if (!card->ivalid) {
-                if (request_irq(card->irq, &eicon_irq, 0, "Eicon PCI ISDN", card->card))
-                 {
-                  printk(KERN_ERR "eicon_pci: Couldn't request irq %d\n", card->irq);
-                  return -EIO;
-                 }
-        }
-        card->ivalid = 1;
-
-#ifdef EICON_PCI_DEBUG
-        printk(KERN_DEBUG "eicon_pci: testing interrupt\n");
-#endif
-        /* Trigger an interrupt and check if it is delivered */
-        outb(0x41, cfg + 0x4c);		/* enable PLX for interrupts */
-	outb(0x89, reg + M_RESET);	/* place int request */
-
-        timeout = jiffies + 20;
-        while (timeout > jiffies) {
-          if (card->irqprobe != 1) break;
-          SLEEP(5);
-         }
-        if (card->irqprobe == 1) {
-           free_irq(card->irq, card); 
-           card->ivalid = 0; 
-           printk(KERN_ERR "eicon_pci: Getting no interrupts !\n");
-           return -EIO;
-         }
-
-   /* initializing some variables */
-   ((eicon_card *)card->card)->ReadyInt = 0;
-   for(j=0; j<256; j++) ((eicon_card *)card->card)->IdTable[j] = NULL;
-   for(j=0; j< (card->channels + 1); j++) {
-                ((eicon_card *)card->card)->bch[j].e.busy = 0;
-                ((eicon_card *)card->card)->bch[j].e.D3Id = 0;
-                ((eicon_card *)card->card)->bch[j].e.B2Id = 0;
-                ((eicon_card *)card->card)->bch[j].e.ref = 0;
-                ((eicon_card *)card->card)->bch[j].e.Req = 0;
-                ((eicon_card *)card->card)->bch[j].e.complete = 1;
-                ((eicon_card *)card->card)->bch[j].fsm_state = EICON_STATE_NULL;
-   }
-
-   printk(KERN_INFO "Eicon: Card successfully started\n");
-
- return 0;
 }
 
-
-/*
- * Configure a card, download code into PRI card,
- * check if we get interrupts and return 0 on succes.
- * Return -ERRNO on failure.
- */
-int
-eicon_pci_load_pri(eicon_pci_card *card, eicon_pci_codebuf *cb) {
-        eicon_pci_boot    *boot;
-	eicon_pr_ram  *prram;
-        int               i,j;
-        int               timeout;
-	int		  FeatureValue = 0;
-	unsigned int	  offset, offp=0, size, length;
-	unsigned long int signature = 0;
-	t_dsp_download_space dl_para;
-	t_dsp_download_desc  dsp_download_table;
-        eicon_pci_codebuf cbuf;
-        unsigned char     *code;
-	unsigned char	  req_int;
-    	char *ram, *reg, *cfg;	
-
-        if (copy_from_user(&cbuf, cb, sizeof(eicon_pci_codebuf)))
-                return -EFAULT;
-
-        boot = &card->shmem->boot;
-	ram = (char *)card->PCIram;
-	reg = (char *)card->PCIreg;
-	cfg = (char *)card->PCIcfg;
-	prram = (eicon_pr_ram *)ram;
-
-	/* reset board */
-	writeb(_MP_RISC_RESET | _MP_LED1 | _MP_LED2, card->PCIreg + MP_RESET);
-	SLEEP(20);
-	writeb(0, card->PCIreg + MP_RESET);
-	SLEEP(20);
-
-	/* set command count to 0 */
-	writel(0, &boot->reserved); 
-
-	/* check if CPU increments the life word */
-        i = readw(&boot->live);
-        SLEEP(20);
-        if (i == readw(&boot->live)) {
-           printk(KERN_ERR "eicon_pci: card is reset, but CPU not running !\n");
-           return -EIO;
-         }
-#ifdef EICON_PCI_DEBUG
-	 printk(KERN_DEBUG "eicon_pci: reset card OK (CPU running)\n");
-#endif
-
-	/* download firmware : DSP and Protocol */
-#ifdef EICON_PCI_DEBUG
-	printk(KERN_DEBUG "eicon_pci: downloading firmware...\n");
 #endif
-
-       	/* Allocate code-buffer */
-       	if (!(code = kmalloc(400, GFP_KERNEL))) {
-                printk(KERN_WARNING "eicon_pci_boot: Couldn't allocate code buffer\n");
-       	        return -ENOMEM;
-        }
-
-	/* prepare protocol upload */
-	dl_para.type		= DL_PARA_MEM_TYPE;
-	dl_para.dat.mem.boot	= boot;
-
-        for (j = 0; j <= cbuf.dsp_code_num; j++)
-         {
-	   if (j==0) size = cbuf.protocol_len;
-		else size = cbuf.dsp_code_len[j];	
-
-           if (j==1) writel(MP_DSP_ADDR, &boot->addr); /* DSP code entry point */
-
-		if (j == 0) dl_para.dat.io.r3addr = MP_PROTOCOL_ADDR;
-		if (j == 1) dl_para.dat.io.r3addr = MP_DSP_CODE_BASE +
-					((sizeof(__u32) + (sizeof(dsp_download_table) * 35) + 3) &0xfffffffc);
-		if (j == 2) dl_para.dat.io.r3addr = MP_DSP_CODE_BASE;
-		if (j == 3) dl_para.dat.io.r3addr = MP_DSP_CODE_BASE + sizeof(__u32);
-
-           offset = 0;
-           do  /* download block of up to 400 bytes */
-            {
-              length = ((size - offset) >= 400) ? 400 : (size - offset);
-
-        	if (copy_from_user(code, (&cb->code) + offp + offset, length)) {
-                	kfree(code);
-	                return -EFAULT;
-        	}
-
-		if ((offset == 0) && (j < 2)) {
-	           	FeatureValue = eicon_pci_print_hdr(code, j ? 0x00 : 0x80); 
-#ifdef EICON_PCI_DEBUG
-	if (FeatureValue) printk(KERN_DEBUG "eicon_pci: Feature Value : 0x%x.\n", FeatureValue);
-#endif
-			if ((j==0) && (!(FeatureValue & PROTCAP_TELINDUS))) {
-                  		printk(KERN_ERR "eicon_pci: Protocol Code cannot handle Telindus\n");
-				kfree(code);
-		                return -EFAULT;
-			}
-                	((eicon_card *)card->card)->Feature = FeatureValue;
-		}
-
-		if (eicon_upload(&dl_para, length, code, 1))
-		{
-		  if (dl_para.dat.mem.timeout == 0)
-	                  printk(KERN_ERR "eicon_pci: code block check failed at 0x%x !\n",dl_para.dat.io.r3addr);
-			else
-			  printk(KERN_ERR "eicon_pci: timeout, no ACK to load !\n");
-		  kfree(code);
-                  return -EIO;
-		}
-
-              /* move onto next block */
-              offset += length;
-	      dl_para.dat.mem.r3addr += length;
-            } while (offset < size);
-#ifdef EICON_PCI_DEBUG
-	printk(KERN_DEBUG "eicon_pci: %d bytes loaded.\n", offset);
-#endif
-	 offp += size;
-         }
-	 kfree(code);	
-
-	/* initialize the adapter data structure */
-#ifdef EICON_PCI_DEBUG
-	printk(KERN_DEBUG "eicon_pci: copy configuration data into shared memory...\n");
-#endif
-        /* clear out config space */
-        for (i = 0; i < 256; i++) writeb(0, &ram[i]);
-
-        /* copy configuration down to the card */
-        writeb(cbuf.tei, &ram[8]);
-        writeb(cbuf.nt2, &ram[9]);
-        writeb(0, &ram[10]);
-        writeb(cbuf.WatchDog, &ram[11]);
-        writeb(cbuf.Permanent, &ram[12]);
-        writeb(cbuf.XInterface, &ram[13]);
-        writeb(cbuf.StableL2, &ram[14]);
-        writeb(cbuf.NoOrderCheck, &ram[15]);
-        writeb(cbuf.HandsetType, &ram[16]);
-        writeb(0, &ram[17]);
-        writeb(cbuf.LowChannel, &ram[18]);
-        writeb(cbuf.ProtVersion, &ram[19]);
-        writeb(cbuf.Crc4, &ram[20]);
-        for (i = 0; i < 32; i++)
-         {
-           writeb(cbuf.l[0].oad[i], &ram[32 + i]);
-           writeb(cbuf.l[0].osa[i], &ram[64 + i]);
-           writeb(cbuf.l[0].spid[i], &ram[96 + i]);
-           writeb(cbuf.l[1].oad[i], &ram[128 + i]);
-           writeb(cbuf.l[1].osa[i], &ram[160 + i]);
-           writeb(cbuf.l[1].spid[i], &ram[192 + i]);
-         }
-#ifdef EICON_PCI_DEBUG
-	printk(KERN_DEBUG "eicon_pci: configured card OK\n");
-#endif
-
-	/* start adapter */
-#ifdef EICON_PCI_DEBUG
-	printk(KERN_DEBUG "eicon_pci: tell card to start...\n");
-#endif
-        writel(MP_PROTOCOL_ADDR, &boot->addr); /* RISC code entry point */
-        writel(3, &boot->cmd); /* DIVAS_START_CMD */
-
-        /* wait till card ACKs */
-        timeout = jiffies + (5*HZ);
-        while (timeout > jiffies) {
-           signature = readl(&boot->signature);
-           if ((signature >> 16) == DIVAS_SIGNATURE) break;
-           SLEEP(2);
-         }
-        if ((signature >> 16) != DIVAS_SIGNATURE)
-         {
-#ifdef EICON_PCI_DEBUG
-           printk(KERN_ERR "eicon_pci: signature 0x%lx expected 0x%x\n",(signature >> 16),DIVAS_SIGNATURE);
-#endif
-           printk(KERN_ERR "eicon_pci: timeout, protocol code not running !\n");
-           return -EIO;
-         }
-#ifdef EICON_PCI_DEBUG
-	printk(KERN_DEBUG "eicon_pci: Protocol code running, signature OK\n");
-#endif
-
-	/* get serial number and number of channels supported by card */
-        card->channels = readb(&ram[0x3f6]);
-        card->serial = readl(&ram[0x3f0]);
-        printk(KERN_INFO "Eicon: Supported channels : %d\n", card->channels);
-        printk(KERN_INFO "Eicon: Card serial no. = %lu\n", card->serial);
-
-	/* test interrupt */
-	readb(&ram[0x3fe]);
-        writeb(0, &ram[0x3fe]); /* reset any pending interrupt */
-	readb(&ram[0x3fe]);
-
-        writew(MP_IRQ_RESET_VAL, &cfg[MP_IRQ_RESET]);
-        writew(0, &cfg[MP_IRQ_RESET + 2]);
-
-        card->irqprobe = 1;
-
-	if (!card->ivalid) {
-	        if (request_irq(card->irq, &eicon_irq, 0, "Eicon PCI ISDN", card->card)) 
-        	 {
-	          printk(KERN_ERR "eicon_pci: Couldn't request irq %d\n", card->irq);
-        	  return -EIO;
-	         }
-	}
-	card->ivalid = 1;
-
-        req_int = readb(&prram->ReadyInt);
-#ifdef EICON_PCI_DEBUG
-	printk(KERN_DEBUG "eicon_pci: testing interrupt\n");
-#endif
-        req_int++;
-        /* Trigger an interrupt and check if it is delivered */
-        writeb(req_int, &prram->ReadyInt);
-
-        timeout = jiffies + 20;
-        while (timeout > jiffies) {
-          if (card->irqprobe != 1) break;
-          SLEEP(2);
-         }
-        if (card->irqprobe == 1) {
-           free_irq(card->irq, card);
-	   card->ivalid = 0;
-           printk(KERN_ERR "eicon_pci: Getting no interrupts !\n");
-           return -EIO;
-         }
-
-   /* initializing some variables */
-   ((eicon_card *)card->card)->ReadyInt = 0;
-   for(j=0; j<256; j++) ((eicon_card *)card->card)->IdTable[j] = NULL;
-   for(j=0; j< (card->channels + 1); j++) {
-		((eicon_card *)card->card)->bch[j].e.busy = 0;
-		((eicon_card *)card->card)->bch[j].e.D3Id = 0;
-		((eicon_card *)card->card)->bch[j].e.B2Id = 0;
-		((eicon_card *)card->card)->bch[j].e.ref = 0;
-		((eicon_card *)card->card)->bch[j].e.Req = 0;
-                ((eicon_card *)card->card)->bch[j].e.complete = 1;
-                ((eicon_card *)card->card)->bch[j].fsm_state = EICON_STATE_NULL;
-   }
-
-   printk(KERN_INFO "Eicon: Card successfully started\n");
-
- return 0;
-}
-
 #endif	/* CONFIG_PCI */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/eicon_pci.h linux.19p18/drivers/isdn/eicon/eicon_pci.h
--- linux.vanilla/drivers/isdn/eicon/eicon_pci.h	Fri Apr 21 12:46:09 2000
+++ linux.19p18/drivers/isdn/eicon/eicon_pci.h	Mon Feb 19 18:28:20 2001
@@ -1,4 +1,4 @@
-/* $Id: eicon_pci.h,v 1.4 2000/01/23 21:21:23 armin Exp $
+/* $Id: eicon_pci.h,v 1.6 2000/05/07 08:51:04 armin Exp $
  *
  * ISDN low-level module for Eicon active ISDN-Cards (PCI part).
  *
@@ -19,26 +19,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
- * $Log: eicon_pci.h,v $
- * Revision 1.4  2000/01/23 21:21:23  armin
- * Added new trace capability and some updates.
- * DIVA Server BRI now supports data for ISDNLOG.
- *
- * Revision 1.3  1999/03/29 11:19:51  armin
- * I/O stuff now in seperate file (eicon_io.c)
- * Old ISA type cards (S,SX,SCOM,Quadro,S2M) implemented.
- *
- * Revision 1.2  1999/03/02 12:37:50  armin
- * Added some important checks.
- * Analog Modem with DSP.
- * Channels will be added to Link-Level after loading firmware.
- *
- * Revision 1.1  1999/01/01 18:09:46  armin
- * First checkin of new eicon driver.
- * DIVA-Server BRI/PCI and PRI/PCI are supported.
- * Old diehl code is obsolete.
- *
- *
  */
 
 #ifndef eicon_pci_h
@@ -46,147 +26,20 @@
 
 #ifdef __KERNEL__
 
-
-#define PCI_VENDOR_EICON        0x1133
-#define PCI_DIVA_PRO20          0xe001	/* Not supported */
-#define PCI_DIVA20              0xe002	/* Not supported */
-#define PCI_DIVA_PRO20_U        0xe003	/* Not supported */
-#define PCI_DIVA20_U            0xe004	/* Not supported */
-#define PCI_MAESTRA             0xe010
-#define PCI_MAESTRAQ            0xe012
-#define PCI_MAESTRAQ_U          0xe013
-#define PCI_MAESTRAP            0xe014
-
-#define DIVA_PRO20          1
-#define DIVA20              2
-#define DIVA_PRO20_U        3
-#define DIVA20_U            4
-#define MAESTRA             5
-#define MAESTRAQ            6
-#define MAESTRAQ_U          7
-#define MAESTRAP            8
-
-#define TRUE  1
-#define FALSE 0
-
-#define DIVAS_SIGNATURE 0x4447
-
-
-/* MAESTRA BRI PCI */
-
-#define M_RESET		0x10		/* offset of reset register */
-#define M_DATA		0x00		/* offset of data register */
-#define M_ADDR		0x04		/* offset of address register */
-#define M_ADDRH		0x0c		/* offset of high address register */
-
-#define M_DSP_CODE_LEN            0xbf7d0000
-#define M_DSP_CODE                0xbf7d0004  /* max 128K DSP-Code */ 
-#define M_DSP_CODE_BASE           0xbf7a0000  
-#define M_MAX_DSP_CODE_SIZE       0x00050000  /* max 320K DSP-Code (Telindus) */
-
-
-
-/* MAESTRA PRI PCI */
-
-#define MP_SHARED_RAM_OFFSET 0x1000  /* offset of shared RAM base in the DRAM memory bar */
-
-#define MP_IRQ_RESET     0xc18       /* offset of interrupt status register in the CONFIG memory bar */
-#define MP_IRQ_RESET_VAL 0xfe        /* value to clear an interrupt */
-
-#define MP_PROTOCOL_ADDR 0xa0011000  /* load address of protocol code */
-#define MP_DSP_ADDR      0xa03c0000  /* load address of DSP code */
-#define MP_MAX_PROTOCOL_CODE_SIZE  0x000a0000   /* max 640K Protocol-Code */
-#define MP_DSP_CODE_BASE           0xa03a0000
-#define MP_MAX_DSP_CODE_SIZE       0x00060000   /* max 384K DSP-Code */
-
-#define MP_RESET         0x20        /* offset of RESET register in the DEVICES memory bar */
-
-/* RESET register bits */
-#define _MP_S2M_RESET    0x10        /* active lo   */
-#define _MP_LED2         0x08        /* 1 = on      */
-#define _MP_LED1         0x04        /* 1 = on      */
-#define _MP_DSP_RESET    0x02        /* active lo   */
-#define _MP_RISC_RESET   0x81        /* active hi, bit 7 for compatibility with old boards */
-
-/* boot interface structure */
-typedef struct {
-	__u32 cmd	__attribute__ ((packed));
-	__u32 addr	__attribute__ ((packed));
-	__u32 len	__attribute__ ((packed));
-	__u32 err	__attribute__ ((packed));
-	__u32 live	__attribute__ ((packed));
-	__u32 reserved[(0x1020>>2)-6] __attribute__ ((packed));
-	__u32 signature	__attribute__ ((packed));
-	__u8 data[1];    /* real interface description */
-} eicon_pci_boot;
-
-
-#define DL_PARA_IO_TYPE   0
-#define DL_PARA_MEM_TYPE  1
-
-typedef struct tag_dsp_download_space
-{
-  __u16 type;  /* see definitions above to differ union elements */
-  union
-  {
-    struct
-    {
-      __u32               r3addr;
-      __u16               ioADDR;
-      __u16               ioADDRH;
-      __u16               ioDATA;
-      __u16               BadData;  /* in case of verify error */
-      __u16               GoodData;
-    } io;     /* for io based adapters */
-    struct
-    {
-      __u32               r3addr;
-      eicon_pci_boot	  *boot;
-      __u32               BadData;  /* in case of verify error */
-      __u32               GoodData;
-      __u16               timeout;
-    } mem;    /* for memory based adapters */
-  } dat;
-} t_dsp_download_space;
-
-
-/* Shared memory */
-typedef union {
-	eicon_pci_boot boot;
-} eicon_pci_shmem;
-
 /*
  * card's description
  */
 typedef struct {
-	int		  ramsize;
 	int   		  irq;	    /* IRQ		          */
-	unsigned int      PCIram;
-	unsigned int	  PCIreg;
-	unsigned int	  PCIcfg;
-	long int   	  serial;   /* Serial No.		  */
 	int		  channels; /* No. of supported channels  */
         void*             card;
-        eicon_pci_shmem*  shmem;    /* Shared-memory area         */
-        unsigned char*    intack;   /* Int-Acknowledge            */
-        unsigned char*    stopcpu;  /* Writing here stops CPU     */
-        unsigned char*    startcpu; /* Writing here starts CPU    */
         unsigned char     type;     /* card type                  */
-        unsigned char     irqprobe; /* Flag: IRQ-probing          */
-        unsigned char     mvalid;   /* Flag: Memory is valid      */
-        unsigned char     ivalid;   /* Flag: IRQ is valid         */
         unsigned char     master;   /* Flag: Card is Quadro 1/4   */
-        void*             generic;  /* Ptr to generic card struct */
 } eicon_pci_card;
 
-
-
-extern int eicon_pci_load_pri(eicon_pci_card *card, eicon_pci_codebuf *cb);
-extern int eicon_pci_load_bri(eicon_pci_card *card, eicon_pci_codebuf *cb);
-extern void eicon_pci_release(eicon_pci_card *card);
-extern void eicon_pci_printpar(eicon_pci_card *card);
 extern int eicon_pci_find_card(char *ID);
 
 #endif  /* __KERNEL__ */
 
 #endif	/* eicon_pci_h */
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/fourbri.c linux.19p18/drivers/isdn/eicon/fourbri.c
--- linux.vanilla/drivers/isdn/eicon/fourbri.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/eicon/fourbri.c	Mon Feb 19 18:28:20 2001
@@ -0,0 +1,573 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.7  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+/* Diva Server 4BRI specific part of initialisation */
+#include "sys.h"
+#include "idi.h"
+#include "divas.h"
+#include "pc.h"
+#include "pr_pc.h"
+#include "dsp_defs.h"
+#include "constant.h"
+#include "adapter.h"
+#include "uxio.h"
+
+#define TEST_INT_DIVAS_Q	0x13
+
+#define	DIVAS_MAINT_OFFSET	0xff00	/* value for 4BRI card */
+#define MQ_BOARD_DSP_OFFSET 0x00a00000
+#define MQ_DSP1_ADDR_OFFSET 0x00000008
+#define MQ_DSP_JUNK_OFFSET  0x00000400
+#define MQ_DSP1_DATA_OFFSET 0x00000000
+#define MQ_BOARD_ISAC_DSP_RESET  0x00800028
+#define MQ_BREG_RISC  0x1200      /* RISC Reset */
+#define MQ_ISAC_DSP_RESET 0x0028 /* ISAC and DSP reset address offset */
+#define MQ_RISC_COLD_RESET_MASK         0x0001      /* RISC Cold reset                        */
+#define MQ_RISC_WARM_RESET_MASK         0x0002      /* RISC Warm reset                        */
+#define MQ_IRQ_REQ_ON                   0x1
+#define MQ_IRQ_REQ_OFF                  0x0
+#define MQ_BREG_IRQ_TEST                0x0608
+#define PLX9054_INTCSR      0x69 
+#define PLX9054_INT_ENA     0x09
+
+#define DIVAS_IOBASE	0x01
+#define M_PCI_RESET	0x10
+
+byte mem_in(ADAPTER *a, void *adr);
+word mem_inw(ADAPTER *a, void *adr);
+void mem_in_buffer(ADAPTER *a, void *adr, void *P, word length);
+void mem_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e);
+void mem_out(ADAPTER *a, void *adr, byte data);
+void mem_outw(ADAPTER *a, void *adr, word data);
+void mem_out_buffer(ADAPTER *a, void *adr, void *P, word length);
+void mem_inc(ADAPTER *a, void *adr);
+
+int Divas4BRIInitPCI(card_t *card, dia_card_t *cfg);
+static int fourbri_ISR (card_t* card);
+
+int FPGA_Download(word, dword, byte *, byte *, int);
+extern byte FPGA_Bytes[];
+extern void *get_card(int);
+
+byte UxCardPortIoIn(ux_diva_card_t *card, byte *base, int offset);
+void UxCardPortIoOut(ux_diva_card_t *card, byte *base, int offset, byte);
+word GetProtFeatureValue(char *sw_id);
+
+void memcp(byte *dst, byte *src, dword dwLen);
+int memcm(byte *dst, byte *src, dword dwLen);
+
+static int diva_server_4bri_reset(card_t *card)
+{
+	byte *ctl;
+
+	DPRINTF(("divas: reset Diva Server 4BRI"));
+
+	ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY);
+
+	/* stop RISC, DSP's and ISAC  */
+   UxCardMemOut(card->hw, &ctl[MQ_BREG_RISC], 0);
+   UxCardMemOut(card->hw, &ctl[MQ_ISAC_DSP_RESET], 0);
+
+	UxCardMemDetach(card->hw, ctl);
+
+	return 0;
+}
+
+static int diva_server_4bri_config(card_t *card, dia_config_t *config)
+{
+	byte *shared;
+	int i, j;
+
+	DPRINTF(("divas: configure Diva Server 4BRI"));
+
+	shared = (byte *) UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+	
+	for (i=0; i<256; i++)
+	{
+		UxCardMemOut(card->hw, &shared[i], 0);
+	}
+
+	UxCardMemOut(card->hw, &shared[ 8], config->tei);
+	UxCardMemOut(card->hw, &shared[ 9], config->nt2);
+	UxCardMemOut(card->hw, &shared[10], config->sig_flags);
+	UxCardMemOut(card->hw, &shared[11], config->watchdog);
+	UxCardMemOut(card->hw, &shared[12], config->permanent);
+	UxCardMemOut(card->hw, &shared[13], config->x_interface);
+	UxCardMemOut(card->hw, &shared[14], config->stable_l2);
+	UxCardMemOut(card->hw, &shared[15], config->no_order_check);
+	UxCardMemOut(card->hw, &shared[16], config->handset_type);
+	UxCardMemOut(card->hw, &shared[17], 0);
+	UxCardMemOut(card->hw, &shared[18], config->low_channel);
+	UxCardMemOut(card->hw, &shared[19], config->prot_version);
+	UxCardMemOut(card->hw, &shared[20], config->crc4);
+
+	if ((card->hw->features) && (card->hw->features & PROTCAP_V90D))
+	{
+		DPRINTF(("divas: Signifying V.90"));
+		UxCardMemOut(card->hw, &shared[22], 4);
+	}
+	else
+	{
+		UxCardMemOut(card->hw, &shared[22], 0);
+	}
+
+	for (i=0; i<2; i++)
+	{
+		for (j=0; j<32; j++)
+		{
+			UxCardMemOut(card->hw, &shared[32+(i*96)+j],config->terminal[i].oad[j]);
+		}
+
+		for (j=0; j<32; j++)
+		{
+			UxCardMemOut(card->hw, &shared[64+(i*96)+j],config->terminal[i].osa[j]);
+		}
+
+		for (j=0; j<32; j++)
+		{
+			UxCardMemOut(card->hw, &shared[96+(i*96)+j],config->terminal[i].spid[j]);
+		}
+	}
+
+	UxCardMemDetach(card->hw, shared);
+
+	return 0;
+}
+
+static
+void diva_server_4bri_reset_int(card_t *card)
+{
+	byte *ctl;
+
+	ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY);
+
+	UxCardMemOut(card->hw, &ctl[MQ_BREG_IRQ_TEST], MQ_IRQ_REQ_OFF);
+
+	UxCardMemDetach(card->hw, ctl);
+
+	return;
+}
+
+ 
+static int diva_server_4bri_test_int(card_t *card)
+{
+	byte *ctl, i;
+	byte *reg;
+
+	DPRINTF(("divas: test interrupt for Diva Server 4BRI"));
+
+	/* We get the last (dummy) adapter in so we need to go back to the first */
+
+	card = get_card(card->cfg.card_id - 3);
+
+	/* Enable interrupts on PLX chip */
+
+	reg = UxCardMemAttach(card->hw, DIVAS_REG_MEMORY);
+
+	UxCardPortIoOut(card->hw, reg, PLX9054_INTCSR, PLX9054_INT_ENA);
+
+	UxCardMemDetach(card->hw, reg);
+
+	/* Set the test interrupt flag */
+	card->test_int_pend = TEST_INT_DIVAS_Q;
+
+	/* Now to trigger the interrupt */
+
+	ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY);
+
+	UxCardMemOut(card->hw, &ctl[MQ_BREG_IRQ_TEST], MQ_IRQ_REQ_ON);
+
+	UxCardMemDetach(card->hw, ctl);
+
+	for (i = 0; i < 50; i++)
+	{
+		if (!card->test_int_pend)
+		{
+			break;
+		}
+		UxPause(10);
+	}
+
+	if (card->test_int_pend)
+	{
+		DPRINTF(("active: timeout waiting for card to interrupt"));
+		return (-1);
+	}
+	
+	return 0;
+}
+
+
+static void print_hdr(unsigned char *code, int offset)
+{
+	unsigned char hdr[80];
+	int i;
+
+	i = 0;
+
+	while ((i < (DIM(hdr) -1)) && 
+		(code[offset + i] != '\0') &&
+		(code[offset + i] != '\r') &&
+		(code[offset + i] != '\n'))
+	{
+		hdr[i] = code[offset + i];
+		i++;
+	}
+
+	hdr[i] = '\0';
+
+	DPRINTF(("divas: loading %s", hdr));
+}
+
+static int diva_server_4bri_load(card_t *card, dia_load_t *load)
+{
+	byte *pRAM=NULL;
+	int download_offset=0;
+	card_t *FirstCard;
+	byte sw_id[80];
+
+	DPRINTF(("divas: loading Diva Server 4BRI[%d]", load->card_id));
+
+	switch(load->code_type)
+	{
+		case DIA_CPU_CODE:
+			DPRINTF(("divas: RISC code"));
+			print_hdr(load->code, 0x80);
+			card->hw->features = GetProtFeatureValue((char *)&load->code[0x80]);
+			download_offset = 0; // Protocol code written to offset 0
+			pRAM = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY);
+			break;
+
+		case DIA_DSP_CODE:
+			DPRINTF(("divas: DSP code"));
+			print_hdr(load->code, 0x0); 
+			FirstCard = get_card(load->card_id - 3);
+			if ((card->hw->features) && (card->hw->features & PROTCAP_V90D))
+			{
+				download_offset = MQ_V90D_DSP_CODE_BASE;
+			}
+			else
+			{
+				download_offset = MQ_ORG_DSP_CODE_BASE;
+			}
+			pRAM = UxCardMemAttach(FirstCard->hw, DIVAS_RAM_MEMORY);
+			download_offset += (((sizeof(dword) + (sizeof(t_dsp_download_desc)* DSP_MAX_DOWNLOAD_COUNT)) + 3) & 0xFFFFFFFC);
+
+			break;
+
+		case DIA_TABLE_CODE:
+			DPRINTF(("divas: TABLE code"));
+			FirstCard = get_card(load->card_id - 3);
+			if ((card->hw->features) && (card->hw->features & PROTCAP_V90D))
+			{
+				download_offset = MQ_V90D_DSP_CODE_BASE + sizeof(dword);
+			}
+			else
+			{
+				download_offset = MQ_ORG_DSP_CODE_BASE + sizeof(dword);
+			}
+			pRAM = UxCardMemAttach(FirstCard->hw, DIVAS_RAM_MEMORY);
+			break;
+
+		case DIA_CONT_CODE:
+			DPRINTF(("divas: continuation code"));
+			break;
+
+        case DIA_DLOAD_CNT:
+			DPRINTF(("divas: COUNT code"));
+			FirstCard = get_card(load->card_id - 3);
+			if ((card->hw->features) && (card->hw->features & PROTCAP_V90D))
+			{
+				download_offset = MQ_V90D_DSP_CODE_BASE;
+			}
+			else
+			{
+				download_offset = MQ_ORG_DSP_CODE_BASE;
+			}
+			pRAM = UxCardMemAttach(FirstCard->hw, DIVAS_RAM_MEMORY);
+			break;
+
+		case DIA_FPGA_CODE:
+			DPRINTF(("divas: 4BRI FPGA download - %d bytes", load->length));
+			if (FPGA_Download(IDI_ADAPTER_MAESTRAQ,
+ 			card->hw->io_base,
+			 sw_id,
+			 load->code,
+			 load->length
+			) == -1)
+			{
+				DPRINTF(("divas: FPGA download failed"));
+				return -1;
+			}
+
+			/* NOW reset the 4BRI */
+			diva_server_4bri_reset(card);
+			return 0; // No need for anything further loading
+
+		default:
+			DPRINTF(("divas: unknown code type"));
+			return -1;
+	}
+
+   memcp(pRAM + (download_offset & 0x3FFFFF), load->code, load->length);
+
+	{
+		int mism_off;
+	if ((mism_off = memcm(pRAM + (download_offset & 0x3FFFFF), load->code, load->length)))
+	{
+		DPRINTF(("divas: memory mismatch at offset %d", mism_off));
+		UxCardMemDetach(card->hw, pRAM);
+		return -1;
+	}
+	}
+
+	UxCardMemDetach(card->hw, pRAM);
+
+	return 0;
+}
+
+static int diva_server_4bri_start(card_t *card, byte *channels)
+{
+	byte *ctl;
+	byte *shared, i;
+	int adapter_num;
+
+	DPRINTF(("divas: start Diva Server 4BRI"));
+	*channels = 0;
+	card->is_live = FALSE;
+
+	ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY);
+
+	UxCardMemOutW(card->hw, &ctl[MQ_BREG_RISC], MQ_RISC_COLD_RESET_MASK);
+
+	UxPause(2);
+
+	UxCardMemOutW(card->hw, &ctl[MQ_BREG_RISC], MQ_RISC_WARM_RESET_MASK | MQ_RISC_COLD_RESET_MASK);
+
+	UxPause(10);
+	
+	UxCardMemDetach(card->hw, ctl);
+
+	shared = (byte *) UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+	for ( i = 0 ; i < 300 ; ++i )
+	{
+		UxPause (10) ;
+
+		if ( UxCardMemInW(card->hw, &shared[0x1E]) == 0x4447 )
+		{
+			DPRINTF(("divas: Protocol startup time %d.%02d seconds",
+			         (i / 100), (i % 100) ));
+
+			break;
+		}
+	}
+
+	if (i==300)
+	{
+		DPRINTF(("divas: Timeout starting card"));
+		DPRINTF(("divas: Signature == 0x%04X", UxCardMemInW(card->hw, &shared[0x1E])));
+
+		UxCardMemDetach(card->hw, shared);
+		return -1;
+	}
+
+	UxCardMemDetach(card->hw, shared);
+
+	for (adapter_num=3; adapter_num >= 0; adapter_num--)
+	{
+		card_t *qbri_card;
+
+		qbri_card = get_card(card->cfg.card_id - adapter_num);
+
+		if (qbri_card)
+		{
+			qbri_card->is_live = TRUE;
+			shared = UxCardMemAttach(qbri_card->hw, DIVAS_SHARED_MEMORY);
+			*channels += UxCardMemIn(qbri_card->hw, &shared[0x3F6]);
+			UxCardMemDetach(qbri_card->hw, shared);
+		}
+		else
+		{
+			DPRINTF(("divas: Couldn't get card info %d", card->cfg.card_id));
+		}
+	}
+
+	diva_server_4bri_test_int(card);
+
+	return 0;
+}
+
+static
+int 	diva_server_4bri_mem_get(card_t *card, mem_block_t *mem_block)
+
+{
+	byte	*a;
+	byte	*card_addr;
+	word	length = 0;
+	int		i;
+
+	a = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY);
+
+	card_addr = a;
+	card_addr += mem_block->addr;
+
+	for (i=0; i < sizeof(mem_block->data); i++)
+	{
+		mem_block->data[i] = UxCardMemIn(card->hw, card_addr);
+		card_addr++;
+		length++;
+	}
+
+	UxCardMemDetach(card->hw, a);
+
+	return length;
+}
+
+/*
+ * Initialise 4BRI specific entry points
+ */
+
+int Divas4BriInit(card_t *card, dia_card_t *cfg)
+{
+//	byte sw_id[80];
+//	extern int FPGA_Done;
+
+	DPRINTF(("divas: initialise Diva Server 4BRI"));
+
+	if (Divas4BRIInitPCI(card, cfg) == -1)
+	{
+		return -1;
+	}
+
+	/* Need to download the FPGA */
+/*	if (!FPGA_Done)
+	{
+		int retVal;
+
+		retVal=FPGA_Download(IDI_ADAPTER_MAESTRAQ,
+ 			cfg->io_base,
+			 sw_id,
+			 FPGA_Bytes
+			);
+		if(retVal==-1)
+		{
+		
+			DPRINTF(("divas: FPGA Download Failed"));
+			return -1;
+
+		}
+		FPGA_Done = 1;
+	} */
+
+	card->card_reset = diva_server_4bri_reset;
+	card->card_load = diva_server_4bri_load;
+	card->card_config = diva_server_4bri_config;
+	card->card_start = diva_server_4bri_start;
+	card->reset_int = diva_server_4bri_reset_int;
+	card->card_mem_get = diva_server_4bri_mem_get;
+
+	card->xlog_offset = DIVAS_MAINT_OFFSET;
+
+	card->out = DivasOut;
+	card->test_int = DivasTestInt;
+	card->dpc = DivasDpc;
+	card->clear_int = DivasClearInt;
+	card->card_isr = fourbri_ISR;
+
+	card->a.ram_out = mem_out;
+	card->a.ram_outw = mem_outw;
+	card->a.ram_out_buffer = mem_out_buffer;
+	card->a.ram_inc = mem_inc;
+
+	card->a.ram_in = mem_in;
+	card->a.ram_inw = mem_inw;
+	card->a.ram_in_buffer = mem_in_buffer;
+	card->a.ram_look_ahead = mem_look_ahead;
+
+	return 0;
+}
+
+void memcp(byte *dst, byte *src, dword dwLen)
+{
+	while (dwLen)
+	{
+		*dst = *src;
+		dst++; src++;
+		dwLen--;
+	}
+}
+
+int memcm(byte *dst, byte *src, dword dwLen)
+{
+	int offset = 0;
+
+	while (offset < dwLen)
+	{
+		if(*dst != *src)
+			return (offset+1);
+
+		offset++;
+		src++;
+		dst++;
+	}
+
+	return 0;
+}
+
+
+
+/*int fourbri_ISR (card_t* card) 
+{
+	int served = 0;
+	byte *DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE);
+	
+
+	if (UxCardPortIoIn (card->hw, DivasIOBase, M_PCI_RESET) & 0x01) 
+	{
+		served = 1;
+		card->int_pend  += 1;
+		DivasDpcSchedule(); 
+		UxCardPortIoOut (card->hw, DivasIOBase, M_PCI_RESET, 0x08);
+	}
+
+	UxCardMemDetach(card->hw, DivasIOBase);
+
+	return (served != 0);
+}*/
+
+
+static int fourbri_ISR (card_t* card) 
+{
+	byte *ctl;
+
+	card->int_pend  += 1;
+	DivasDpcSchedule(); /* ISR DPC */
+
+	ctl = UxCardMemAttach(card->hw, DIVAS_CTL_MEMORY);
+	UxCardMemOut(card->hw, &ctl[MQ_BREG_IRQ_TEST], MQ_IRQ_REQ_OFF);
+	UxCardMemDetach(card->hw, ctl);
+
+	return (1);
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/fpga.c linux.19p18/drivers/isdn/eicon/fpga.c
--- linux.vanilla/drivers/isdn/eicon/fpga.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/eicon/fpga.c	Mon Feb 19 18:28:20 2001
@@ -0,0 +1,155 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.2  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+#include "sys.h"
+#include "idi.h"
+#include "uxio.h"
+
+#define FPGA_PORT		0x6E
+#define FPGA_DLOAD_BUFLEN   	256
+#define NAME_OFFSET         	0x10
+#define NAME_MAXLEN         	12
+#define DATE_OFFSET         	0x2c
+#define DATE_MAXLEN         	10
+
+word UxCardPortIoInW(ux_diva_card_t *card, byte *base, int offset);
+void UxCardPortIoOutW(ux_diva_card_t *card, byte *base, int offset, word);
+void UxPause(long int);
+
+/*-------------------------------------------------------------------------*/
+/* Loads the FPGA configuration file onto the hardware.                    */
+/* Function returns 0 on success, else an error number.                    */
+/* On success, an identifier string is returned in the buffer              */
+/*                                                                         */
+/* A buffer of FPGA_BUFSIZE, a handle to the already opened bitstream      */
+/* file and a file read function has to be provided by the operating       */
+/* system part.                                                            */
+/* ----------------------------------------------------------------------- */
+int FPGA_Download( word      cardtype,
+                        dword     RegBase,
+                        byte *strbuf,
+                        byte FPGA_SRC[],
+			int FPGA_LEN
+                      )
+{
+  word        i, j, k;
+  word        baseval, Mask_PROGRAM, Mask_DONE, Mask_CCLK, Mask_DIN;
+  dword       addr;
+  byte        *pFPGA;
+
+  //--- check for legal cardtype
+  switch (cardtype)
+  {
+    case IDI_ADAPTER_MAESTRAQ:
+      addr          = RegBase ; // address where to access FPGA
+      Mask_PROGRAM  = 0x0001;         // FPGA pins at address
+      Mask_DONE     = 0x0002;
+      Mask_CCLK     = 0x0100;
+      Mask_DIN      = 0x0400;
+      baseval       = 0x000d;         // PROGRAM hi, CCLK lo, DIN lo by default
+    break;
+      
+    default:
+	
+  	DPRINTF(("divas: FPGA Download ,Illegal Card"));
+      	return -1; // illegal card 
+  }
+
+  //--- generate id string from file content
+  for (j=NAME_OFFSET, k=0; j<(NAME_OFFSET+NAME_MAXLEN); j++, k++) //name
+  {
+    if (!FPGA_SRC[j]) break;
+    strbuf[k] = FPGA_SRC[j];
+  } 
+  strbuf[k++] = ' ';
+  for (j=DATE_OFFSET; j<(DATE_OFFSET+DATE_MAXLEN); j++, k++) // date
+  {
+    if (!FPGA_SRC[j]) break;
+    strbuf[k] = FPGA_SRC[j];
+  } 
+  strbuf[k] = 0;
+
+  DPRINTF(("divas: FPGA Download - %s", strbuf));
+
+  //--- prepare download, Pulse PROGRAM pin down.
+  UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval &~Mask_PROGRAM);  // PROGRAM low pulse
+  UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval);                 // release
+  UxPause(50);  // wait until FPGA finised internal memory clear
+  
+  //--- check done pin, must be low
+  if (UxCardPortIoInW(NULL, (byte *) addr, FPGA_PORT) &Mask_DONE) 
+  {
+    DPRINTF(("divas: FPGA_ERR_DONE_WRONG_LEVEL"));
+    return -1;
+  }
+
+  pFPGA = FPGA_SRC;
+
+  i = 0; 
+  /* Move past the header */
+  while ((FPGA_SRC[i] != 0xFF) && (i < FPGA_LEN)) 
+  {
+    i++;
+  }
+
+  // We've hit the 0xFF so move on to the next byte
+  // i++;
+  DPRINTF(("divas: FPGA Code starts at offset %d", i));
+
+  //--- put data onto the FPGA
+  for (;i<FPGA_LEN; i++)
+  {
+    //--- put byte onto FPGA
+    for (j=0; j<8; j++)
+    {
+      if (FPGA_SRC[i] &(0x80>>j)) baseval |= Mask_DIN; // write a hi
+      else                      baseval &=~Mask_DIN; // write a lo
+      UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval);
+      UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval | Mask_CCLK);     // set CCLK hi
+      UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval);                 // set CCLK lo
+    }
+  }
+
+  //--- add some additional startup clock cycles and check done pin
+  for (i=0; i<5; i++) 
+  {
+    UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval | Mask_CCLK);     // set CCLK hi
+    UxCardPortIoOutW(NULL, (byte *) addr, FPGA_PORT, baseval);                 // set CCLK lo
+  }
+
+  UxPause(100);
+
+  if (UxCardPortIoInW(NULL, (byte *) addr, FPGA_PORT) &Mask_DONE) 
+  {
+    DPRINTF(("divas: FPGA download successful"));
+  }
+  else
+  {
+    DPRINTF(("divas: FPGA download failed - 0x%x", UxCardPortIoInW(NULL, (byte *) addr, FPGA_PORT)));
+	return -1;
+  }
+
+return 0;
+}
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/idi.c linux.19p18/drivers/isdn/eicon/idi.c
--- linux.vanilla/drivers/isdn/eicon/idi.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/eicon/idi.c	Mon Feb 19 18:28:20 2001
@@ -0,0 +1,867 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.8  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+/*
+ * Core driver for Diva Server cards
+ * Implements the IDI interface
+ */
+
+#include "idi.h"
+#include "adapter.h"
+#include "pc.h"
+#include "pr_pc.h"
+#include "sys.h"
+#include "uxio.h"
+
+/* IDI request functions */
+
+static void	request(card_t *card, ENTITY *e);
+
+static void req_0(ENTITY *e)	{ request(&DivasCards[ 0], e); }
+static void req_1(ENTITY *e)	{ request(&DivasCards[ 1], e); }
+static void req_2(ENTITY *e)	{ request(&DivasCards[ 2], e); }
+static void req_3(ENTITY *e)	{ request(&DivasCards[ 3], e); }
+static void req_4(ENTITY *e)	{ request(&DivasCards[ 4], e); }
+static void req_5(ENTITY *e)	{ request(&DivasCards[ 5], e); }
+static void req_6(ENTITY *e)	{ request(&DivasCards[ 6], e); }
+static void req_7(ENTITY *e)	{ request(&DivasCards[ 7], e); }
+static void req_8(ENTITY *e)	{ request(&DivasCards[ 8], e); }
+static void req_9(ENTITY *e)	{ request(&DivasCards[ 9], e); }
+static void req_10(ENTITY *e)	{ request(&DivasCards[10], e); }
+static void req_11(ENTITY *e)	{ request(&DivasCards[11], e); }
+static void req_12(ENTITY *e)	{ request(&DivasCards[12], e); }
+static void req_13(ENTITY *e)	{ request(&DivasCards[13], e); }
+static void req_14(ENTITY *e)	{ request(&DivasCards[14], e); }
+static void req_15(ENTITY *e)	{ request(&DivasCards[15], e); }
+
+IDI_CALL DivasIdiRequest[16] =
+{
+    &req_0,		&req_1,		&req_2,		&req_3,
+    &req_4,		&req_5,		&req_6,		&req_7,
+    &req_8,		&req_9,		&req_10,	&req_11,
+	&req_12,	&req_13,	&req_14,	&req_15
+};
+
+#define PR_RAM  ((struct pr_ram *)0)
+#define RAM ((struct dual *)0)
+
+/*------------------------------------------------------------------*/
+/* local function prototypes                                        */
+/*------------------------------------------------------------------*/
+
+static byte isdn_rc(ADAPTER *, byte, byte, byte, word);
+static byte isdn_ind(ADAPTER *, byte, byte, byte, PBUFFER *, byte, word);
+
+/*
+ * IDI related functions
+ */
+
+static
+ENTITY	*entity_ptr(ADAPTER *a, byte e_no)
+{
+	card_t	*card;
+
+	card = a->io;
+
+	return card->e_tbl[e_no].e;
+}
+
+static
+void	CALLBACK(ADAPTER *a, ENTITY *e)
+{
+	card_t	*card = a->io;
+
+	if (card->log_types & DIVAS_LOG_IDI)
+	{
+		DivasLogIdi(card, e, FALSE);
+	}
+
+	(*e->callback)(e);
+}
+
+static
+void	*PTR_P(ADAPTER *a, ENTITY *e, void *P)
+{
+	return(P);
+}
+
+static
+void	*PTR_R(ADAPTER *a, ENTITY *e)
+{
+	return((void*)e->R);
+}
+
+static
+void	*PTR_X(ADAPTER *a, ENTITY *e)
+{
+	return((void*)e->X);
+}
+
+static
+void	free_entity(ADAPTER *a, byte e_no) 
+{
+	card_t	*card;
+	int		ipl;
+
+	card = a->io;
+
+	ipl = UxCardLock(card->hw);
+
+	card->e_tbl[e_no].e = NULL;
+	card->e_count--;
+
+	UxCardUnlock(card->hw, ipl);
+
+	return;
+}
+
+static
+void	assign_queue(ADAPTER * a, byte e_no, word ref)
+{
+	card_t	*card;
+	int		ipl;
+
+	card = a->io;
+
+	ipl = UxCardLock(card->hw);
+
+	card->e_tbl[e_no].assign_ref = ref;
+	card->e_tbl[e_no].next = card->assign;
+	card->assign = e_no;
+
+	UxCardUnlock(card->hw, ipl);
+
+	return;
+}
+
+static
+byte	get_assign(ADAPTER *a, word ref)
+{
+	card_t	*card;
+	byte	e_no;
+	int		ipl;
+
+	card = a->io;
+
+	ipl = UxCardLock(card->hw);
+
+	e_no = (byte)card->assign;
+	while (e_no)
+	{
+		if (card->e_tbl[e_no].assign_ref == ref)
+		{
+			break;
+		}
+		e_no = card->e_tbl[e_no].next;
+	}
+
+	UxCardUnlock(card->hw, ipl);
+
+	return e_no;
+}
+
+static
+void	req_queue(ADAPTER * a, byte e_no)
+{
+	card_t	*card;
+	int		ipl;
+
+	card = a->io;
+
+	ipl = UxCardLock(card->hw);
+
+	card->e_tbl[e_no].next = 0;
+
+	if (card->e_head)
+	{
+		card->e_tbl[card->e_tail].next = e_no;
+		card->e_tail = e_no;
+	}
+	else
+	{
+		card->e_head = e_no;
+		card->e_tail = e_no;
+	}
+
+	UxCardUnlock(card->hw, ipl);
+
+	return;
+}
+
+static
+byte	look_req(ADAPTER * a)
+{
+	card_t	*card;
+
+	card = a->io;
+
+	return(card->e_head);
+}
+
+static
+void	next_req(ADAPTER * a)
+{
+	card_t	*card;
+	int		ipl;
+
+
+	card = a->io;
+
+	ipl = UxCardLock(card->hw);
+
+	card->e_head = card->e_tbl[card->e_head].next;
+	if (!card->e_head)
+	{
+		card->e_tail = 0;
+	}
+
+	UxCardUnlock(card->hw, ipl);
+
+	return;
+}
+
+
+/*
+ * IDI request function for active cards
+ */
+static
+void	request(card_t *card, ENTITY *e)
+{
+	word	*special_req;
+	int		i;
+	int		ipl;
+
+
+	if (card->log_types & DIVAS_LOG_IDI)
+	{
+		DivasLogIdi(card, e, TRUE);
+	}
+
+	if (!e->Req)
+	{
+		special_req = (word *) e;
+
+		switch (*special_req)
+		{
+		case REQ_REMOVE:
+			return;
+
+		case REQ_NAME:
+			for (i=0; i < DIM(card->cfg.name); i++)
+			{
+				((struct get_name_s *) e)->name[i] = card->cfg.name[i];
+			}
+			return;
+
+		case REQ_SERIAL:
+		case REQ_XLOG:
+			DPRINTF(("IDI: attempted REQ_SERIAL or REQ_XLOG"));
+			return;
+
+		default:
+			return;
+		}
+	}
+
+	ipl = UxCardLock(card->hw);
+
+   	if (!(e->Id & 0x1f))
+	{
+		DPRINTF(("IDI: ASSIGN req"));
+
+		for (i = 1; i < card->e_max; i++)
+		{
+			if (!card->e_tbl[i].e)
+			{
+				break;
+			}
+		}
+
+		if (i == card->e_max)
+		{
+			DPRINTF(("IDI: request all ids in use (IDI req ignored)"));
+			UxCardUnlock(card->hw, ipl);
+			e->Rc = OUT_OF_RESOURCES;
+			return;
+		}
+
+		card->e_tbl[i].e = e;
+		card->e_count++;
+
+		e->No = (byte) i;
+		e->More = 0;
+		e->RCurrent = 0xff;
+	}
+	else
+	{
+		i = e->No;
+	}
+    
+    if (e->More & XBUSY)
+	{
+		DPRINTF(("IDI: request - entity is busy"));
+		UxCardUnlock(card->hw, ipl);
+		return;
+	}
+
+	e->More |= XBUSY;
+	e->More &= ~ XMOREF;
+	e->XCurrent = 0;
+	e->XOffset = 0;
+
+	card->e_tbl[i].next = 0;
+
+	if(card->e_head)
+	{
+		card->e_tbl[card->e_tail].next = i;
+		card->e_tail = i;
+	}
+	else
+	{
+		card->e_head = i;
+		card->e_tail = i;
+	}
+
+	UxCardUnlock(card->hw, ipl);
+
+	DivasScheduleRequestDpc();
+
+	return;
+}
+
+static byte pr_ready(ADAPTER * a)
+{
+  byte ReadyCount;
+
+  ReadyCount = (byte)(a->ram_in(a, &PR_RAM->ReqOutput) -
+                      a->ram_in(a, &PR_RAM->ReqInput));
+
+  if(!ReadyCount) {
+    if(!a->ReadyInt) {
+      a->ram_inc(a, &PR_RAM->ReadyInt);
+      a->ReadyInt++;
+    }
+  }
+  return ReadyCount;
+}
+
+/*------------------------------------------------------------------*/
+/* output function                                                  */
+/*------------------------------------------------------------------*/
+
+void DivasOut(ADAPTER * a)
+{
+  byte e_no;
+  ENTITY  * this = NULL;
+  BUFFERS  *X;
+  word length;
+  word i;
+  word clength;
+  REQ * ReqOut;
+  byte more;
+  byte ReadyCount;
+  byte ReqCount;
+  byte Id;
+
+        /* while a request is pending ...                           */
+  e_no = look_req(a);
+  if(!e_no)
+  {
+    return;
+  }
+
+  ReadyCount = pr_ready(a);
+  if(!ReadyCount)
+  {
+    DPRINTF(("IDI: card not ready for next request"));
+    return;
+  }
+
+  ReqCount = 0;
+  while(e_no && ReadyCount) {
+
+    next_req(a);
+
+    this = entity_ptr(a, e_no);
+
+#ifdef	USE_EXTENDED_DEBUGS
+	if ( !this )
+	{
+		ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ;
+		DBG_FTL(("!A%d ==> NULL entity ptr - try to ignore", (int)io->ANum))
+		e_no = look_req(a) ;
+		ReadyCount-- ;
+		continue ;
+	}
+	{
+		ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ;
+		DPRINTF(("IDI: >A%d Id=0x%x Req=0x%x", io->ANum, this->Id, this->Req))
+	}
+#else
+    DPRINTF(("IDI: >REQ=%x,Id=%x,Ch=%x",this->Req,this->Id,this->ReqCh));
+#endif
+
+        /* get address of next available request buffer             */
+    ReqOut = (REQ *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextReq)];
+
+        /* now copy the data from the current data buffer into the  */
+        /* adapters request buffer                                  */
+    length = 0;
+    i = this->XCurrent;
+    X = PTR_X(a,this);
+    while(i<this->XNum && length<270) {
+      clength = MIN((word)(270-length),X[i].PLength-this->XOffset);
+      a->ram_out_buffer(a,
+                        &ReqOut->XBuffer.P[length],
+                        PTR_P(a,this,&X[i].P[this->XOffset]),
+                        clength);
+
+      length +=clength;
+      this->XOffset +=clength;
+      if(this->XOffset==X[i].PLength) {
+        this->XCurrent = (byte)++i;
+        this->XOffset = 0;
+      }
+    }
+
+    a->ram_outw(a, &ReqOut->XBuffer.length, length);
+    a->ram_out(a, &ReqOut->ReqId, this->Id);
+    a->ram_out(a, &ReqOut->ReqCh, this->ReqCh);
+
+        /* if its a specific request (no ASSIGN) ...                */
+
+    if(this->Id &0x1f) {
+
+        /* if buffers are left in the list of data buffers do       */
+        /* do chaining (LL_MDATA, N_MDATA)                          */
+
+      this->More++;
+      if(i<this->XNum && this->MInd) {
+        a->ram_out(a, &ReqOut->Req, this->MInd);
+        more = TRUE;
+      }
+      else {
+        this->More |=XMOREF;
+        a->ram_out(a, &ReqOut->Req, this->Req);
+        more = FALSE;
+      }
+
+        /* if we did chaining, this entity is put back into the     */
+        /* request queue                                            */
+
+      if(more) {
+        req_queue(a,this->No);
+      }
+    }
+
+        /* else it's a ASSIGN                                       */
+
+    else {
+
+        /* save the request code used for buffer chaining           */
+
+      this->MInd = 0;
+      if (this->Id==BLLC_ID) this->MInd = LL_MDATA;
+      if (this->Id==NL_ID   ||
+          this->Id==TASK_ID ||
+          this->Id==MAN_ID
+        ) this->MInd = N_MDATA;
+
+        /* send the ASSIGN                                          */
+
+      this->More |=XMOREF;
+      a->ram_out(a, &ReqOut->Req, this->Req);
+
+        /* save the reference of the ASSIGN                         */
+
+      assign_queue(a, this->No, a->ram_inw(a, &ReqOut->Reference));
+    }
+    a->ram_outw(a, &PR_RAM->NextReq, a->ram_inw(a, &ReqOut->next));
+    ReadyCount--;
+    ReqCount++;
+
+    e_no = look_req(a);
+  }
+
+        /* send the filled request buffers to the ISDN adapter      */
+
+  a->ram_out(a, &PR_RAM->ReqInput,
+             (byte)(a->ram_in(a, &PR_RAM->ReqInput) + ReqCount));
+
+        /* if it is a 'unreturncoded' UREMOVE request, remove the  */
+        /* Id from our table after sending the request             */
+  if(this->Req==UREMOVE && this->Id) {
+    Id = this->Id;
+    e_no = a->IdTable[Id];
+    free_entity(a, e_no);
+    a->IdTable[Id] = 0;
+    this->Id = 0;
+  }
+
+}
+
+/*------------------------------------------------------------------*/
+/* isdn interrupt handler                                           */
+/*------------------------------------------------------------------*/
+
+byte DivasDpc(ADAPTER * a)
+{
+  byte Count;
+  RC * RcIn;
+  IND * IndIn;
+  byte c;
+  byte RNRId;
+  byte Rc;
+  byte Ind;
+
+        /* if return codes are available ...                        */
+  if((Count = a->ram_in(a, &PR_RAM->RcOutput))) {
+
+    DPRINTF(("IDI: #Rc=%x",Count));
+
+        /* get the buffer address of the first return code          */
+    RcIn = (RC *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextRc)];
+
+        /* for all return codes do ...                              */
+    while(Count--) {
+
+      if((Rc=a->ram_in(a, &RcIn->Rc))) {
+
+        /* call return code handler, if it is not our return code   */
+        /* the handler returns 2                                    */
+        /* for all return codes we process, we clear the Rc field   */
+        isdn_rc(a,
+                Rc,
+                a->ram_in(a, &RcIn->RcId),
+                a->ram_in(a, &RcIn->RcCh),
+                a->ram_inw(a, &RcIn->Reference));
+
+        a->ram_out(a, &RcIn->Rc, 0);
+      }
+
+        /* get buffer address of next return code                   */
+      RcIn = (RC *)&PR_RAM->B[a->ram_inw(a, &RcIn->next)];
+    }
+
+        /* clear all return codes (no chaining!)                    */
+    a->ram_out(a, &PR_RAM->RcOutput ,0);
+
+        /* call output function                                     */
+    DivasOut(a);
+  }
+
+        /* clear RNR flag                                           */
+  RNRId = 0;
+
+        /* if indications are available ...                         */
+  if((Count = a->ram_in(a, &PR_RAM->IndOutput))) {
+
+    DPRINTF(("IDI: #Ind=%x",Count));
+
+        /* get the buffer address of the first indication           */
+    IndIn = (IND *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextInd)];
+
+        /* for all indications do ...                               */
+    while(Count--) {
+
+        /* if the application marks an indication as RNR, all       */
+        /* indications from the same Id delivered in this interrupt */
+        /* are marked RNR                                           */
+      if(RNRId && RNRId==a->ram_in(a, &IndIn->IndId)) {
+        a->ram_out(a, &IndIn->Ind, 0);
+        a->ram_out(a, &IndIn->RNR, TRUE);
+      }
+      else {
+        Ind = a->ram_in(a, &IndIn->Ind);
+        if(Ind) {
+          RNRId = 0;
+
+        /* call indication handler, a return value of 2 means chain */
+        /* a return value of 1 means RNR                            */
+        /* for all indications we process, we clear the Ind field   */
+          c = isdn_ind(a,
+                       Ind,
+                       a->ram_in(a, &IndIn->IndId),
+                       a->ram_in(a, &IndIn->IndCh),
+                       &IndIn->RBuffer,
+                       a->ram_in(a, &IndIn->MInd),
+                       a->ram_inw(a, &IndIn->MLength));
+
+          if(c==1) {
+            DPRINTF(("IDI: RNR"));
+            a->ram_out(a, &IndIn->Ind, 0);
+            RNRId = a->ram_in(a, &IndIn->IndId);
+            a->ram_out(a, &IndIn->RNR, TRUE);
+          }
+        }
+      }
+
+        /* get buffer address of next indication                    */
+      IndIn = (IND *)&PR_RAM->B[a->ram_inw(a, &IndIn->next)];
+    }
+
+    a->ram_out(a, &PR_RAM->IndOutput, 0);
+  }
+  return FALSE;
+}
+
+byte DivasTestInt(ADAPTER * a)
+{
+  return a->ram_in(a,(void *)0x3fe);
+}
+
+void DivasClearInt(ADAPTER * a)
+{
+  a->ram_out(a,(void *)0x3fe,0); 
+}
+
+/*------------------------------------------------------------------*/
+/* return code handler                                              */
+/*------------------------------------------------------------------*/
+
+static
+byte isdn_rc(ADAPTER * a,
+             byte Rc,
+             byte Id,
+             byte Ch,
+             word Ref)
+{
+  ENTITY  * this;
+  byte e_no;
+
+#ifdef	USE_EXTENDED_DEBUGS
+	{
+		ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ;
+		DPRINTF(("IDI: <A%d Id=0x%x Rc=0x%x", io->ANum, Id, Rc))
+	}
+#else
+  DPRINTF(("IDI: <RC(Rc=%x,Id=%x,Ch=%x)",Rc,Id,Ch));
+#endif
+
+        /* check for ready interrupt                                */
+  if(Rc==READY_INT) {
+    if(a->ReadyInt) {
+      a->ReadyInt--;
+      return 0;
+    }
+    return 2;
+  }
+
+        /* if we know this Id ...                                   */
+  e_no = a->IdTable[Id];
+  if(e_no) {
+
+    this = entity_ptr(a,e_no);
+
+    this->RcCh = Ch;
+
+        /* if it is a return code to a REMOVE request, remove the   */
+        /* Id from our table                                        */
+    if(this->Req==REMOVE && Rc==OK) {
+      free_entity(a, e_no);
+      a->IdTable[Id] = 0;
+      this->Id = 0;
+/**************************************************************/
+      if ((this->More & XMOREC) > 1) {
+        this->More &= ~XMOREC;
+	this->More |= 1;
+	DPRINTF(("isdn_rc, Id=%x, correct More on REMOVE", Id));
+      }
+    }
+
+    if (Rc==OK_FC) {
+      this->Rc = Rc;
+      this->More = (this->More & (~XBUSY | XMOREC)) | 1;
+      this->complete = 0xFF;
+      CALLBACK(a, this);
+      return 0;
+    }
+    if(this->More &XMOREC)
+      this->More--;
+
+        /* call the application callback function                   */
+    if(this->More &XMOREF && !(this->More &XMOREC)) {
+      this->Rc = Rc;
+      this->More &=~XBUSY;
+      this->complete=0xff;
+      CALLBACK(a, this);
+    }
+    return 0;
+  }
+
+        /* if it's an ASSIGN return code check if it's a return     */
+        /* code to an ASSIGN request from us                        */
+  if((Rc &0xf0)==ASSIGN_RC) {
+
+    e_no = get_assign(a, Ref);
+
+    if(e_no) {
+
+      this = entity_ptr(a,e_no);
+
+      this->Id = Id;
+
+        /* call the application callback function                   */
+      this->Rc = Rc;
+      this->More &=~XBUSY;
+      this->complete=0xff;
+      CALLBACK(a, this);
+
+      if(Rc==ASSIGN_OK) {
+        a->IdTable[Id] = e_no;
+      }
+      else
+      {
+        free_entity(a, e_no);
+        a->IdTable[Id] = 0;
+        this->Id = 0;
+      }
+      return 1;
+    }
+  }
+  return 2;
+}
+
+/*------------------------------------------------------------------*/
+/* indication handler                                               */
+/*------------------------------------------------------------------*/
+
+static
+byte isdn_ind(ADAPTER * a,
+              byte Ind,
+              byte Id,
+              byte Ch,
+              PBUFFER * RBuffer,
+              byte MInd,
+              word MLength)
+{
+  ENTITY  * this;
+  word clength;
+  word offset;
+  BUFFERS  *R;
+
+#ifdef	USE_EXTENDED_DEBUGS
+	{
+		ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ;
+		DPRINTF(("IDI: <A%d Id=0x%x Ind=0x%x", io->ANum, Id, Ind))
+	}
+#else
+  DPRINTF(("IDI: <IND(Ind=%x,Id=%x,Ch=%x)",Ind,Id,Ch));
+#endif
+
+  if(a->IdTable[Id]) {
+
+    this = entity_ptr(a,a->IdTable[Id]);
+
+    this->IndCh = Ch;
+
+        /* if the Receive More flag is not yet set, this is the     */
+        /* first buffer of the packet                               */
+    if(this->RCurrent==0xff) {
+
+        /* check for receive buffer chaining                        */
+      if(Ind==this->MInd) {
+        this->complete = 0;
+        this->Ind = MInd;
+      }
+      else {
+        this->complete = 1;
+        this->Ind = Ind;
+      }
+
+        /* call the application callback function for the receive   */
+        /* look ahead                                               */
+      this->RLength = MLength;
+
+      a->ram_look_ahead(a, RBuffer, this);
+
+      this->RNum = 0;
+      CALLBACK(a, this);
+
+        /* map entity ptr, selector could be re-mapped by call to   */
+        /* IDI from within callback                                 */
+      this = entity_ptr(a,a->IdTable[Id]);
+
+        /* check for RNR                                            */
+      if(this->RNR==1) {
+        this->RNR = 0;
+        return 1;
+      }
+
+        /* if no buffers are provided by the application, the       */
+        /* application want to copy the data itself including       */
+        /* N_MDATA/LL_MDATA chaining                                */
+      if(!this->RNR && !this->RNum) {
+        return 0;
+      }
+
+        /* if there is no RNR, set the More flag                    */
+      this->RCurrent = 0;
+      this->ROffset = 0;
+    }
+
+    if(this->RNR==2) {
+      if(Ind!=this->MInd) {
+        this->RCurrent = 0xff;
+        this->RNR = 0;
+      }
+      return 0;
+    }
+        /* if we have received buffers from the application, copy   */
+        /* the data into these buffers                              */
+    offset = 0;
+    R = PTR_R(a,this);
+    do {
+      if(this->ROffset==R[this->RCurrent].PLength) {
+        this->ROffset = 0;
+        this->RCurrent++;
+      }
+      clength = MIN(a->ram_inw(a, &RBuffer->length)-offset,
+                    R[this->RCurrent].PLength-this->ROffset);
+      if(R[this->RCurrent].P) {
+        a->ram_in_buffer(a,
+                         &RBuffer->P[offset],
+                         PTR_P(a,this,&R[this->RCurrent].P[this->ROffset]),
+                         clength);
+      }
+      offset +=clength;
+      this->ROffset +=clength;
+    } while(offset<(a->ram_inw(a, &RBuffer->length)));
+
+        /* if it's the last buffer of the packet, call the          */
+        /* application callback function for the receive complete   */
+        /* call                                                     */
+    if(Ind!=this->MInd) {
+      R[this->RCurrent].PLength = this->ROffset;
+      if(this->ROffset) this->RCurrent++;
+      this->RNum = this->RCurrent;
+      this->RCurrent = 0xff;
+      this->Ind = Ind;
+      this->complete = 2;
+      CALLBACK(a, this);
+    }
+    return 0;
+  }
+  return 2;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/idi.h linux.19p18/drivers/isdn/eicon/idi.h
--- linux.vanilla/drivers/isdn/eicon/idi.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/eicon/idi.h	Mon Feb 19 18:28:20 2001
@@ -0,0 +1,143 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.0  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+/* External IDI interface */
+
+#if !defined(IDI_H)
+#define IDI_H
+
+#include "sys.h"
+
+/* typedefs for our data structures */
+
+typedef struct get_name_s GET_NAME;
+typedef struct entity_s ENTITY;
+typedef struct buffers_s BUFFERS;
+
+/* IDI request/callback function pointer */
+
+typedef void (* IDI_CALL)(ENTITY *);
+
+typedef struct {
+  word length;          /* length of data/parameter field           */
+  byte P[270];          /* data/parameter field                     */
+} DBUFFER;
+
+#define REQ_NAME	0x0100
+#define BOARD_NAME_LENGTH 9
+struct get_name_s {
+  word command;         /* command = 0x0100 */
+  byte name[BOARD_NAME_LENGTH];
+};
+
+#define REQ_REMOVE    0x0000    /* pointer to word which is 0 */
+#define REQ_SERIAL    0x0200  
+struct get_serial_s {
+  word      command;            /* command = 0x0200 */
+  dword     serial;             /* serial number */
+};
+
+#define REQ_POSTCALL  0x0300  
+struct postcall_s {
+  word        command;         /* command = 0x0300 */
+  word        dummy;           /* not used */
+  IDI_CALL    callback;        /* routine adress to call back */
+  ENTITY      *contxt;         /* ptr to entity to use */
+};
+
+#define REQ_XLOG      0x0400   /* structure is card dependent/defined locally */
+
+struct buffers_s {
+  word PLength;
+  byte *P;
+};
+
+struct entity_s {
+  byte                  Req;            /* pending request          */
+  byte                  Rc;             /* return code received     */
+  byte                  Ind;            /* indication received      */
+  byte                  ReqCh;          /* channel of current Req   */
+  byte                  RcCh;           /* channel of current Rc    */
+  byte                  IndCh;          /* channel of current Ind   */
+  byte                  Id;             /* ID used by this entity   */
+  byte                  GlobalId;       /* reserved field           */
+  byte                  XNum;           /* number of X-buffers      */
+  byte                  RNum;           /* number of R-buffers      */
+  BUFFERS               *X;        		/* pointer to X-buffer list */
+  BUFFERS               *R;        		/* pointer to R-buffer list */
+  word                  RLength;        /* length of current R-data */
+  DBUFFER               *RBuffer;       /* buffer of current R-data */
+  byte                  RNR;            /* receive not ready flag   */
+  byte                  complete;       /* receive complete status  */
+  IDI_CALL              callback;
+
+  word                  user[2];
+
+        /* fields used by the driver internally                     */
+  byte                  No;             /* entity number            */
+  byte                  reserved2;      /* reserved field           */
+  byte                  More;           /* R/X More flags           */
+  byte                  MInd;           /* MDATA coding for this ID */
+  byte                  XCurrent;       /* current transmit buffer  */
+  byte                  RCurrent;       /* current receive buffer   */
+  word                  XOffset;        /* offset in x-buffer       */
+  word                  ROffset;        /* offset in r-buffer       */
+};
+
+typedef struct {
+  byte                  type;
+  byte                  channels;
+  word                  features;
+  /* dword		serial; */
+  IDI_CALL              request;
+} DESCRIPTOR;
+
+extern void    DIVA_DIDD_Read(DESCRIPTOR *, int);
+
+        /* descriptor type field coding */
+#define IDI_ADAPTER_S           1
+#define IDI_ADAPTER_PR          2
+#define IDI_ADAPTER_DIVA        3
+#define IDI_ADAPTER_MAESTRA     4
+#define IDI_ADAPTER_MAESTRAQ    5
+#define IDI_ADAPTER_MAESTRAP    6
+#define IDI_VADAPTER            0x40
+#define IDI_DRIVER              0x80
+#define IDI_DIMAINT             0xff
+
+/* feature bit mask values */
+
+#define DI_VOICE        0x0 /* obsolete define */
+#define DI_FAX3         0x1
+#define DI_MODEM        0x2
+#define DI_POST         0x4
+#define DI_V110         0x8
+#define DI_V120         0x10
+#define DI_POTS         0x20
+#define DI_CODEC        0x40
+#define DI_MANAGE       0x80
+#define DI_V_42         0x0100
+#define DI_EXTD_FAX     0x0200 /* Extended FAX (ECM, 2D, T.6, Polling) */
+
+#endif /* IDI_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/kprintf.c linux.19p18/drivers/isdn/eicon/kprintf.c
--- linux.vanilla/drivers/isdn/eicon/kprintf.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/eicon/kprintf.c	Mon Feb 19 18:28:20 2001
@@ -0,0 +1,535 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.3  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+/*
+ * Source file for kernel interface to kernel log facility
+ */
+
+
+#include "sys.h"
+#include <stdarg.h>
+#undef MAX
+#undef MIN
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include "divas.h"
+#include "divalog.h"
+#include "uxio.h"
+
+/*
+ * Implementation of printf and sprintf for kernel
+ */
+
+#define MAX_BUFF    (80)        /* limit size of temporary buffers */
+
+#define WRITE_CHAR(BUFFER, SIZE, C) \
+  if (--(SIZE) < 0) { (BUFFER)--; *(BUFFER) = '\0'; return; } *(BUFFER)++ = (C)
+
+
+/*
+ * convert a number to decimal ASCII
+ */
+
+static
+void    do_decimal( char            *temp,
+                    int             temp_len,
+                    unsigned int    value,
+                    char            *s)
+
+{
+    int     i;
+
+    temp[0] = '\0';
+
+    for (i = 1; i < temp_len; i++)
+    {
+        temp[i] = (char) ((value % 10) + (int) '0');
+        value /= 10;
+    }
+
+    for (i = (temp_len - 1); temp[i] == '0'; i--)
+    {
+        ;
+    }
+
+    if (i == 0)
+    {
+        i++;
+    }
+
+    while (i >= 0)
+    {
+        *s++ = temp[i--];
+    }
+
+    return;
+}
+
+/*
+ * convert a number to octal ASCII
+ */
+
+static
+void    do_octal(   char            *temp,
+                    unsigned int    value,
+                    char            *s)
+
+{
+    int     i;
+
+    temp[0] = '\0';
+
+    for (i = 1; i <= 11; i++)
+    {
+        temp[i] = (char) ((value & 07) + (int) '0');
+        value >>= 3;
+    }
+    temp[11] &= '3';
+
+    for (i = 11; temp[i] == '0'; i--)
+    {
+        ;
+    }
+
+    if (i == 0)
+    {
+        i++;
+    }
+
+    while (i >= 0)
+    {
+        *s++ = temp[i--];
+    }
+
+    return;
+}
+
+/*
+ * convert a number to hex ASCII
+ */
+
+static
+void    do_hex( char            *temp,
+                unsigned int    value,
+                char            *s)
+
+{
+    int     i;
+    static
+    char    *dec_to_hex = "0123456789abcdef";
+
+    temp[0] = '\0';
+
+    for (i = 1; i <= 8; i++)
+    {
+        temp[i] = dec_to_hex[value & 0x0f];
+        value >>= 4;
+    }
+
+    for (i = 8; temp[i] == '0'; i--)
+    {
+        ;
+    }
+
+    if (i == 0)
+    {
+        i++;
+    }
+
+    while (i >= 0)
+    {
+        *s++ = temp[i--];
+    }
+
+    return;
+}
+
+/*
+ * convert a buffer to ASCII HEX
+ */
+
+static
+void    do_buffer(  char    *buffer,
+                    int     length,
+                    char    *s)
+
+{
+    static
+    char    hex_char [] = "0123456789abcdef";
+    char    *b = buffer;
+    int     hex_byte;
+    int     nybble;
+
+    length = (length >= ((MAX_BUFF / 3) + 1)) ? (MAX_BUFF / 3) : length;
+
+    while (length)
+    {
+        hex_byte = (int) *b++;
+        nybble = (hex_byte >> 4) & 0xf;
+        *s++ = hex_char[nybble];
+        nybble = hex_byte & 0xf;
+        *s++ = hex_char[nybble];
+        *s++ = ' ';
+        length--;
+    }
+    *s = '\0';
+
+    return;
+}
+
+/*
+ * Body of sprintf function: behaves just like standard sprintf, except we
+ * have an extra argument (buffer size) which we use to ensure we don't
+ * overflow
+ */
+
+void    Divas_vsprintf(   char    *buffer,
+                    int     size,
+                    char    *fmt,
+                    va_list argptr)
+
+{
+    char        c;          /* single character buffer */
+    int         i;          /* handy scratch counter */
+    int         f;          /* format character (after %) */
+    char        *str;       /* pointer into string */
+    char        temp[20];   /* temp buffer used in printing numbers */
+    char        string[MAX_BUFF]; /* output from number conversion */
+    int         length;     /* length of string "str" */
+    char        fill;       /* fill character ' ' or '0' */
+    boolean_t   leftjust;   /* TRUE if left justified, else right justified */
+    int         fmax, fmin; /* field specifiers % MIN . MAX s */
+    int         leading;    /* number of leading/trailing fill characters */
+    char        sign;       /* set to '-' for negative decimals */
+    int         number;     /* numeric argument */
+
+    char        *buff_ptr;  /* pointer to user's buffer of hex data */
+    int         buff_len;   /* length of hex data */
+
+    /* make sure we have somthing to write into */
+
+    if ((!buffer) || (size <= 0))
+    {
+        return;
+    }
+
+    while (TRUE)
+    {
+        /* echo characters until end or '%' encountered */
+
+        while ((c = *fmt++) != '%')
+        {
+            if (!c)
+            {
+                *buffer = '\0';
+                return;
+            }
+            WRITE_CHAR(buffer, size, c);
+        }
+
+        /* echo %% as % */
+
+        if (*fmt == '%')
+        {
+            WRITE_CHAR(buffer, size, *fmt);
+            continue;
+        }
+
+        /* %- turns on left-justify */
+
+        if ((leftjust = (boolean_t) ((*fmt == '-') ? TRUE : FALSE)))
+        {
+            fmt++;
+        }
+
+        /* %0 turns on zero filling */
+
+        if (*fmt == '0')
+        {
+            fill = '0';
+        }
+        else
+        {
+            fill = ' ';
+        }
+
+        /* minium field width specifier for %d, u, x, c, s */
+
+        fmin = 0;
+
+        if (*fmt == '*')
+        {
+            fmin = va_arg(argptr, int);
+            fmt++;
+        }
+        else
+        {
+            while ('0' <= *fmt && *fmt <= '9')
+            {
+                fmin = (fmin * 10) + (*fmt++ - '0');
+            }
+        }
+
+        /* maximum string width specifier for %s */
+
+        fmax = 0;
+
+        if (*fmt == '.')
+        {
+            if (*(++fmt) == '*')
+            {
+                fmax = va_arg(argptr, int);
+                fmt++;
+            }
+            else
+            {
+                while ('0' <= *fmt && *fmt <= '9')
+                {
+                    fmax = (fmax * 10) + (*fmt++ - '0');
+                }
+            }
+        }
+
+        /* skip over 'l' option (ints are assumed same size as longs) */
+
+        if (*fmt == 'l')
+        {
+            fmt++;
+        }
+
+        /* get the format chacater */
+
+        if (!(f = *fmt++))
+        {
+            WRITE_CHAR(buffer, size, '%');
+            *buffer = '\0';
+            return;
+        }
+
+        sign = '\0';        /* sign == '-' for negative decimal */
+
+        str = string;
+
+        switch (f)
+        {
+        case 'c' :
+            string[0] = (char) va_arg(argptr, int);
+            string[1] = '\0';
+            fmax = 0;
+            fill = ' ';
+            break;
+
+        case 's' :
+            str = va_arg(argptr, char *);
+            fill = ' ';
+            break;
+
+        case 'D' :
+        case 'd' :
+            number = va_arg(argptr, int);
+            if (number < 0)
+            {
+                sign = '-';
+                number = -number;
+            }
+            do_decimal(temp, DIM(temp), (unsigned int) number, str);
+            fmax = 0;
+            break;
+
+        case 'U' :
+        case 'u' :
+            number = va_arg(argptr, int);
+            do_decimal(temp, DIM(temp), (unsigned int) number, str);
+            fmax = 0;
+            break;
+
+        case 'O' :
+        case 'o' :
+            number = va_arg(argptr, int);
+            do_octal(temp, (unsigned int) number, str);
+            fmax = 0;
+            break;
+
+        case 'X' :
+        case 'x' :
+            number = va_arg(argptr, int);
+            do_hex(temp, (unsigned int) number, str);
+            fmax = 0;
+            break;
+
+        case 'H' :
+        case 'h' :
+            buff_ptr = va_arg(argptr, char *);
+            buff_len = va_arg(argptr, int);
+            do_buffer(buff_ptr, buff_len, str);
+            fmax = 0;
+            break;
+
+        default :
+            WRITE_CHAR(buffer, size, ((char) f));
+            break;
+        }
+
+        /* get the length of the string */
+
+        length = 0;
+        while (str[length])
+        {
+            length++;
+        }
+
+        /* make sure we have fmax and fmin values that are O.K. */
+
+        if (fmin > DIM(string) || fmin < 0)
+        {
+            fmin = 0;
+        }
+
+        if (fmax > DIM(string) || fmax < 0)
+        {
+            fmax = 0;
+        }
+
+        /* figure out how many leading characters thare are */
+
+        leading = 0;
+
+        if (fmax || fmin)
+        {
+            if (fmax)
+            {
+                if (length > fmax)
+                {
+                    length = fmax;
+                }
+            }
+
+            if (fmin)
+            {
+                leading = fmin - length;
+            }
+
+            if (sign == '-')
+            {
+                leading--;
+            }
+        }
+
+        /* output sign now, if fill is numeric */
+
+        if (sign == '-' && fill == '0')
+        {
+            WRITE_CHAR(buffer, size, '-');
+        }
+
+        /* if right justified, output fill characters */
+
+        if (!leftjust)
+        {
+            for (i = 0; i < leading; i++)
+            {
+                WRITE_CHAR(buffer, size, fill);
+            }
+        }
+
+        /* output sign now, if fill is spaces */
+
+        if (sign == '-' && fill == ' ')
+        {
+            WRITE_CHAR(buffer, size, '-');
+        }
+
+        /* now the actual value */
+
+        for (i = 0; i < length; i++)
+        {
+            WRITE_CHAR(buffer, size, str[i]);
+        }
+
+        /* if left justified, fill out with the fill character */
+
+        if (leftjust)
+        {
+            for (i = 0; i < leading; i++)
+            {
+                WRITE_CHAR(buffer, size, fill);
+            }
+        }
+    }
+}
+
+/*
+ * sprintf for kernel
+ *
+ * call our vsprintf assuming user has a big buffer....
+ */
+
+void    DivasSprintf(char *buffer, char *fmt, ...)
+
+{
+    va_list     argptr;         /* pointer to additional args */
+
+    va_start(argptr, fmt);
+
+    Divas_vsprintf(buffer, 1024, fmt, argptr);
+
+    va_end(argptr);
+
+    return;
+}
+
+void    DivasPrintf(char  *fmt, ...)
+
+{
+    klog_t      log;            /* log entry buffer */
+
+    va_list     argptr;         /* pointer to additional args */
+
+    va_start(argptr, fmt);
+
+    /* clear log entry */
+
+    bzero((caddr_t) &log, sizeof(klog_t));
+
+    log.card = -1;
+    log.type = KLOG_TEXT_MSG;
+
+    /* time stamp the entry */
+
+    log.time_stamp = UxTimeGet();
+
+    /* call vsprintf to format the user's information */
+
+    Divas_vsprintf(log.buffer, DIM(log.buffer), fmt, argptr);
+
+    va_end(argptr);
+
+    /* send to the log streams driver and return */
+
+    DivasLogAdd(&log, sizeof(klog_t));
+
+    return;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/lincfg.c linux.19p18/drivers/isdn/eicon/lincfg.c
--- linux.vanilla/drivers/isdn/eicon/lincfg.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/eicon/lincfg.c	Mon Feb 19 18:28:20 2001
@@ -0,0 +1,407 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.9  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+#include <linux/fs.h>
+#undef N_DATA   /* Because we have our own definition */
+
+#include <asm/segment.h>
+#include <asm/io.h>
+
+#include "sys.h"
+#include "idi.h"
+#include "constant.h"
+#include "divas.h"
+#undef ID_MASK
+#include "pc.h"
+#include "pr_pc.h"
+
+#include "adapter.h"
+#include "uxio.h"
+
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+
+#define HW_ID_EICON_PCI			0x1133
+#define HW_ID_DIVA_SERVER_P		0xE014
+#define HW_ID_DIVA_SERVER_B_ST	0xE010
+#define HW_ID_DIVA_SERVER_B_U	0xE013
+#define HW_ID_DIVA_SERVER_Q   	0xE012
+
+struct file_operations Divas_fops;
+int Divas_major;
+
+extern int do_ioctl(struct inode *pDivasInode, struct file *pDivasFile, 
+			 unsigned int command, unsigned long arg);
+extern unsigned int do_poll(struct file *pFile, struct poll_table_struct *pPollTable);
+extern ssize_t do_read(struct file *pFile, char *pUserBuffer, size_t BufferSize, loff_t *pOffset);
+extern int do_open(struct inode *, struct file *);
+extern int do_release(struct inode *, struct file *);
+
+int FPGA_Done=0;
+
+int DivasCardsDiscover(void)
+{
+	word wNumCards = 0, wDeviceIndex = 0;
+	byte byBus, byFunc;
+	word wPCIConsultation, PCItmp;
+	dword j, i;
+	unsigned int PCIserial;
+	dia_card_t Card;
+	byte *b;
+	
+	while (wDeviceIndex < 10)
+	{
+		wPCIConsultation = pcibios_find_device(HW_ID_EICON_PCI, 
+				HW_ID_DIVA_SERVER_Q, 
+				wDeviceIndex, 
+				&byBus, &byFunc);
+
+		if (wPCIConsultation == PCIBIOS_SUCCESSFUL)
+		{
+
+			dword dwRAM, dwDivasIOBase, dwCFG, dwCTL; 			
+			byte byIRQ;
+			
+			printk(KERN_DEBUG "Divas: DIVA Server 4BRI Found\n");
+			pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2,(unsigned int *) &dwRAM);
+			dwRAM &= 0xFFC00000;
+			
+			pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_1,(unsigned int *) &dwDivasIOBase);
+			dwDivasIOBase &= 0xFFFFFF00;
+			
+			pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_0,(unsigned int *) &dwCFG);
+			dwCFG &= 0xFFFFFF00;
+			
+			pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_3,(unsigned int *) &dwCTL);
+			dwCTL &= 0xFFFFE000;
+			
+
+			pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ);
+			/* Retrieve the serial number */
+
+			pcibios_write_config_word(byBus,byFunc,0x4E,0x00FC);
+
+			for (j=0, PCItmp=0; j<10000 && !PCItmp; j++)
+			{
+				pcibios_read_config_word(byBus,byFunc,0x4E, &PCItmp);
+				PCItmp &= 0x8000;  // extract done flag
+			}
+
+			pcibios_read_config_dword(byBus,byFunc,0x50, &PCIserial);
+
+		
+			Card.memory[DIVAS_RAM_MEMORY] = ioremap(dwRAM, 0x400000);
+			Card.memory[DIVAS_CTL_MEMORY] = ioremap(dwCTL, 0x2000);
+			Card.memory[DIVAS_CFG_MEMORY] = ioremap(dwCFG, 0x100);
+			Card.io_base=dwDivasIOBase;
+
+			Card.irq = byIRQ;
+			
+			Card.card_type = DIA_CARD_TYPE_DIVA_SERVER_Q;
+			Card.bus_type = DIA_BUS_TYPE_PCI;
+	
+			FPGA_Done = 0;
+
+			/* Create four virtual card structures as we want to treat 
+			   the 4Bri card as 4 Bri cards*/
+			for(i=0;i<4;i++)
+			{
+
+				b=Card.memory[DIVAS_RAM_MEMORY];
+				b+=(MQ_PROTCODE_OFFSET) * (i==0?0:1); 
+				DPRINTF(("divas: offset = 0x%x", i* MQ_PROTCODE_OFFSET));
+				Card.memory[DIVAS_RAM_MEMORY]=b;
+ 
+				b = Card.memory[DIVAS_RAM_MEMORY];
+				b += MQ_SM_OFFSET;
+				Card.memory[DIVAS_SHARED_MEMORY] = b;
+
+				Card.bus_num = byBus;
+				Card.func_num = byFunc;
+				Card.slot = -1;
+
+			
+				/* Fill in Name */
+				Card.name[0] = 'D';
+				Card.name[1] = 'I';
+				Card.name[2] = 'V';
+				Card.name[3] = 'A';
+				Card.name[4] = 'S';
+				Card.name[5] = 'Q';
+				Card.name[6] = '0' + i;
+				Card.name[7] = '\0';
+
+				Card.serial = PCIserial;
+
+			 	Card.card_id = wNumCards;
+
+ 				if (DivasCardNew(&Card) != 0)
+				{
+					// Force for loop to terminate
+					i = 4;
+					continue;
+				}
+				wNumCards++;
+
+			}//for
+		}
+		wDeviceIndex++;
+	}
+
+	wDeviceIndex = 0;
+
+	while (wDeviceIndex < 10)
+	{
+		wPCIConsultation = pcibios_find_device(HW_ID_EICON_PCI, 
+				HW_ID_DIVA_SERVER_B_ST, 
+				wDeviceIndex, 
+				&byBus, &byFunc);
+
+		if (wPCIConsultation == PCIBIOS_SUCCESSFUL)
+		{
+			dword dwPLXIOBase, dwDivasIOBase;
+			byte byIRQ;
+
+			printk(KERN_DEBUG "Divas: DIVA Server BRI (S/T) Found\n");
+			pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_1, (unsigned int *) &dwPLXIOBase);
+			dwPLXIOBase &= 0xFFFFFF80;
+
+			pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2, (unsigned int *) &dwDivasIOBase);
+			dwDivasIOBase &= 0xFFFFFFFC;
+
+			pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ);
+
+			Card.card_id = wNumCards;
+			Card.card_type = DIA_CARD_TYPE_DIVA_SERVER_B;
+			Card.bus_type = DIA_BUS_TYPE_PCI;
+			Card.irq = byIRQ;
+			Card.reset_base = dwPLXIOBase;
+			Card.io_base = dwDivasIOBase;
+			Card.bus_num = byBus;
+			Card.func_num = byFunc;
+			Card.slot = -1;
+			Card.name[0] = 'D';
+			Card.name[1] = 'I';
+			Card.name[2] = 'V';
+			Card.name[3] = 'A';
+			Card.name[4] = 'S';
+			Card.name[5] = 'B';
+			Card.name[6] = '\0';
+
+			if (check_region(Card.io_base, 0x20))
+			{
+				printk(KERN_WARNING "Divas: DIVA I/O Base already in use 0x%x-0x%x\n", Card.io_base, Card.io_base + 0x1F);
+				wDeviceIndex++;
+				continue;
+			}
+
+			if (check_region(Card.reset_base, 0x80))
+			{
+				printk(KERN_WARNING "Divas: PLX I/O Base already in use 0x%x-0x%x\n", Card.reset_base, Card.reset_base + 0x7F);
+				wDeviceIndex++;
+				continue;
+			}
+
+			if (DivasCardNew(&Card) != 0)
+			{
+				wDeviceIndex++;
+				continue;
+			}
+			wNumCards++;
+		}
+
+		wPCIConsultation = pcibios_find_device(HW_ID_EICON_PCI, 
+				HW_ID_DIVA_SERVER_B_U, 
+				wDeviceIndex, 
+				&byBus, &byFunc);
+
+		if (wPCIConsultation == PCIBIOS_SUCCESSFUL)
+		{
+			dword dwPLXIOBase, dwDivasIOBase;
+			byte byIRQ;
+
+			printk(KERN_DEBUG "Divas: DIVA Server BRI (U) Found\n");
+
+			pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_1, (unsigned int *) &dwPLXIOBase);
+			dwPLXIOBase &= 0xFFFFFF80;
+
+			pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2, (unsigned int *) &dwDivasIOBase);
+			dwDivasIOBase &= 0xFFFFFFFC;
+
+			pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ);
+
+			Card.card_id = wNumCards;
+			Card.card_type = DIA_CARD_TYPE_DIVA_SERVER_B;
+			Card.bus_type = DIA_BUS_TYPE_PCI;
+			Card.irq = byIRQ;
+			Card.reset_base = dwPLXIOBase;
+			Card.io_base = dwDivasIOBase;
+			Card.bus_num = byBus;
+			Card.func_num = byFunc;
+			Card.slot = -1;
+			Card.name[0] = 'D';
+			Card.name[1] = 'I';
+			Card.name[2] = 'V';
+			Card.name[3] = 'A';
+			Card.name[4] = 'S';
+			Card.name[5] = 'B';
+			Card.name[6] = '\0';
+
+			if (check_region(Card.io_base, 0x20))
+			{
+				printk(KERN_WARNING "Divas: DIVA I/O Base already in use 0x%x-0x%x\n", Card.io_base, Card.io_base + 0x1F);	
+				wDeviceIndex++;
+				continue;
+			}
+
+			if (check_region(Card.reset_base, 0x80))
+			{
+				printk(KERN_WARNING "Divas: PLX I/O Base already in use 0x%x-0x%x\n", Card.reset_base, Card.reset_base + 0x7F);
+				wDeviceIndex++;
+				continue;
+			}
+
+			if (DivasCardNew(&Card) != 0)
+			{
+				wDeviceIndex++;
+				continue;
+			}
+			wNumCards++;
+		}
+
+		wDeviceIndex++;
+	}
+
+	wDeviceIndex = 0;
+
+	while (wDeviceIndex < 10)
+	{
+		wPCIConsultation = pcibios_find_device(HW_ID_EICON_PCI, 
+				HW_ID_DIVA_SERVER_P, 
+				wDeviceIndex, 
+				&byBus, &byFunc);
+
+		if (wPCIConsultation == PCIBIOS_SUCCESSFUL)
+		{
+			dword dwRAM, dwREG, dwCFG;
+			byte byIRQ;
+
+			printk(KERN_DEBUG "Divas: DIVA Server PRI Found\n");
+
+			pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_0, (unsigned int *) &dwRAM);
+			dwRAM &= 0xFFFFF000;
+
+			pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2, (unsigned int *) &dwREG);
+			dwREG &= 0xFFFFF000;
+			
+			pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_4, (unsigned int *) &dwCFG);
+			dwCFG &= 0xFFFFF000;
+
+			pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ);
+
+			Card.memory[DIVAS_RAM_MEMORY] = ioremap(dwRAM, 0x10000);
+			Card.memory[DIVAS_REG_MEMORY] = ioremap(dwREG, 0x4000);
+			Card.memory[DIVAS_CFG_MEMORY] = ioremap(dwCFG, 0x1000);
+			Card.memory[DIVAS_SHARED_MEMORY] = Card.memory[DIVAS_RAM_MEMORY] + DIVAS_SHARED_OFFSET;
+
+/*			pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_1, (unsigned int *) &dwPLXIOBase);
+			dwPLXIOBase &= 0xFFFFFFFc;
+
+			pcibios_read_config_dword(byBus, byFunc, PCI_BASE_ADDRESS_2, (unsigned int *) &dwDivasIOBase);
+			dwDivasIOBase &= 0xFFFFFF80;
+
+			pcibios_read_config_byte(byBus, byFunc, PCI_INTERRUPT_LINE, &byIRQ);
+*/
+			Card.card_id = wNumCards;
+			Card.card_type = DIA_CARD_TYPE_DIVA_SERVER;
+			Card.bus_type = DIA_BUS_TYPE_PCI;
+			Card.irq = byIRQ;
+/*			Card.reset_base = dwPLXIOBase;
+			Card.io_base = dwDivasIOBase;*/
+			Card.bus_num = byBus;
+			Card.func_num = byFunc;
+			Card.slot = -1;
+			Card.name[0] = 'D';
+			Card.name[1] = 'I';
+			Card.name[2] = 'V';
+			Card.name[3] = 'A';
+			Card.name[4] = 'S';
+			Card.name[5] = 'P';
+			Card.name[6] = '\0';
+
+			if (DivasCardNew(&Card) != 0)
+			{
+				wDeviceIndex++;
+				continue;
+			}
+			wNumCards++;
+		}
+
+		wDeviceIndex++;
+	}
+
+
+	printk(KERN_INFO "Divas: %d cards detected\n", wNumCards);
+
+	if(wNumCards == 0)
+	{
+		return -1;
+	}
+
+	Divas_fops.ioctl = do_ioctl;
+	Divas_fops.poll = do_poll;
+	Divas_fops.read = do_read;
+	Divas_fops.open = do_open;
+	Divas_fops.release = do_release;
+
+	Divas_major = register_chrdev(0, "Divas", &Divas_fops);
+
+	if (Divas_major < 0)
+	{
+		printk(KERN_WARNING "Divas: Unable to register character driver\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+/* Error return -1 */
+int DivasConfigGet(dia_card_t *card)
+{
+	/* Retrieve Config from O/S? Not in Linux */
+	return 0;
+}
+
+dia_config_t *DivasConfig(card_t *card, dia_config_t *config)
+{
+	/*	If config retrieved from OS then copy the data into a dia_config_t structure here
+		and return the pointer here. If the config 'came from above' then just 
+
+			return config;
+	*/
+
+	return config;
+}
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/linchr.c linux.19p18/drivers/isdn/eicon/linchr.c
--- linux.vanilla/drivers/isdn/eicon/linchr.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/eicon/linchr.c	Mon Feb 19 18:28:20 2001
@@ -0,0 +1,269 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.12  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/poll.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+
+#undef N_DATA
+
+#include "adapter.h"
+#include "divas.h"
+#include "divalog.h"
+
+extern int DivasCardNext;
+void UxPause(long ms);
+void bcopy(void *pSource, void *pDest, dword dwLength);
+int DivasGetMem(mem_block_t *);
+
+#define DIA_IOCTL_UNLOCK 12
+void UnlockDivas(void);
+
+int do_ioctl(struct inode *pDivasInode, struct file *pDivasFile, 
+			 unsigned int command, unsigned long arg)
+{
+	dia_load_t *pDivaLoad;
+	dia_start_t *pDivaStart;
+	dia_config_t *pDivaConfig;
+	dia_log_t *pDivaLog;
+	byte *pUserCards, card_i;
+	word wCardNum;
+	mem_block_t *mem_block;
+
+	switch (command)
+	{
+		case DIA_IOCTL_CONFIG:
+			pDivaConfig = (dia_config_t *) arg;
+			
+			if (!verify_area(VERIFY_READ, pDivaConfig, sizeof(dia_config_t)))
+			{
+				DivasCardConfig(pDivaConfig);
+			}
+			else
+			{
+				printk(KERN_WARNING "Divas: Unable to complete CONFIG ioctl (verify area failed)\n");
+				return -1;
+			}
+				return 0;
+
+		case DIA_IOCTL_DETECT:
+			pUserCards = (byte *) arg;
+
+			if (!verify_area(VERIFY_WRITE, pUserCards, 20))
+			{
+				put_user(DivasCardNext, pUserCards++);
+
+				for (card_i=1; card_i < 20; card_i++)
+				{
+					put_user((byte) DivasCards[card_i - 1].cfg.card_type, pUserCards++);
+				}
+			}
+			else
+			{
+				printk(KERN_WARNING "Divas: Unable to complete DETECT ioctl (verify area failed)\n");
+				return -1;
+			}
+			return 0;
+
+		case DIA_IOCTL_START:
+			pDivaStart = (dia_start_t *) arg;
+			
+			if (!verify_area(VERIFY_READ, pDivaStart, sizeof(dia_start_t)))
+			{
+				return DivasCardStart(pDivaStart->card_id);
+			}
+			else
+			{
+				printk(KERN_WARNING "Divas: Unable to complete START ioctl (verify area failed)\n");
+				return -1;
+			}
+
+
+		case DIA_IOCTL_FLAVOUR:
+			return 0;
+
+		case DIA_IOCTL_LOAD:
+			pDivaLoad = (dia_load_t *) arg;
+			if (!verify_area(VERIFY_READ, pDivaLoad->code,pDivaLoad->length))
+			{
+				if (DivasCardLoad(pDivaLoad))
+				{
+					printk(KERN_WARNING "Divas: Error loading DIVA Server adapter\n");
+					return -EINVAL;
+				}
+			}
+			else
+			{
+				printk(KERN_WARNING "Divas: Error in LOAD parameters (verify failed)\n");
+				return -EINVAL;
+			}
+			return 0;
+
+		case DIA_IOCTL_LOG:
+			pDivaLog = (dia_log_t *) arg;
+			
+			if (!verify_area(VERIFY_READ, pDivaLog, sizeof(dia_log_t)))
+			{
+				DivasLog(pDivaLog);
+			}
+			else
+			{
+				printk(KERN_WARNING "Divas: Unable to complete LOG ioctl (verify area failed)\n");
+				return -1;
+			}
+			return 0;
+
+		case DIA_IOCTL_XLOG_REQ:
+			
+			if (!verify_area(VERIFY_READ, (void *)arg, sizeof(word)))
+			{
+				wCardNum = * (word *) arg;
+				DivasXlogReq(wCardNum);
+			}
+			else
+			{
+				printk(KERN_WARNING "Divas: Unable to complete XLOG_REQ ioctl (verify area failed)\n");
+				return -1;
+			}
+			return 0;
+
+		case DIA_IOCTL_GET_NUM:
+			
+			if (!verify_area(VERIFY_WRITE, (void *)arg, sizeof(int)))
+			{
+				* (int *) arg = DivasCardNext;
+			}
+			else
+			{
+				printk(KERN_WARNING "Divas: Unable to complete GET_NUM ioctl (verify area failed)\n");
+				return -1;
+			}
+			return 0;
+
+		case DIA_IOCTL_GET_LIST:
+			DPRINTF(("divas: DIA_IOCTL_GET_LIST"));
+			
+			if (!verify_area(VERIFY_WRITE, (void *)arg, sizeof(dia_card_list_t)))
+			{
+				DivasGetList((dia_card_list_t *)arg);
+			}
+			else
+			{
+				printk(KERN_WARNING "Divas: Unable to complete GET_LIST ioctl (verify area failed)\n");
+				return -1;
+			}
+			return 0;
+
+		case DIA_IOCTL_GET_MEM:
+			mem_block = (mem_block_t *) arg;
+			
+			if (!verify_area(VERIFY_WRITE, mem_block, sizeof(mem_block_t)))
+			{
+				DivasGetMem(mem_block);
+			}
+			else
+			{
+				printk(KERN_WARNING "Divas: Unable to complete GET_MEM ioctl (verify area failed)\n");
+				return -1;
+			}
+			return 0;
+
+		case DIA_IOCTL_UNLOCK:
+			UnlockDivas();
+			return 0;
+
+		default:
+			printk(KERN_WARNING "Divas: Unknown IOCTL Received by DIVA Server Driver(%d)\n", command);
+			return -EINVAL;
+	}
+	
+	return -EINVAL;
+}
+
+unsigned int do_poll(struct file *pFile, struct poll_table_struct *pPollTable)
+{
+	word wMask = 0;
+
+    if (!DivasLogFifoEmpty())
+    {
+		wMask |= POLLIN | POLLRDNORM;
+	}
+
+	return wMask;
+}
+
+ssize_t do_read(struct file *pFile, char *pUserBuffer, size_t BufferSize, loff_t *pOffset)
+{
+	klog_t *pClientLogBuffer = (klog_t *) pUserBuffer;
+	klog_t *pHeadItem;
+
+	if (BufferSize < sizeof(klog_t))
+	{
+		printk(KERN_WARNING "Divas: Divalog buffer specifed a size that is too small (%d - %d required)\n",
+			BufferSize, sizeof(klog_t));
+		return 0;
+	}
+
+	pHeadItem = (klog_t *) DivasLogFifoRead();
+
+	if (pHeadItem)
+	{
+		bcopy(pHeadItem, pClientLogBuffer, sizeof(klog_t));
+		kfree(pHeadItem);
+		return sizeof(klog_t);
+	}
+
+	return 0;
+}
+static int private_usage_count;
+
+int do_open(struct inode *pInode, struct file *pFile)
+{
+	MOD_INC_USE_COUNT;
+#ifdef MODULE
+	private_usage_count++;
+#endif
+	return 0;
+}
+
+int do_release(struct inode *pInode, struct file *pFile)
+{
+	MOD_DEC_USE_COUNT;
+#ifdef MODULE
+	private_usage_count--;
+#endif
+	return 0;
+}
+
+void UnlockDivas(void)
+{
+	while (private_usage_count > 0)
+	{
+		private_usage_count--;
+		MOD_DEC_USE_COUNT;
+	}
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/linio.c linux.19p18/drivers/isdn/eicon/linio.c
--- linux.vanilla/drivers/isdn/eicon/linio.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/eicon/linio.c	Mon Feb 19 18:28:20 2001
@@ -0,0 +1,747 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.16  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+#define N_DATA
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#undef N_DATA
+
+#include "uxio.h"
+
+static
+int log_on=0;
+
+int		Divasdevflag = 0;
+
+//spinlock_t diva_lock = SPIN_LOCK_UNLOCKED;
+
+static
+ux_diva_card_t card_pool[MAX_CARDS];
+
+void UxPause(long int ms)
+{
+	int timeout = jiffies + ((ms * HZ) / 1000);
+
+	while (time_before(jiffies, timeout));
+}
+
+int UxCardHandleGet(ux_diva_card_t **card, dia_card_t *cfg)
+{
+	int 		i;
+	ux_diva_card_t	*c;
+
+	if (cfg->bus_type != DIA_BUS_TYPE_PCI)
+	{
+		DPRINTF(("divas hw: type not PCI (%d)", cfg->bus_type));
+		return -1;
+	}
+
+	for (i = 0; (i < DIM(card_pool)) && (card_pool[i].in_use); i++)
+	{
+		;
+	}
+
+	if (i == DIM(card_pool))
+	{
+		DPRINTF(("divas hw: card_pool exhausted"));
+		return -1;
+	}
+
+	c = *card = &card_pool[i];
+
+	switch (cfg->bus_type)
+	{
+	case DIA_BUS_TYPE_PCI:
+		c->bus_num = cfg->bus_num;
+		c->func_num = cfg->func_num;
+		c->io_base = cfg->io_base;
+		c->reset_base = cfg->reset_base;
+		c->card_type    = cfg->card_type;
+		c->mapped = NULL;
+		c->slot 	= cfg->slot;
+		c->irq 		= (int) cfg->irq;
+		c->pDRAM    	= cfg->memory[DIVAS_RAM_MEMORY];
+		c->pDEVICES 	= cfg->memory[DIVAS_REG_MEMORY];
+		c->pCONFIG  	= cfg->memory[DIVAS_CFG_MEMORY];
+		c->pSHARED  	= cfg->memory[DIVAS_SHARED_MEMORY];
+		c->pCONTROL  	= cfg->memory[DIVAS_CTL_MEMORY];
+
+	/*		c->bus_type 	= DIA_BUS_TYPE_PCI;
+		c->bus_num 	= cfg->bus_num & 0x3f;
+		c->slot 	= cfg->slot;
+		c->irq 		= (int) cfg->irq;
+		c->int_priority = (int) cfg->int_priority;
+		c->card_type    = cfg->card_type;
+		c->io_base      = cfg->io_base;
+		c->reset_base   = cfg->reset_base;
+		c->pDRAM    	= cfg->memory[DIVAS_RAM_MEMORY];
+		c->pDEVICES 	= cfg->memory[DIVAS_REG_MEMORY];
+		c->pCONFIG  	= cfg->memory[DIVAS_CFG_MEMORY];
+		c->pSHARED  	= cfg->memory[DIVAS_SHARED_MEMORY];
+		DPRINTF(("divas hw: pDRAM is 0x%x", c->pDRAM));
+		DPRINTF(("divas hw: pSHARED is 0x%x", c->pSHARED));
+		DPRINTF(("divas hw: pCONFIG is 0x%x", c->pCONFIG));
+		c->cm_key		= cm_getbrdkey("Divas", cfg->card_id);*/
+		break;
+	default:
+		break;
+	}
+
+	c->in_use = TRUE;
+
+	return 0;
+}
+
+void UxCardHandleFree(ux_diva_card_t *card)
+{
+	card->in_use = FALSE;
+}
+
+
+#define PLX_IOBASE 0
+#define DIVAS_IOBASE 1
+void *UxCardMemAttach(ux_diva_card_t *card, int id)
+{
+	if (card->card_type == DIA_CARD_TYPE_DIVA_SERVER)
+	{
+		switch (id)
+		{
+		case DIVAS_SHARED_MEMORY:
+			card->mapped = card->pSHARED;
+			return card->pSHARED;
+			break;
+		case DIVAS_RAM_MEMORY:
+			card->mapped = card->pDRAM;
+			return card->pDRAM;
+			break;
+		case DIVAS_REG_MEMORY:
+			card->mapped = card->pDEVICES;
+			return card->pDEVICES;
+			break;
+		case DIVAS_CFG_MEMORY:
+			card->mapped = card->pCONFIG;
+			return card->pCONFIG;
+			break;
+		default:
+			ASSERT(FALSE);
+			card->mapped = NULL;
+			return (void *) 0;
+		}
+	}
+	else if (card->card_type == DIA_CARD_TYPE_DIVA_SERVER_B)
+	{
+		switch (id)
+		{
+		case PLX_IOBASE:
+			return (void *) card->reset_base;
+			break;
+		case DIVAS_IOBASE:
+			return (void *) card->io_base;
+			break;
+		default:
+			ASSERT(FALSE);
+			return 0;
+		}
+	}
+	
+	else if (card->card_type == DIA_CARD_TYPE_DIVA_SERVER_Q)
+	{
+		switch (id)
+		{
+		case DIVAS_SHARED_MEMORY:
+			card->mapped = card->pSHARED;
+			return card->pSHARED;
+			break;
+		case DIVAS_RAM_MEMORY:
+			card->mapped = card->pDRAM;
+			return card->pDRAM;
+			break;
+		case DIVAS_REG_MEMORY:
+			card->mapped = (void *) card->io_base;
+			return (void *) card->io_base;
+			break;
+		case DIVAS_CTL_MEMORY:
+			card->mapped = card->pCONTROL;
+			return card->pCONTROL;
+			break;
+		default:
+			// ASSERT(FALSE);
+			DPRINTF(("divas: Trying to attach to mem %d", id));
+			card->mapped = NULL;
+			return (void *) 0;
+		}
+	} else
+		DPRINTF(("divas: Tried to attach to unknown card"));
+
+	/* Unknown card type */
+	return NULL;
+}
+
+void UxCardMemDetach(ux_diva_card_t *card, void *address)
+{
+	return; // Just a place holder. No un-mapping done.
+}
+
+void UxCardLog(int turn_on)
+{
+	log_on = turn_on;
+}
+
+/*
+ * Control Register I/O Routines to be performed on Attached I/O ports
+ */
+
+void UxCardPortIoOut(ux_diva_card_t *card, void *AttachedBase, int offset, byte the_byte)
+{
+	word base = (word) (dword) AttachedBase;
+
+	base += offset;
+
+	outb(the_byte, base);
+}
+
+void UxCardPortIoOutW(ux_diva_card_t *card, void *AttachedBase, int offset, word the_word)
+{
+	word base = (word) (dword) AttachedBase;
+
+	base += offset;
+
+	outw(the_word, base);
+}
+
+void UxCardPortIoOutD(ux_diva_card_t *card, void *AttachedBase, int offset, dword the_dword)
+{
+	word base = (word) (dword) AttachedBase;
+
+	base += offset;
+
+	outl(the_dword, base);
+}
+
+byte UxCardPortIoIn(ux_diva_card_t *card, void *AttachedBase, int offset)
+{
+	word base = (word) (dword) AttachedBase;
+
+	base += offset;
+
+	return inb(base);
+}
+
+word UxCardPortIoInW(ux_diva_card_t *card, void *AttachedBase, int offset)
+{
+	word base = (word) (dword) AttachedBase;
+
+	base += offset;
+
+	return inw(base);
+}
+
+/*
+ * Memory mapped card I/O functions
+ */
+
+byte UxCardMemIn(ux_diva_card_t *card, void *address)
+{
+	byte	b;
+	volatile byte* t = (byte*)address;
+
+	b = *t;
+
+	if (log_on)
+	{
+		byte *a = address;
+		a -= (int) card->mapped;
+		DPRINTF(("divas hw: read 0x%02x from 0x%x (memory mapped)", b & 0xff, a));
+    	}
+
+    return(b); 
+}
+
+word UxCardMemInW(ux_diva_card_t *card, void *address)
+{
+	word	w;
+	volatile word* t = (word*)address;
+
+    w = *t;
+
+	if (log_on)
+    {
+		byte *a = address;
+		a -= (int) card->mapped;
+		DPRINTF(("divas hw: read 0x%04x from 0x%x (memory mapped)", w & 0xffff, a));
+    }
+
+    return (w);
+}
+
+dword UxCardMemInD(ux_diva_card_t *card, void *address)
+{
+	dword	dw;
+	volatile dword* t = (dword*)address;
+
+    dw = *t;
+
+	if (log_on)
+    {
+		byte *a = address;
+		a -= (int) card->mapped;
+		DPRINTF(("divas hw: read 0x%08x from 0x%x (memory mapped)", dw, a));
+    }
+
+    return (dw);
+}
+
+void UxCardMemInBuffer(ux_diva_card_t *card, void *address, void *buffer, int length)
+{
+	volatile byte *pSource = address;
+	byte *pDest = buffer;
+
+	while (length--)
+	{
+		*pDest++ = *pSource++;
+	}
+
+	if (log_on)
+    {
+		byte *a = address;
+		a -= (int) card->mapped;
+		pDest = buffer;
+		DPRINTF(("divas hw: read %02x %02x %02x %02x %02x %02x %02x %02x from 0x%x (memory mapped)", 
+		pDest[0] & 0xff, pDest[1] & 0xff, pDest[2] & 0xff, pDest[3] & 0xff,
+		pDest[4] & 0xff, pDest[5] & 0xff, pDest[6] & 0xff, pDest[7] & 0xff,
+		a));
+    }
+
+    return;
+}
+
+void UxCardMemOut(ux_diva_card_t *card, void *address, byte data)
+{
+	volatile byte* t = (byte*)address;
+
+	if (log_on)
+	{
+		byte *a = address;
+		a -= (int) card->mapped;
+		DPRINTF(("divas hw: wrote 0x%02x to 0x%x (memory mapped)", data & 0xff, a));
+	}
+
+	*t = data;
+
+    	return;
+}
+
+void UxCardMemOutW(ux_diva_card_t *card, void *address, word data)
+{
+	volatile word* t = (word*)address;
+
+	if (log_on)
+	{
+		byte *a = address;
+		a -= (int) card->mapped;
+		DPRINTF(("divas hw: wrote 0x%04x to 0x%x (memory mapped)", data & 0xffff, a));
+	}
+
+	*t = data;
+    return;
+}
+
+void UxCardMemOutD(ux_diva_card_t *card, void *address, dword data)
+{
+	volatile dword* t = (dword*)address;
+
+	if (log_on)
+	{
+		byte *a = address;
+		a -= (int) card->mapped;
+		DPRINTF(("divas hw: wrote 0x%08x to 0x%x (memory mapped)", data, a));
+	}
+
+	*t = data;
+    return;
+}
+
+void UxCardMemOutBuffer(ux_diva_card_t *card, void *address, void *buffer, int length)
+{
+	byte 	*pSource = buffer;
+	byte	*pDest = address;
+
+	while (length--)
+	{
+		*pDest++ = *pSource++;
+	}
+
+	if (log_on)
+    {
+		byte *a = address;
+		a -= (int) card->mapped;
+		pDest = buffer;
+		DPRINTF(("divas hw: wrote %02x %02x %02x %02x %02x %02x %02x %02x to 0x%x (memory mapped)", 
+		pDest[0] & 0xff, pDest[1] & 0xff, pDest[2] & 0xff, pDest[3] & 0xff,
+		pDest[4] & 0xff, pDest[5] & 0xff, pDest[6] & 0xff, pDest[7] & 0xff,
+		a));
+    }
+
+    return;
+}
+
+/*
+ * Memory mapped card I/O functions
+ */
+
+byte UxCardIoIn(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address)
+
+{
+	byte the_byte;
+
+    outb(0xFF, card->io_base + 0xC);
+	outw((word) (dword) address, card->io_base + 4);
+
+	the_byte = inb(card->io_base);
+
+	if (log_on)
+    {
+		DPRINTF(("divas hw: read 0x%02x from 0x%x (I/O mapped)", 
+					the_byte & 0xff, address));
+    }
+    
+	return the_byte;
+}
+
+word UxCardIoInW(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address)
+
+{
+	word the_word;
+
+	outb(0xFF, card->io_base + 0xC);
+	outw((word) (dword) address, card->io_base + 4);
+	the_word = inw(card->io_base);
+
+	if (log_on)
+    {
+		DPRINTF(("divas hw: read 0x%04x from 0x%x (I/O mapped)", 
+					the_word & 0xffff, address));
+    }
+
+	return the_word;
+}
+
+dword UxCardIoInD(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address)
+
+{
+	dword the_dword;
+
+	outb(0xFF, card->io_base + 0xC);
+	outw((word) (dword) address, card->io_base + 4);
+	the_dword = inl(card->io_base);
+
+	if (log_on)
+    {
+		DPRINTF(("divas hw: read 0x%08x from 0x%x (I/O mapped)", 
+					the_dword, address));
+    }
+
+    return the_dword;
+}
+
+void UxCardIoInBuffer(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, void *buffer, int length)
+
+{
+	byte *pSource = address;
+	byte *pDest = buffer;
+
+	if ((word) (dword) address & 0x1)
+	{
+		outb(0xFF, card->io_base + 0xC);
+		outw((word) (dword) pSource, card->io_base + 4);
+		*pDest = (byte) inb(card->io_base);
+		pDest++;
+		pSource++;
+		length--;
+		if (!length)
+        {
+            return;
+        }
+    }
+
+	outb(0xFF, card->io_base + 0xC);
+	outw((word) (dword) pSource, card->io_base + 4);
+	insw(card->io_base, (word *)pDest,length%2 ? (length+1)>>1 : length>>1);
+
+	if (log_on)
+    {
+		pDest = buffer;
+		DPRINTF(("divas hw: read %02x %02x %02x %02x %02x %02x %02x %02x from 0x%x (I/O mapped)", 
+		pDest[0] & 0xff, pDest[1] & 0xff, pDest[2] & 0xff, pDest[3] & 0xff,
+		pDest[4] & 0xff, pDest[5] & 0xff, pDest[6] & 0xff, pDest[7] & 0xff,
+		address));
+    }
+
+    return;
+}
+
+/* Output */
+
+void UxCardIoOut(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, byte data)
+{
+	if (log_on)
+    {
+		DPRINTF(("divas hw: wrote 0x%02x to 0x%x (I/O mapped)", 
+					data & 0xff, address));
+    }
+
+	outb(0xFF, card->io_base + 0xC);
+	outw((word) (dword) address, card->io_base + 4);
+	outb((byte) data & 0xFF, card->io_base);
+
+    return;
+}
+
+void UxCardIoOutW(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, word data)
+{
+	if (log_on)
+    {
+		DPRINTF(("divas hw: wrote 0x%04x to 0x%x (I/O mapped)", 
+					data & 0xffff, address));
+    }
+
+	outb(0xFF, card->io_base + 0xC);
+	outw((word) (dword) address, card->io_base + 4);
+	outw((word) data & 0xFFFF, card->io_base);
+
+    return;
+}
+
+void UxCardIoOutD(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, dword data)
+{
+	if (log_on)
+    {
+		DPRINTF(("divas hw: wrote 0x%08x to 0x%x (I/O mapped)", data, address));
+    }
+
+	outb(0xFF, card->io_base + 0xC);
+	outw((word) (dword) address, card->io_base + 4);
+	outl((dword) data & 0xFFFFFFFF, card->io_base);
+
+    return;
+}
+
+void UxCardIoOutBuffer(ux_diva_card_t *card, void *AttachedDivasIOBase, void *address, void *buffer, int length)
+
+{
+	byte 	*pSource = buffer;
+	byte	*pDest = address;
+
+	if ((word) (dword) address & 1)
+	{
+		outb(0xFF, card->io_base + 0xC);
+		outw((word) (dword) pDest, card->io_base + 4);
+		outb(*pSource, card->io_base);
+		pSource++;
+		pDest++;
+		length--;
+		if (!length)
+        {
+			return;
+        }
+	}
+
+    outb(0xFF, card->io_base + 0xC);
+	outw((word) (dword) pDest, card->io_base + 4);
+	outsw(card->io_base, (word *)pSource, length%2 ? (length+1)>>1 : length>>1);
+
+	if (log_on)
+    {
+		pDest = buffer;
+		DPRINTF(("divas hw: wrote %02x %02x %02x %02x %02x %02x %02x %02x to 0x%x (I/O mapped)", 
+		pDest[0] & 0xff, pDest[1] & 0xff, pDest[2] & 0xff, pDest[3] & 0xff,
+		pDest[4] & 0xff, pDest[5] & 0xff, pDest[6] & 0xff, pDest[7] & 0xff,
+		address));
+    }
+
+    return;
+}
+
+void 	Divasintr(int arg, void *unused, struct pt_regs *unused_regs)
+{
+	int i;
+	card_t *card = NULL;
+	ux_diva_card_t *ux_ref = NULL;
+
+	for (i = 0; i < DivasCardNext; i++)
+	{
+
+		if (arg == DivasCards[i].cfg.irq)
+		{
+			card = &DivasCards[i];
+			ux_ref = card->hw;
+	
+			if ((ux_ref) && (card->is_live))
+			{
+				(*ux_ref->user_isr)(ux_ref->user_isr_arg);	
+			}
+			else 
+			{
+				DPRINTF(("divas: ISR couldn't locate card"));
+			}
+		}
+	}
+
+	return;
+}
+
+
+int UxIsrInstall(ux_diva_card_t *card, isr_fn_t *isr_fn, void *isr_arg)
+{
+	int result;
+
+        card->user_isr = isr_fn;
+        card->user_isr_arg = isr_arg;
+
+	result = request_irq(card->irq, Divasintr, SA_INTERRUPT | SA_SHIRQ, "Divas", (void *) isr_arg);
+
+	return result;
+}
+
+void UxIsrRemove(ux_diva_card_t *card, void *dev_id)
+{
+	free_irq(card->irq, card->user_isr_arg);
+}
+
+void UxPciConfigWrite(ux_diva_card_t *card, int size, int offset, void *value)
+{
+	switch (size)
+	{
+	case sizeof(byte):
+		pcibios_write_config_byte(card->bus_num, card->func_num, offset, * (byte *) value);
+		break;
+	case sizeof(word):
+		pcibios_write_config_word(card->bus_num, card->func_num, offset, * (word *) value);
+		break;
+	case sizeof(dword):
+		pcibios_write_config_dword(card->bus_num, card->func_num, offset, * (dword *) value);
+		break;
+	default:
+		printk(KERN_WARNING "Divas: Invalid size in UxPciConfigWrite\n");
+	}
+}
+
+void UxPciConfigRead(ux_diva_card_t *card, int size, int offset, void *value)
+{
+	switch (size)
+	{
+	case sizeof(byte):
+		pcibios_read_config_byte(card->bus_num, card->func_num, offset, (byte *) value);
+		break;
+	case sizeof(word):
+		pcibios_read_config_word(card->bus_num, card->func_num, offset, (word *) value);
+		break;
+	case sizeof(dword):
+		pcibios_read_config_dword(card->bus_num, card->func_num, offset, (unsigned int *) value);
+		break;
+	default:
+		printk(KERN_WARNING "Divas: Invalid size in UxPciConfigRead\n");
+	}
+}
+
+void *UxAlloc(unsigned int size)
+{
+	void *m;
+
+	m = kmalloc(size, GFP_ATOMIC);
+
+	return m;
+}
+
+void UxFree(void *ptr)
+{
+	kfree(ptr);
+}
+
+int UxCardLock(ux_diva_card_t *card)
+{
+	unsigned long flags;
+
+ 	//spin_lock_irqsave(&diva_lock, flags);
+	
+	save_flags(flags);
+	cli();
+	return flags;
+	
+}
+
+void UxCardUnlock(ux_diva_card_t *card, int ipl)
+{
+	//spin_unlock_irqrestore(&diva_lock, ipl);
+
+	restore_flags(ipl);
+
+}
+
+dword UxTimeGet(void)
+{
+	return jiffies;
+}
+
+long UxInterlockedIncrement(ux_diva_card_t *card, long *dst)
+{
+	register volatile long *p;
+	register long ret;
+	int ipl;
+
+	p =dst;
+	
+	ipl = UxCardLock(card);
+
+	*p += 1;
+	ret = *p;
+
+	UxCardUnlock(card,ipl);
+
+	return(ret);
+
+}
+
+long UxInterlockedDecrement(ux_diva_card_t *card, long *dst)
+{
+	register volatile long *p;
+	register long ret;
+	int ipl;
+
+	p =dst;
+	
+	ipl = UxCardLock(card);
+
+	*p -= 1;
+	ret = *p;
+
+	UxCardUnlock(card,ipl);
+
+	return(ret);
+
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/linsys.c linux.19p18/drivers/isdn/eicon/linsys.c
--- linux.vanilla/drivers/isdn/eicon/linsys.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/eicon/linsys.c	Mon Feb 19 18:28:20 2001
@@ -0,0 +1,167 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.10  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+#include <linux/sched.h>
+#undef N_DATA
+#include <linux/tqueue.h>
+
+#include <linux/smp.h>
+struct pt_regs;
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+
+#include "sys.h"
+#include "divas.h"
+#include "adapter.h"
+#include "divalog.h"
+
+#include "uxio.h"
+
+#ifdef MODULE
+void bcopy(void *pSource, void *pDest, dword dwLength)
+{
+	memcpy(pDest, pSource, dwLength);
+}
+#endif
+
+void bzero(void *pDataArea, dword dwLength)
+{
+	memset(pDataArea, 0, dwLength);
+}
+
+int Divas4BRIInitPCI(card_t *card, dia_card_t *cfg)
+{
+	/* Use UxPciConfigWrite	routines to initialise PCI config space */
+
+/*	wPCIcommand = 0x03;
+	cm_write_devconfig16(CMKey, PCI_COMMAND, &wPCIcommand);
+
+	wPCIcommand = 0x280;
+	cm_write_devconfig16(CMKey, PCI_STATUS, &wPCIcommand);
+
+	bPCIcommand = 0x30;
+	cm_write_devconfig16(CMKey, PCI_STATUS, &wPCIcommand);
+*/
+	return 0; 
+}
+
+int DivasPRIInitPCI(card_t *card, dia_card_t *cfg)
+{
+	/* Use UxPciConfigWrite	routines to initialise PCI config space */
+
+/*		wPCIcommand = 0x03;
+	cm_write_devconfig16(CMKey, PCI_COMMAND, &wPCIcommand);
+	
+	wPCIcommand = 0x280;
+	cm_write_devconfig16(CMKey, PCI_STATUS, &wPCIcommand);
+	
+	bPCIcommand = 0x30;
+	cm_write_devconfig8(CMKey, PCI_LATENCY, &bPCIcommand);*/
+
+	return 0;  
+}
+
+int DivasBRIInitPCI(card_t *card, dia_card_t *cfg)
+{
+	/* Need to set these platform dependent values after patching */
+
+	card->hw->reset_base = card->cfg.reset_base;
+	card->hw->io_base = card->cfg.io_base;
+
+	request_region(card->hw->reset_base,0x80,"Divas");
+	request_region(card->hw->io_base,0x20,"Divas");
+
+
+	/* Same as for PRI */
+	return DivasPRIInitPCI(card, cfg);
+}
+
+/* ######################### Stubs of routines that are not done yet ################## */
+/*void DivasLogIdi(card_t *card, ENTITY *e, int request)
+{
+}
+*/
+
+int	DivasDpcSchedule(void)
+{
+	static	struct tq_struct DivasTask;
+
+	DivasTask.routine = DivasDoDpc;
+	DivasTask.data = (void *) 0;
+
+	queue_task(&DivasTask, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+
+	return 0;
+}
+
+int	DivasScheduleRequestDpc(void)
+{
+	static	struct tq_struct DivasTask;
+
+	DivasTask.routine = DivasDoRequestDpc;
+	DivasTask.data = (void *) 0;
+
+	queue_task(&DivasTask, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+
+	return 0;
+}
+
+void    DivasLogAdd(void *buffer, int length)
+{
+    static
+    boolean_t   overflow = FALSE;
+    static
+    boolean_t   busy = FALSE;
+
+    /* make sure we're not interrupting ourselves */
+
+    if (busy)
+    {
+        printk(KERN_DEBUG "Divas: Logging interrupting self !\n");
+        return;
+    }
+    busy = TRUE;
+
+    /* ignore call if daemon isn't running and we've reached limit */
+
+    if (DivasLogFifoFull())
+    {
+        if (!overflow)
+        {
+            printk(KERN_DEBUG "Divas: Trace buffer full\n");
+            overflow = TRUE;
+        }
+        busy = FALSE;
+        return;
+    }
+
+	DivasLogFifoWrite(buffer, length);
+
+    busy = FALSE;
+    return;
+}
+
+/* #################################################################################### */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/log.c linux.19p18/drivers/isdn/eicon/log.c
--- linux.vanilla/drivers/isdn/eicon/log.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/eicon/log.c	Mon Feb 19 18:28:20 2001
@@ -0,0 +1,176 @@
+   
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.5  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+/*
+ * Source file for diva log facility
+ */
+
+#include "sys.h"
+#include "idi.h"
+#include "divas.h"
+#include "adapter.h"
+#include "divalog.h"
+
+#include "uxio.h"
+
+/*Counter to monitor number of messages */ 
+static int m_count;
+ 
+#define     MAX_BUFFERED_MSGS   (1000)
+
+/* Our Linked List Structure to hold message */
+typedef struct klog_link{
+  klog_t klog;
+  struct klog_link *next;
+}KNODE;
+
+/* First & Last structures in list*/
+KNODE *head;
+KNODE *tail;
+
+/* 
+ * retrieve message from FIFO buffer
+ * returns NULL if buffer empty
+ * otherwise returns pointer to entry 
+ */
+
+char	*DivasLogFifoRead(void)
+
+{
+	KNODE *old_head;
+
+	if(head==NULL) 
+	{
+		/* Buffer Empty - No Messages */
+		return NULL;	
+	}
+
+	m_count--;
+	/* Keep track of message to be read & increment to next message*/
+	old_head = head;
+	head = head->next;
+    /*Return ptr to Msg */	
+    return((char *)old_head);
+}
+
+/* 
+ * write message into FIFO buffer
+ */
+
+void	DivasLogFifoWrite(char *entry, int length)
+
+{
+    KNODE *new_klog;
+
+    if(head == NULL) 
+    {
+	/* No Entries in Log */
+	tail=NULL;
+	m_count=0;
+	new_klog=UxAlloc(sizeof(KNODE));
+
+	if(new_klog==NULL)
+	{
+		return;
+	}
+
+	m_count++;
+	bzero(new_klog,sizeof(KNODE));
+
+	/* Set head & tail to point to the new Msg Struct */
+	head=tail=new_klog;
+	tail->next=NULL;
+    }
+    else
+    {
+	new_klog=UxAlloc(sizeof(KNODE));
+	
+	if(new_klog==NULL)
+	{
+		return;
+	}
+
+	m_count++;
+	bzero(new_klog,sizeof(KNODE));
+
+	/* Let last Msg Struct point to new Msg Struct & inc tail */
+	tail->next=new_klog;
+	tail=new_klog;
+	tail->next=NULL;
+    }
+
+    if (length > sizeof(klog_t))
+    {
+        length = sizeof(klog_t);
+    }
+
+    bcopy(entry,&tail->klog,length);
+
+    return;
+}
+
+/*
+ * DivaslogFifoEmpty:return TRUE if FIFO buffer is empty,otherwise FALSE
+ */
+int DivasLogFifoEmpty(void)
+{
+	return (m_count == 0);
+}
+
+/*
+ *DivasLogFifoFull:return TRUE if FIFO buffer is full,otherwise FALSE
+ */
+int DivasLogFifoFull(void)
+{
+	return (m_count == MAX_BUFFERED_MSGS);
+}
+
+/*
+ * generate an IDI log entry
+ */
+
+void	DivasLogIdi(card_t *card, ENTITY *e, int request)
+
+{
+	klog_t		klog;
+
+	bzero(&klog, sizeof(klog));
+
+	klog.time_stamp = UxTimeGet();
+
+	klog.length = sizeof(ENTITY) > sizeof(klog.buffer) ?
+						sizeof(klog.buffer) : sizeof(ENTITY);
+
+	klog.card = (int) (card - DivasCards);
+
+	klog.type = request ? KLOG_IDI_REQ : KLOG_IDI_CALLBACK;
+	klog.code = 0;
+	bcopy(e, klog.buffer, klog.length);
+
+    /* send to the log driver and return */
+
+    DivasLogAdd(&klog, sizeof(klog));
+
+	return;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/pc.h linux.19p18/drivers/isdn/eicon/pc.h
--- linux.vanilla/drivers/isdn/eicon/pc.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/eicon/pc.h	Mon Feb 19 18:28:20 2001
@@ -0,0 +1,317 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.2  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+#ifndef PC_H_INCLUDED
+#define PC_H_INCLUDED
+
+
+#define byte unsigned char
+#define word unsigned short
+#define dword unsigned long
+#if !defined(MIN)
+#define MIN(a,b) ((a)>(b) ? (b) : (a))
+#endif
+#if !defined(MAX)
+#define MAX(a,b) ((a)>(b) ? (a) : (b))
+#endif
+
+/*------------------------------------------------------------------*/
+/* buffer definition                                                */
+/*------------------------------------------------------------------*/
+
+typedef struct {
+  word length;          /* length of data/parameter field           */
+  byte P[270];          /* data/parameter field                     */
+} PBUFFER;
+
+/*------------------------------------------------------------------*/
+/* dual port ram structure                                          */
+/*------------------------------------------------------------------*/
+
+struct dual
+{
+  byte Req;             /* request register                         */
+  byte ReqId;           /* request task/entity identification       */
+  byte Rc;              /* return code register                     */
+  byte RcId;            /* return code task/entity identification   */
+  byte Ind;             /* Indication register                      */
+  byte IndId;           /* Indication task/entity identification    */
+  byte IMask;           /* Interrupt Mask Flag                      */
+  byte RNR;             /* Receiver Not Ready (set by PC)           */
+  byte XLock;           /* XBuffer locked Flag                      */
+  byte Int;             /* ISDN-S interrupt                         */
+  byte ReqCh;           /* Channel field for layer-3 Requests       */
+  byte RcCh;            /* Channel field for layer-3 Returncodes    */
+  byte IndCh;           /* Channel field for layer-3 Indications    */
+  byte MInd;            /* more data indication field               */
+  word MLength;         /* more data total packet length            */
+  byte ReadyInt;        /* request field for ready interrupt        */
+  byte SWReg;           /* Software register for special purposes   */  
+  byte Reserved[11];    /* reserved space                           */
+  byte InterfaceType;   /* interface type 1=16K interface           */
+  word Signature;       /* ISDN-S adapter Signature (GD)            */
+  PBUFFER XBuffer;      /* Transmit Buffer                          */
+  PBUFFER RBuffer;      /* Receive Buffer                           */
+};
+
+/*------------------------------------------------------------------*/
+/* SWReg Values (0 means no command)                                */
+/*------------------------------------------------------------------*/
+#define SWREG_DIE_WITH_LEDON  0x01
+#define SWREG_HALT_CPU        0x02 /* Push CPU into a while(1) loop */         
+
+/*------------------------------------------------------------------*/
+/* Id Fields Coding                                                 */
+/*------------------------------------------------------------------*/
+
+#define ID_MASK 0xe0    /* Mask for the ID field                    */
+#define GL_ERR_ID 0x1f  /* ID for error reporting on global requests*/
+
+#define DSIG_ID  0x00   /* ID for D-channel signaling               */
+#define NL_ID    0x20   /* ID for network-layer access (B or D)     */
+#define BLLC_ID  0x60   /* ID for B-channel link level access       */
+#define TASK_ID  0x80   /* ID for dynamic user tasks                */
+#define TIMER_ID 0xa0   /* ID for timer task                        */
+#define TEL_ID   0xc0   /* ID for telephone support                 */
+#define MAN_ID   0xe0   /* ID for management                        */
+
+/*------------------------------------------------------------------*/
+/* ASSIGN and REMOVE requests are the same for all entities         */
+/*------------------------------------------------------------------*/
+
+#define ASSIGN  0x01
+#define UREMOVE  0xfe   /* without returncode */  
+#define REMOVE  0xff
+
+/*------------------------------------------------------------------*/
+/* Timer Interrupt Task Interface                                   */
+/*------------------------------------------------------------------*/
+
+#define ASSIGN_TIM 0x01
+#define REMOVE_TIM 0xff
+
+/*------------------------------------------------------------------*/
+/* dynamic user task interface                                      */
+/*------------------------------------------------------------------*/
+
+#define ASSIGN_TSK 0x01
+#define REMOVE_TSK 0xff
+
+#define LOAD 0xf0
+#define RELOCATE 0xf1
+#define START 0xf2
+#define LOAD2 0xf3
+#define RELOCATE2 0xf4
+
+/*------------------------------------------------------------------*/
+/* dynamic user task messages                                       */
+/*------------------------------------------------------------------*/
+
+#define TSK_B2          0x0000
+#define TSK_WAKEUP      0x2000
+#define TSK_TIMER       0x4000
+#define TSK_TSK         0x6000
+#define TSK_PC          0xe000
+
+/*------------------------------------------------------------------*/
+/* LL management primitives                                         */
+/*------------------------------------------------------------------*/
+
+#define ASSIGN_LL 1     /* assign logical link                      */
+#define REMOVE_LL 0xff  /* remove logical link                      */
+
+/*------------------------------------------------------------------*/
+/* LL service primitives                                            */
+/*------------------------------------------------------------------*/
+
+#define LL_UDATA 1      /* link unit data request/indication        */
+#define LL_ESTABLISH 2  /* link establish request/indication        */
+#define LL_RELEASE 3    /* link release request/indication          */
+#define LL_DATA 4       /* data request/indication                  */
+#define LL_LOCAL 5      /* switch to local operation (COM only)     */
+#define LL_DATA_PEND 5  /* data pending indication (SDLC SHM only)  */
+#define LL_REMOTE 6     /* switch to remote operation (COM only)    */
+#define LL_TEST 8       /* link test request                        */
+#define LL_MDATA 9      /* more data request/indication             */
+#define LL_BUDATA 10    /* broadcast unit data request/indication   */
+#define LL_XID 12       /* XID command request/indication           */
+#define LL_XID_R 13     /* XID response request/indication          */
+
+/*------------------------------------------------------------------*/
+/* NL service primitives                                            */
+/*------------------------------------------------------------------*/
+
+#define N_MDATA         1       /* more data to come REQ/IND        */
+#define N_CONNECT       2       /* OSI N-CONNECT REQ/IND            */
+#define N_CONNECT_ACK   3       /* OSI N-CONNECT CON/RES            */
+#define N_DISC          4       /* OSI N-DISC REQ/IND               */
+#define N_DISC_ACK      5       /* OSI N-DISC CON/RES               */
+#define N_RESET         6       /* OSI N-RESET REQ/IND              */
+#define N_RESET_ACK     7       /* OSI N-RESET CON/RES              */
+#define N_DATA          8       /* OSI N-DATA REQ/IND               */
+#define N_EDATA         9       /* OSI N-EXPEDITED DATA REQ/IND     */
+#define N_UDATA         10      /* OSI D-UNIT-DATA REQ/IND          */
+#define N_BDATA         11      /* BROADCAST-DATA REQ/IND           */
+#define N_DATA_ACK      12      /* data ack ind for D-bit procedure */
+#define N_EDATA_ACK     13      /* data ack ind for INTERRUPT       */
+
+#define N_Q_BIT         0x10    /* Q-bit for req/ind                */
+#define N_M_BIT         0x20    /* M-bit for req/ind                */
+#define N_D_BIT         0x40    /* D-bit for req/ind                */
+
+/*------------------------------------------------------------------*/
+/* Signaling management primitives                                  */
+/*------------------------------------------------------------------*/
+
+#define ASSIGN_SIG 1    /* assign signaling task                    */
+#define UREMOVE_SIG 0xfe /* remove signaling task without returncode */
+#define REMOVE_SIG 0xff /* remove signaling task                    */
+
+/*------------------------------------------------------------------*/
+/* Signaling service primitives                                     */
+/*------------------------------------------------------------------*/
+
+#define CALL_REQ 1      /* call request                             */
+#define CALL_CON 1      /* call confirmation                        */
+#define CALL_IND 2      /* incoming call connected                  */
+#define LISTEN_REQ 2    /* listen request                           */
+#define HANGUP 3        /* hangup request/indication                */
+#define SUSPEND 4       /* call suspend request/confirm             */
+#define RESUME 5        /* call resume request/confirm              */
+#define SUSPEND_REJ 6   /* suspend rejected indication              */
+#define USER_DATA 8     /* user data for user to user signaling     */
+#define CONGESTION 9    /* network congestion indication            */
+#define INDICATE_REQ 10 /* request to indicate an incoming call     */
+#define INDICATE_IND 10 /* indicates that there is an incoming call */
+#define CALL_RES 11     /* accept an incoming call                  */
+#define CALL_ALERT 12   /* send ALERT for incoming call             */
+#define INFO_REQ 13     /* INFO request                             */
+#define INFO_IND 13     /* INFO indication                          */
+#define REJECT 14       /* reject an incoming call                  */
+#define RESOURCES 15    /* reserve B-Channel hardware resources     */
+#define TEL_CTRL 16     /* Telephone control request/indication     */
+#define STATUS_REQ 17   /* Request D-State (returned in INFO_IND)   */
+#define FAC_REG_REQ 18  /* connection idependent fac registration   */
+#define FAC_REG_ACK 19  /* fac registration acknowledge             */
+#define FAC_REG_REJ 20  /* fac registration reject                  */
+#define CALL_COMPLETE 21/* send a CALL_PROC for incoming call       */
+#define FACILITY_REQ 22 /* send a Facility Message type             */
+#define FACILITY_IND 22 /* Facility Message type indication         */
+#define SIG_CTRL     29 /* Control for signalling hardware          */
+#define DSP_CTRL     30 /* Control for DSPs                         */
+#define LAW_REQ      31 /* Law config request for (returns info_i)  */ 
+
+ 
+/*------------------------------------------------------------------*/
+/* management service primitives                                    */
+/*------------------------------------------------------------------*/
+
+#define MAN_READ        2
+#define MAN_WRITE       3
+#define MAN_EXECUTE     4
+#define MAN_EVENT_ON    5
+#define MAN_EVENT_OFF   6
+#define MAN_LOCK        7
+#define MAN_UNLOCK      8   
+
+#define MAN_INFO_IND    2
+#define MAN_EVENT_IND   3
+#define MAN_TRACE_IND   4  
+
+#define MAN_ESC         0x80
+
+/*------------------------------------------------------------------*/
+/* return code coding                                               */
+/*------------------------------------------------------------------*/
+
+#define UNKNOWN_COMMAND         0x01    /* unknown command          */
+#define WRONG_COMMAND           0x02    /* wrong command            */
+#define WRONG_ID                0x03    /* unknown task/entity id   */
+#define WRONG_CH                0x04    /* wrong task/entity id     */
+#define UNKNOWN_IE              0x05    /* unknown information el.  */
+#define WRONG_IE                0x06    /* wrong information el.    */
+#define OUT_OF_RESOURCES        0x07    /* ISDN-S card out of res.  */
+#define ADAPTER_DEAD            0x08    /* ISDN card CPU halted     */ 
+#define N_FLOW_CONTROL          0x10    /* Flow-Control, retry      */
+#define ASSIGN_RC               0xe0    /* ASSIGN acknowledgement   */
+#define ASSIGN_OK               0xef    /* ASSIGN OK                */
+#define OK_FC                   0xfc    /* Flow-Control RC          */
+#define READY_INT               0xfd    /* Ready interrupt          */
+#define TIMER_INT               0xfe    /* timer interrupt          */
+#define OK                      0xff    /* command accepted         */
+
+/*------------------------------------------------------------------*/
+/* information elements                                             */
+/*------------------------------------------------------------------*/
+
+#define SHIFT 0x90              /* codeset shift                    */
+#define MORE 0xa0               /* more data                        */
+#define CL 0xb0                 /* congestion level                 */
+
+        /* codeset 0                                                */
+
+#define BC  0x04                /* Bearer Capability                */
+#define CAU 0x08                /* cause                            */
+#define CAD 0x0c                /* Connected address                */
+#define CAI 0x10                /* call identity                    */
+#define CHI 0x18                /* channel identification           */
+#define LLI 0x19                /* logical link id                  */
+#define CHA 0x1a                /* charge advice                    */
+#define DT  0x29                /* ETSI date/time                   */
+#define KEY 0x2c                /* keypad information element       */
+#define FTY 0x1c                /* facility information element     */ 
+#define DSP 0x28                /* display                          */
+#define OAD 0x6c                /* origination address              */
+#define OSA 0x6d                /* origination sub-address          */
+#define CPN 0x70                /* called party number              */
+#define DSA 0x71                /* destination sub-address          */
+#define RDX 0x73                /* redirected number extended       */
+#define RDN 0x74                /* redirected number                */  
+#define LLC 0x7c                /* low layer compatibility          */
+#define HLC 0x7d                /* high layer compatibility         */
+#define UUI 0x7e                /* user user information            */
+#define ESC 0x7f                /* escape extension                 */
+
+#define DLC 0x20                /* data link layer configuration    */
+#define NLC 0x21                /* network layer configuration      */
+
+        /* codeset 6                                                */
+
+#define SIN 0x01                /* service indicator                */
+#define CIF 0x02                /* charging information             */
+#define DATE 0x03               /* date                             */
+#define CPS 0x07                /* called party status              */
+
+/*------------------------------------------------------------------*/
+/* TEL_CTRL contents                                                */
+/*------------------------------------------------------------------*/
+
+#define RING_ON         0x01
+#define RING_OFF        0x02
+#define HANDS_FREE_ON   0x03
+#define HANDS_FREE_OFF  0x04
+#define ON_HOOK         0x80
+#define OFF_HOOK        0x90
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/pc_maint.h linux.19p18/drivers/isdn/eicon/pc_maint.h
--- linux.vanilla/drivers/isdn/eicon/pc_maint.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/eicon/pc_maint.h	Mon Feb 19 18:28:20 2001
@@ -0,0 +1,162 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.0  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+#ifndef PC_MAINT_H
+#define PC_MAINT_H
+
+#if !defined(MIPS_SCOM)
+#define BUFFER_SZ  48
+#define MAINT_OFFS 0x380
+#else
+#define BUFFER_SZ  128
+#define MAINT_OFFS 0xff00
+#endif
+
+#define MIPS_BUFFER_SZ  128
+#define MIPS_MAINT_OFFS 0xff00
+
+#define DO_LOG                     1
+#define MEMR                    2
+#define MEMW                    3
+#define IOR                     4
+#define IOW                     5
+#define B1TEST                  6
+#define B2TEST                  7
+#define BTESTOFF                8
+#define DSIG_STATS              9
+#define B_CH_STATS              10
+#define D_CH_STATS              11
+#define BL1_STATS               12
+#define BL1_STATS_C             13
+#define GET_VERSION             14
+#define OS_STATS                15
+#define XLOG_SET_MASK           16
+#define XLOG_GET_MASK           17
+#define DSP_READ                20
+#define DSP_WRITE               21
+
+#define OK 0xff
+#define MORE_EVENTS 0xfe
+#define NO_EVENT 1
+
+struct DSigStruc
+{
+  byte Id;
+  byte uX;
+  byte listen;
+  byte active;
+  byte sin[3];
+  byte bc[6];
+  byte llc[6];
+  byte hlc[6];
+  byte oad[20];
+};
+
+struct BL1Struc {
+  dword cx_b1;
+  dword cx_b2;
+  dword cr_b1;
+  dword cr_b2;
+  dword px_b1;
+  dword px_b2;
+  dword pr_b1;
+  dword pr_b2;
+  word er_b1;
+  word er_b2;
+};
+
+struct L2Struc {
+  dword XTotal;
+  dword RTotal;
+  word XError;
+  word RError;
+};
+
+struct OSStruc {
+  word free_n;
+};
+
+typedef union
+{
+  struct DSigStruc DSigStats;
+  struct BL1Struc BL1Stats;
+  struct L2Struc L2Stats;
+  struct OSStruc OSStats;
+  byte   b[BUFFER_SZ];
+  word   w[BUFFER_SZ>>1];
+  word   l[BUFFER_SZ>>2]; /* word is wrong, do not use! Use 'd' instead. */
+  dword  d[BUFFER_SZ>>2];
+} BUFFER;
+
+typedef union
+{
+  struct DSigStruc DSigStats;
+  struct BL1Struc BL1Stats;
+  struct L2Struc L2Stats;
+  struct OSStruc OSStats;
+  byte   b[MIPS_BUFFER_SZ];
+  word   w[MIPS_BUFFER_SZ>>1];
+  word   l[BUFFER_SZ>>2]; /* word is wrong, do not use! Use 'd' instead. */
+  dword  d[MIPS_BUFFER_SZ>>2];
+} MIPS_BUFFER;
+
+
+#if !defined(MIPS_SCOM)
+struct pc_maint
+{
+  byte req;
+  byte rc;
+  byte *mem;  /*far*/
+  short length;
+  word port;
+  byte fill[6];
+  BUFFER data;
+};
+#else
+struct pc_maint
+{
+  byte req;
+  byte rc;
+  byte reserved[2];     /* R3000 alignment ... */
+  byte far *mem;
+  short length;
+  word port;
+  byte fill[4];         /* data at offset 16   */
+  BUFFER data;
+};
+#endif
+
+struct mi_pc_maint
+{
+  byte req;
+  byte rc;
+  byte reserved[2];     /* R3000 alignment ... */
+  byte *mem; /*far*/
+  short length;
+  word port;
+  byte fill[4];         /* data at offset 16   */
+  MIPS_BUFFER data;
+};
+
+#endif /* PC_MAINT_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/pr_pc.h linux.19p18/drivers/isdn/eicon/pr_pc.h
--- linux.vanilla/drivers/isdn/eicon/pr_pc.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/eicon/pr_pc.h	Mon Feb 19 18:28:20 2001
@@ -0,0 +1,83 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.0  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+#if !defined(PR_PC_H)
+#define PR_PC_H
+
+struct pr_ram {
+  word NextReq;         /* pointer to next Req Buffer               */
+  word NextRc;          /* pointer to next Rc Buffer                */
+  word NextInd;         /* pointer to next Ind Buffer               */
+  byte ReqInput;        /* number of Req Buffers sent               */
+  byte ReqOutput;       /* number of Req Buffers returned           */
+  byte ReqReserved;     /* number of Req Buffers reserved           */
+  byte Int;             /* ISDN-P interrupt                         */
+  byte XLock;           /* Lock field for arbitration               */
+  byte RcOutput;        /* number of Rc buffers received            */
+  byte IndOutput;       /* number of Ind buffers received           */
+  byte IMask;           /* Interrupt Mask Flag                      */
+  byte Reserved1[2];    /* reserved field, do not use               */
+  byte ReadyInt;        /* request field for ready interrupt        */
+  byte Reserved2[12];   /* reserved field, do not use               */
+  byte InterfaceType;   /* interface type 1=16K interface           */
+  word Signature;       /* ISDN-P initialized indication            */
+  byte B[1];            /* buffer space for Req,Ind and Rc          */
+};
+
+typedef struct {
+  word next;
+  byte Req;
+  byte ReqId;
+  byte ReqCh;
+  byte Reserved1;
+  word Reference;
+  byte Reserved[8];
+  PBUFFER XBuffer;
+} REQ;
+
+typedef struct {
+  word next;
+  byte Rc;
+  byte RcId;
+  byte RcCh;
+  byte Reserved1;
+  word Reference;
+  byte Reserved2[8];
+} RC;
+
+typedef struct {
+  word next;
+  byte Ind;
+  byte IndId;
+  byte IndCh;
+  byte MInd;
+  word MLength;
+  word Reference;
+  byte RNR;
+  byte Reserved;
+  dword Ack;
+  PBUFFER RBuffer;
+} IND;
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/pri.c linux.19p18/drivers/isdn/eicon/pri.c
--- linux.vanilla/drivers/isdn/eicon/pri.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/eicon/pri.c	Mon Feb 19 18:28:20 2001
@@ -0,0 +1,530 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.5  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+/* Diva Server PRI specific part of initialisation */
+#include "sys.h"
+#include "idi.h"
+#include "divas.h"
+#include "pc.h"
+#include "pr_pc.h"
+#include "dsp_defs.h"
+
+#include "adapter.h"
+#include "uxio.h"
+
+#define	DIVAS_LOAD_CMD		0x02
+#define	DIVAS_START_CMD		0x03
+#define	DIVAS_IRQ_RESET		0xC18
+#define DIVAS_IRQ_RESET_VAL	0xFE
+
+#define	TEST_INT_DIVAS		0x11
+#define TEST_INT_DIVAS_BRI	0x12
+
+#define DIVAS_RESET	0x81
+#define DIVAS_LED1	0x04
+#define DIVAS_LED2	0x08
+#define DIVAS_LED3	0x20
+#define DIVAS_LED4	0x40
+
+#define	DIVAS_RESET_REG		0x20
+
+#define	DIVAS_SIGNATURE	0x4447
+
+/* offset to start of MAINT area (used by xlog) */
+
+#define	DIVAS_MAINT_OFFSET	0xef00	/* value for PRI card */
+
+#define MP_PROTOCOL_ADDR		0xA0011000
+#define MP_DSP_CODE_BASE		0xa03a0000  
+
+typedef struct {
+		dword cmd;
+		dword addr;
+		dword len;
+		dword err;
+		dword live;
+		dword reserved[(0x1020>>2)-6];
+		dword signature;
+		byte  data[1];
+} diva_server_boot_t;
+
+byte mem_in(ADAPTER *a, void *adr);
+word mem_inw(ADAPTER *a, void *adr);
+void mem_in_buffer(ADAPTER *a, void *adr, void *P, word length);
+void mem_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e);
+void mem_out(ADAPTER *a, void *adr, byte data);
+void mem_outw(ADAPTER *a, void *adr, word data);
+void mem_out_buffer(ADAPTER *a, void *adr, void *P, word length);
+void mem_inc(ADAPTER *a, void *adr);
+
+int DivasPRIInitPCI(card_t *card, dia_card_t *cfg);
+static int pri_ISR (card_t* card);
+
+static int diva_server_reset(card_t *card)
+{
+	byte *reg;
+	diva_server_boot_t *boot = NULL;
+	dword live = 0;
+	int	i = 0;
+	dword	dwWait;
+
+	DPRINTF(("divas: reset Diva Server PRI"));
+
+	reg = UxCardMemAttach(card->hw, DIVAS_REG_MEMORY);
+
+	UxCardMemOut(card->hw, &reg[DIVAS_RESET_REG], DIVAS_RESET | 
+						DIVAS_LED1 | DIVAS_LED2 | DIVAS_LED3 | DIVAS_LED4);
+
+	for (dwWait = 0x000fffff; dwWait; dwWait--)
+		;
+
+	UxCardMemOut(card->hw, &reg[DIVAS_RESET_REG], 0x00);
+
+	for (dwWait = 0x000fffff; dwWait; dwWait--)
+		;
+
+	UxCardMemDetach(card->hw, reg);
+
+	boot = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY);
+
+	UxCardMemOutD(card->hw, boot->reserved, 0);
+
+	live = UxCardMemInD(card->hw, &boot->live);
+
+	for (i=0; i<5; i++)
+	{
+		if (live != UxCardMemInD(card->hw, &boot->live))
+		{
+			break;
+		}
+		UxPause(10);
+	}
+
+	if (i == 5)
+	{
+		UxCardMemDetach(card->hw, boot);
+
+		DPRINTF(("divas: card is reset but CPU not running"));
+		return -1;
+	}
+
+	UxCardMemDetach(card->hw, boot);
+
+	DPRINTF(("divas: card reset after %d ms", i * 10));
+
+	return 0;
+}
+
+static int diva_server_config(card_t *card, dia_config_t *config)
+{
+	byte *shared;
+	int i, j;
+
+	DPRINTF(("divas: configure Diva Server PRI"));
+
+	shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+	UxCardLog(0);
+	for (i=0; i<256; i++)
+	{
+		UxCardMemOut(card->hw, &shared[i], 0);
+	}
+
+	UxCardMemOut(card->hw, &shared[ 8], config->tei);
+	UxCardMemOut(card->hw, &shared[ 9], config->nt2);
+	UxCardMemOut(card->hw, &shared[10], config->sig_flags);
+	UxCardMemOut(card->hw, &shared[11], config->watchdog);
+	UxCardMemOut(card->hw, &shared[12], config->permanent);
+	UxCardMemOut(card->hw, &shared[13], config->x_interface);
+	UxCardMemOut(card->hw, &shared[14], config->stable_l2);
+	UxCardMemOut(card->hw, &shared[15], config->no_order_check);
+	UxCardMemOut(card->hw, &shared[16], config->handset_type);
+	UxCardMemOut(card->hw, &shared[17], 0);
+	UxCardMemOut(card->hw, &shared[18], config->low_channel);
+	UxCardMemOut(card->hw, &shared[19], config->prot_version);
+	UxCardMemOut(card->hw, &shared[20], config->crc4);
+
+	for (i=0; i<2; i++)
+	{
+		for (j=0; j<32; j++)
+		{
+			UxCardMemOut(card->hw, &shared[32+(i*96)+j],config->terminal[i].oad[j]);
+		}
+
+		for (j=0; j<32; j++)
+		{
+			UxCardMemOut(card->hw, &shared[64+(i*96)+j],config->terminal[i].osa[j]);
+		}
+
+		for (j=0; j<32; j++)
+		{
+			UxCardMemOut(card->hw, &shared[96+(i*96)+j],config->terminal[i].spid[j]);
+		}
+	}
+
+	UxCardMemDetach(card->hw, shared);
+
+	return 0;
+}
+
+static
+void diva_server_reset_int(card_t *card)
+{
+	byte *cfg;
+
+	cfg = UxCardMemAttach(card->hw, DIVAS_CFG_MEMORY);
+
+	UxCardMemOutW(card->hw, &cfg[DIVAS_IRQ_RESET], DIVAS_IRQ_RESET_VAL);
+	UxCardMemOutW(card->hw, &cfg[DIVAS_IRQ_RESET + 2], 0);
+	UxCardMemDetach(card->hw, cfg);
+
+	return;
+}
+
+ 
+static int diva_server_test_int(card_t *card)
+{
+	int i;
+	byte *shared;
+	byte req_int;
+
+	DPRINTF(("divas: test interrupt for Diva Server PRI"));
+
+	shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+	UxCardMemIn(card->hw, &shared[0x3FE]);
+	UxCardMemOut(card->hw, &shared[0x3FE], 0);
+	UxCardMemIn(card->hw, &shared[0x3FE]);
+
+	UxCardMemDetach(card->hw, shared);
+
+	diva_server_reset_int(card);
+
+	shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY);
+
+	card->test_int_pend = TEST_INT_DIVAS;
+
+	req_int = UxCardMemIn(card->hw, &(((struct pr_ram *)shared)->ReadyInt));
+
+	req_int++;
+
+	UxCardMemOut(card->hw, &(((struct pr_ram *)shared)->ReadyInt), req_int);
+
+	UxCardMemDetach(card->hw, shared);
+
+	UxCardLog(0);
+	for (i = 0; i < 50; i++)
+	{
+		if (!card->test_int_pend)
+		{
+			break;
+		}
+		UxPause(10);
+	}
+
+
+	if (card->test_int_pend)
+	{
+
+		DPRINTF(("active: timeout waiting for card to interrupt"));
+		return (-1);
+	
+	}
+	
+	return 0;
+}
+
+
+static void print_hdr(unsigned char *code, int offset)
+{
+	unsigned char hdr[80];
+		int i;
+
+	i = 0;
+
+	while ((i < (DIM(hdr) -1)) && 
+		(code[offset + i] != '\0') &&
+		(code[offset + i] != '\r') &&
+		(code[offset + i] != '\n'))
+	{
+		hdr[i] = code[offset + i];
+		i++;
+	}
+
+	hdr[i] = '\0';
+
+	DPRINTF(("divas: loading %s", hdr));
+}
+
+static int diva_server_load(card_t *card, dia_load_t *load)
+{
+	diva_server_boot_t *boot;
+	int i, offset, length;
+	dword cmd = 0;
+
+	DPRINTF(("divas: loading Diva Server PRI"));
+
+	boot = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY);
+
+	switch(load->code_type)
+	{
+		case DIA_CPU_CODE:
+			DPRINTF(("divas: RISC code"));
+			print_hdr(load->code, 0x80);
+
+			UxCardMemOutD(card->hw, &boot->addr, MP_PROTOCOL_ADDR);
+			break;
+
+		case DIA_DSP_CODE:
+			DPRINTF(("divas: DSP code"));
+			print_hdr(load->code, 0x0);
+
+			UxCardMemOutD(card->hw, &boot->addr,  
+				(MP_DSP_CODE_BASE + (((sizeof(dword) +
+				(sizeof(t_dsp_download_desc) * DSP_MAX_DOWNLOAD_COUNT))
+				+ ~ALIGNMENT_MASK_MAESTRA) & ALIGNMENT_MASK_MAESTRA)));
+			break;
+
+		case DIA_TABLE_CODE:
+			DPRINTF(("divas: TABLE code"));
+			UxCardMemOutD(card->hw, &boot->addr,
+				(MP_DSP_CODE_BASE + sizeof(dword)));
+			break;
+
+		case DIA_CONT_CODE:
+			DPRINTF(("divas: continuation code"));
+			break;
+
+        case DIA_DLOAD_CNT:
+			DPRINTF(("divas: COUNT code"));
+			UxCardMemOutD(card->hw, &boot->addr, MP_DSP_CODE_BASE);
+			break;
+
+		default:
+			DPRINTF(("divas: unknown code type"));
+			UxCardMemDetach(card->hw, boot);
+			return -1;
+	}
+
+	UxCardLog(0);
+	offset = 0;
+
+	do
+	{
+		length = (load->length - offset >= 400) ? 400 : load->length - offset;
+
+		for (i=0; i<length; i++)
+		{
+			UxCardMemOut(card->hw, &boot->data[i], load->code[offset+i]);
+		}
+
+        for (i=0; i<length; i++)
+		{
+			if (load->code[offset + i] != UxCardMemIn(card->hw, &boot->data[i]))
+			{
+				UxCardMemDetach(card->hw, boot);
+
+				DPRINTF(("divas: card code block verify failed"));
+				return -1;
+			}
+		}
+	
+		UxCardMemOutD(card->hw, &boot->len, (length + 3) / 4);
+		UxCardMemOutD(card->hw, &boot->cmd, DIVAS_LOAD_CMD);
+
+		for (i=0; i<50000; i++)
+		{
+			cmd = UxCardMemInD(card->hw, &boot->cmd);
+			if (!cmd)
+			{
+				break;
+			}
+			/*UxPause(1);*/
+		}
+
+		if (cmd)
+		{
+			DPRINTF(("divas: timeout waiting for card to ACK load (offset = %d)", offset));
+			UxCardMemDetach(card->hw, boot);
+			return -1;
+		}
+
+		offset += length;
+
+	} while (offset < load->length);
+
+	UxCardMemDetach(card->hw, boot);
+
+	DPRINTF(("divas: DIVA Server card loaded"));
+
+	return 0;
+}
+
+static int diva_server_start(card_t *card, byte *channels)
+{
+	diva_server_boot_t *boot;
+	byte *ram;
+	int	i;
+	dword signature = 0;
+
+	DPRINTF(("divas: start Diva Server PRI"));
+
+	card->is_live = FALSE;
+
+	boot = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY);
+
+	UxCardMemOutD(card->hw, &boot->addr, MP_PROTOCOL_ADDR);
+	UxCardMemOutD(card->hw, &boot->cmd, DIVAS_START_CMD);
+
+	UxCardLog(0);
+
+	for (i = 0; i < 300; i++)
+	{
+		signature = UxCardMemInD(card->hw, &boot->signature);
+		if ((signature >> 16) == DIVAS_SIGNATURE)
+		{
+			DPRINTF(("divas: started card after %d ms", i * 10));
+			break;
+		}
+		UxPause(10);
+	}
+
+	if ((signature >> 16) != DIVAS_SIGNATURE)
+	{
+		UxCardMemDetach(card->hw, boot);
+		DPRINTF(("divas: timeout waiting for card to run protocol code (sig = 0x%x)", signature));
+		return -1;
+	}
+
+	card->is_live = TRUE;
+
+	ram = (byte *) boot;
+	ram += DIVAS_SHARED_OFFSET;
+
+	*channels = UxCardMemIn(card->hw, &ram[0x3F6]);
+	card->serial_no = UxCardMemInD(card->hw, &ram[0x3F0]);
+
+	UxCardMemDetach(card->hw, boot);
+
+	if (diva_server_test_int(card))
+	{
+		DPRINTF(("divas: interrupt test failed"));
+		return -1;	
+	}
+
+	DPRINTF(("divas: DIVA Server card started"));
+
+	return 0;
+}
+
+static
+int 	diva_server_mem_get(card_t *card, mem_block_t *mem_block)
+
+{
+	byte	*a;
+	byte	*card_addr;
+	word	length = 0;
+	int		i;
+
+	a = UxCardMemAttach(card->hw, DIVAS_RAM_MEMORY);
+
+	card_addr = a;
+	card_addr += mem_block->addr;
+
+	for (i=0; i < sizeof(mem_block->data); i++)
+	{
+		mem_block->data[i] = UxCardMemIn(card->hw, card_addr);
+		card_addr++;
+		length++;
+	}
+
+	UxCardMemDetach(card->hw, a);
+
+	return length;
+}
+
+/*
+ * Initialise PRI specific entry points
+ */
+
+int DivasPriInit(card_t *card, dia_card_t *cfg)
+{
+	DPRINTF(("divas: initialise Diva Server PRI"));
+
+	if (DivasPRIInitPCI(card, cfg) == -1)
+	{
+		return -1;
+	}
+
+	card->card_reset = diva_server_reset;
+	card->card_load = diva_server_load;
+	card->card_config = diva_server_config;
+	card->card_start = diva_server_start;
+	card->reset_int = diva_server_reset_int;
+	card->card_mem_get = diva_server_mem_get;
+
+	card->xlog_offset = DIVAS_MAINT_OFFSET;
+
+	card->out = DivasOut;
+	card->test_int = DivasTestInt;
+	card->dpc = DivasDpc;
+	card->clear_int = DivasClearInt;
+	card->card_isr  = pri_ISR;
+
+	card->a.ram_out = mem_out;
+	card->a.ram_outw = mem_outw;
+	card->a.ram_out_buffer = mem_out_buffer;
+	card->a.ram_inc = mem_inc;
+
+	card->a.ram_in = mem_in;
+	card->a.ram_inw = mem_inw;
+	card->a.ram_in_buffer = mem_in_buffer;
+	card->a.ram_look_ahead = mem_look_ahead;
+
+	return 0;
+}
+
+
+static int pri_ISR (card_t* card) 
+{
+	int served = 0;
+	byte* cfg = UxCardMemAttach(card->hw, DIVAS_CFG_MEMORY);
+	volatile unsigned long* isr = (unsigned long*)&cfg[DIVAS_IRQ_RESET];
+	register unsigned long val = *isr;
+	
+	if (val & 0x80000000)  /* our card had caused interrupt ??? */
+	{
+		served = 1;
+		card->int_pend  += 1;
+		DivasDpcSchedule(); /* ISR DPC */
+
+		*isr = (unsigned long)~0x03E00000; /* Clear interrupt line */
+	}
+
+	UxCardMemDetach(card->hw, cfg);
+
+	return (served != 0);
+}
+
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/sys.h linux.19p18/drivers/isdn/eicon/sys.h
--- linux.vanilla/drivers/isdn/eicon/sys.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/eicon/sys.h	Mon Feb 19 18:28:20 2001
@@ -0,0 +1,116 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.2  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+/* Environment provided by system and miscellaneous definitions */
+
+#if !defined(SYS_H)
+#define SYS_H
+
+/* abreviations for unsigned types */
+typedef int boolean_t;
+
+typedef unsigned char byte;
+
+typedef unsigned long dword;
+typedef unsigned short word;
+
+/* abreviations for volatile types */
+
+typedef volatile byte	vbyte;
+typedef volatile word	vword;
+typedef volatile dword	vdword;
+
+/* Booleans */
+
+#if !defined(TRUE)
+#define TRUE    (1)
+#define FALSE   (0)
+#endif
+
+/* NULL pointer */
+
+#if !defined(NULL)
+#define NULL    ((void *) 0)
+#endif
+
+/* MIN and MAX */
+
+#if !defined(MIN)
+#define MIN(a,b) ((a)>(b) ? (b) : (a))
+#endif
+#if !defined(MAX)
+#define MAX(a,b) ((a)>(b) ? (a) : (b))
+#endif
+
+/* Return the dimension of an array */
+
+#if !defined(DIM)
+#define DIM(array)  (sizeof (array)/sizeof ((array)[0]))
+#endif
+
+/*
+ * Return the number of milliseconds since last boot
+ */
+
+extern	dword	UxTimeGet(void);
+
+extern	void 	DivasSprintf(char *buffer, char *format, ...);
+extern	void 	DivasPrintf(char *format, ...);
+
+/* fatal errors, asserts and tracing */
+
+void HwFatalErrorFrom(char *file, int line);
+void HwFatalError(void);
+/* void HwAssert(char *file, int line, char *condition); */
+
+#include <linux/kernel.h>
+#define _PRINTK printk
+
+#define _PRINTF	DivasPrintf
+void _PRINTF(char *format, ...);
+#define PRINTF(arg_list)	_PRINTF arg_list
+#if defined DTRACE
+# define DPRINTF(arg_list)	_PRINTF arg_list
+# define KDPRINTF(arg_list)	_PRINTF arg_list ; _PRINTK arg_list ; _PRINTK("\n");
+#else
+# define DPRINTF(arg_list)	(void)0
+# define KDPRINTF(arg_list)	_PRINTK arg_list ; _PRINTK("\n");
+#endif
+
+#if !defined(ASSERT)
+#if defined DEBUG || defined DBG
+# define HwFatalError()	HwFatalErrorFrom(__FILE__, __LINE__)
+# define ASSERT(cond)								\
+		if (!(cond)) 								\
+		{											\
+/*			HwAssert(__FILE__, __LINE__, #cond);*/	\
+		}
+#else
+# define ASSERT(cond)	((void)0)
+#endif
+#endif /* !defined(ASSERT) */
+
+#define TRACE	(_PRINTF(__FILE__"@%d\n", __LINE__))
+
+#endif /* SYS_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/uxio.h linux.19p18/drivers/isdn/eicon/uxio.h
--- linux.vanilla/drivers/isdn/eicon/uxio.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/eicon/uxio.h	Tue Feb 20 13:44:47 2001
@@ -0,0 +1,217 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.6  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+/*
+ * Interface to Unix specific code for performing card I/O
+ */
+
+#if !defined(UXIO_H)
+#define UXIO_H
+
+#include "sys.h"
+#include "adapter.h"
+
+
+struct pt_regs;
+
+/* user callback, returns zero if interrupt was from this card */
+typedef	void		isr_fn_t(void *);
+struct ux_diva_card_s
+{
+	word	in_use;
+	int		io_base;
+	int		reset_base;
+	int		card_type;
+	byte		*mapped;
+	int		bus_num;
+	int		func_num;
+	int		slot;
+	int		irq;
+	byte		*pDRAM;
+	byte		*pDEVICES;
+	byte		*pCONFIG;
+	byte		*pSHARED;
+	byte		*pCONTROL;
+	word		features;
+	void		*user_isr_arg;
+	isr_fn_t	*user_isr;
+};
+
+void bcopy(void *pSource, void *pDest, dword dwLength);
+void bzero(void *pDataArea, dword dwLength);
+
+
+/*
+ * Get a card handle to enable card to be accessed
+ */
+
+int		UxCardHandleGet(	ux_diva_card_t	**card,
+							dia_card_t		*cfg);
+
+/*
+ * Free a card handle as no longer needed
+ */
+
+void	UxCardHandleFree(ux_diva_card_t *card);
+
+/*
+ * Lock and unlock access to a card
+ */
+
+int		UxCardLock(ux_diva_card_t *card);
+void	UxCardUnlock(ux_diva_card_t *card, int ipl);
+
+/*
+ * Set the mapping address for PCI cards
+ */
+
+int		UxCardAddrMappingSet(ux_diva_card_t	*card,
+							int				id,
+							void			*address,
+							int				size);
+
+/*
+ * Attach card to memory to enable it to be accessed
+ * Returns the mapped address
+ */
+
+void	*UxCardMemAttach(ux_diva_card_t *card, int id);
+
+/*
+ * map card out of memory after completion of access
+ */
+
+void	UxCardMemDetach(ux_diva_card_t *card, void *address);
+
+/*
+ * input functions for memory-mapped cards
+ */
+
+byte	UxCardMemIn(ux_diva_card_t *card, void *address);
+
+word	UxCardMemInW(ux_diva_card_t *card, void *address);
+
+dword	UxCardMemInD(ux_diva_card_t *card, void *address);
+
+void	UxCardMemInBuffer(	ux_diva_card_t *card,
+							void			*address,
+							void			*buffer,
+							int				length);
+
+/*
+ * output functions for memory-mapped cards
+ */
+
+void UxCardMemOut(ux_diva_card_t *card, void *address, byte data);
+
+void UxCardMemOutW(ux_diva_card_t *card, void *address, word data);
+
+void UxCardMemOutD(ux_diva_card_t *card, void *address, dword data);
+
+void UxCardMemOutBuffer(	ux_diva_card_t	*card,
+							void			*address,
+							void			*buffer,
+							int				length);
+
+/*
+ * input functions for I/O-mapped cards
+ */
+
+byte	UxCardIoIn(ux_diva_card_t *card, void *, void *address);
+
+word	UxCardIoInW(ux_diva_card_t *card, void *, void *address);
+
+dword	UxCardIoInD(ux_diva_card_t *card, void *, void *address);
+
+void	UxCardIoInBuffer(	ux_diva_card_t *card,
+							void *, void			*address,
+							void			*buffer,
+							int				length);
+
+/*
+ * output functions for I/O-mapped cards
+ */
+
+void UxCardIoOut(ux_diva_card_t *card, void *, void *address, byte data);
+
+void UxCardIoOutW(ux_diva_card_t *card, void *, void *address, word data);
+
+void UxCardIoOutD(ux_diva_card_t *card, void *, void *address, dword data);
+
+void UxCardIoOutBuffer(	ux_diva_card_t	*card,
+							void *, void			*address,
+							void			*buffer,
+							int				length);
+
+/*
+ * Get specified PCI config
+ */
+
+void	UxPciConfigRead(ux_diva_card_t	*card, 
+						int				size,
+						int				offset,
+						void			*value);
+
+/*
+ * Set specified PCI config
+ */
+
+void	UxPciConfigWrite(ux_diva_card_t	*card, 
+						int				size,
+						int				offset,
+						void			*value);
+
+/* allocate memory, returning NULL if none available */
+
+void	*UxAlloc(unsigned int size);
+
+void	UxFree(void *);
+
+/*
+ * Pause for specified number of milli-seconds 
+ */
+
+void	UxPause(long ms);
+
+/*
+ * Install an ISR for the specified card
+ */
+
+int		UxIsrInstall(ux_diva_card_t *card, isr_fn_t *isr_fn, void *isr_arg);
+
+/*
+ * Remove an ISR for the specified card
+ */
+void	UxIsrRemove(ux_diva_card_t *card, void *);
+
+/*
+ * DEBUG function to turn logging ON or OFF
+ */
+
+void	UxCardLog(int turn_on);
+
+long	UxInterlockedIncrement(ux_diva_card_t *card, long *dst);
+long	UxInterlockedDecrement(ux_diva_card_t *card, long *dst);
+
+#endif /* of UXIO_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/eicon/xlog.c linux.19p18/drivers/isdn/eicon/xlog.c
--- linux.vanilla/drivers/isdn/eicon/xlog.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/eicon/xlog.c	Mon Feb 19 18:28:20 2001
@@ -0,0 +1,180 @@
+
+/*
+ *
+ * Copyright (C) Eicon Technology Corporation, 2000.
+ *
+ * Eicon File Revision :    1.2  
+ *
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
+ * 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.
+ *
+ */
+
+
+/*
+ * Unix Eicon active card driver
+ * XLOG related functions
+ */
+
+#include "sys.h"
+#include "idi.h"
+#include "pc.h"
+#include "pc_maint.h"
+#include "divalog.h"
+
+#include "adapter.h"
+#include "uxio.h"
+
+/*
+ * convert/copy XLOG info into a KLOG entry
+ */
+
+static
+void	xlog_to_klog(byte *b, int size, int card_num)
+
+{
+	typedef struct
+	{
+		word	code;
+		word	time_hi;
+		word	time_lo;
+		word	xcode;
+		byte	data[2];
+	} card_xlog_t;
+
+	card_xlog_t	*x;
+
+	klog_t		klog;
+
+	x = (card_xlog_t *) b;
+
+	bzero(&klog, sizeof(klog));
+
+	klog.time_stamp = (dword) x->time_hi;
+	klog.time_stamp = (klog.time_stamp << 16) | (dword) x->time_lo;
+
+	klog.length = size > sizeof(klog.buffer) ? sizeof(klog.buffer) : size;
+
+	klog.card = card_num;
+	if (x->code == 1)
+	{
+		klog.type = KLOG_XTXT_MSG;
+		klog.code = 0;
+		bcopy(&x->xcode, klog.buffer, klog.length);
+	}
+	else if (x->code == 2)
+	{
+		klog.type = KLOG_XLOG_MSG;
+		klog.code = x->xcode;
+		bcopy(&x->data, klog.buffer, klog.length);
+	}
+	else
+	{
+		char	*c; int i;
+		klog.type = KLOG_TEXT_MSG;
+		klog.code = 0;
+		c = "divas: invalid xlog message code from card";
+		i = 0;
+		while (*c)
+		{
+			klog.buffer[i] = *c;
+			c++;
+			i++;
+		}
+		klog.buffer[i] = *c;
+	}
+
+    /* send to the log driver and return */
+
+    DivasLogAdd(&klog, sizeof(klog));
+
+	return;
+}
+
+/*
+ * send an XLOG request down to specified card
+ * if response available from previous request then read it
+ * if not then just send down new request, ready for next time
+ */
+
+void	DivasXlogReq(int card_num)
+
+{
+	card_t				*card;
+	ADAPTER 			*a;
+
+	if ((card_num < 0) || (card_num > DivasCardNext))
+	{
+		DPRINTF(("xlog: invalid card number"));
+		return;
+	}
+
+	card = &DivasCards[card_num];
+
+	if (DivasXlogRetrieve(card))
+	{
+		return;
+	}
+
+	/* send down request for next time */
+
+	a = &card->a;
+
+	a->ram_out(a, (word *) (card->xlog_offset + 1), 0);
+	a->ram_out(a, (word *) (dword) (card->xlog_offset), DO_LOG);
+
+	return;
+}
+
+/*
+ * retrieve XLOG request from specified card
+ * returns non-zero if new request sent to card
+ */
+
+int		DivasXlogRetrieve(card_t *card)
+
+{
+	ADAPTER 			*a;
+	struct mi_pc_maint	pcm;
+
+	a = &card->a;
+
+	/* get status of last request */
+
+	pcm.rc = a->ram_in(a, (word *)(card->xlog_offset + 1));
+
+	/* if nothing there from previous request, send down a new one */
+
+	if (pcm.rc == OK)
+	{
+		/* read in response */
+
+		a->ram_in_buffer(a, (word *) (dword) card->xlog_offset, &pcm, sizeof(pcm)); 
+
+		xlog_to_klog((byte *) &pcm.data, sizeof(pcm.data), 
+						(int) (card - DivasCards));
+	}
+
+	/* if any response received from card, re-send request */
+
+	if (pcm.rc)
+	{
+		a->ram_out(a, (word *) (card->xlog_offset + 1), 0);
+		a->ram_out(a, (word *) (dword) (card->xlog_offset), DO_LOG);
+
+		return 1;
+	} 
+
+	return 0;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/Makefile linux.19p18/drivers/isdn/hisax/Makefile
--- linux.vanilla/drivers/isdn/hisax/Makefile	Fri Apr 21 12:46:11 2000
+++ linux.19p18/drivers/isdn/hisax/Makefile	Tue Feb 13 18:38:13 2001
@@ -1,217 +1,70 @@
-L_OBJS :=
-M_OBJS :=
-LX_OBJS :=
-MX_OBJS :=
-O_OBJS :=
-OX_OBJS :=
-L_TARGET :=
-O_TARGET :=
-
-O_OBJS := isdnl1.o tei.o isdnl2.o isdnl3.o \
-          lmgr.o q931.o callc.o fsm.o cert.o
-
-# EXTRA_CFLAGS += -S
-
-ifeq ($(CONFIG_HISAX_EURO),y)
-	 O_OBJS += l3dss1.o
-endif
-
-ifeq ($(CONFIG_HISAX_NI1),y)
-       O_OBJS += l3ni1.o
-endif
-
-ifeq ($(CONFIG_HISAX_1TR6),y)
-	 O_OBJS += l3_1tr6.o
-endif
-
-ISAC_OBJ :=
-HSCX_OBJ :=
-ISAR_OBJ :=
-HFC_OBJ :=
-HFC_2BDS0 :=
-JADE_OBJ :=
-W6692_OBJ :=
-
-ifeq ($(CONFIG_HISAX_16_0),y)
-	 O_OBJS += teles0.o
-	 ISAC_OBJ := isac.o
-	 HSCX_OBJ := hscx.o
-endif
-
-ifeq ($(CONFIG_HISAX_16_3),y)
-	 O_OBJS += teles3.o
-	 ISAC_OBJ := isac.o
-	 HSCX_OBJ := hscx.o
-endif
-
-ifeq ($(CONFIG_HISAX_TELESPCI),y)
-	 O_OBJS += telespci.o
-	 ISAC_OBJ := isac.o
-	 HSCX_OBJ := hscx.o
-endif
-
-ifeq ($(CONFIG_HISAX_S0BOX),y)
-	 O_OBJS += s0box.o
-	 ISAC_OBJ := isac.o
-	 HSCX_OBJ := hscx.o
-endif
-
-ifeq ($(CONFIG_HISAX_AVM_A1),y)
-	 O_OBJS += avm_a1.o
-	 ISAC_OBJ := isac.o
-	 HSCX_OBJ := hscx.o
-endif
-
-ifeq ($(CONFIG_HISAX_AVM_A1_PCMCIA),y)
-	 O_OBJS += avm_a1p.o
- 	 ISAC_OBJ := isac.o
-	 HSCX_OBJ := hscx.o
-endif
- 
-ifeq ($(CONFIG_HISAX_FRITZPCI),y)
-	 O_OBJS += avm_pci.o
- 	 ISAC_OBJ := isac.o
-endif
-
-
-ifeq ($(CONFIG_HISAX_ELSA),y)
-	 O_OBJS += elsa.o
-	 ISAC_OBJ := isac.o
-	 HSCX_OBJ := hscx.o
-endif
-
-ifeq ($(CONFIG_HISAX_IX1MICROR2),y)
-	 O_OBJS += ix1_micro.o
-	 ISAC_OBJ := isac.o
-	 HSCX_OBJ := hscx.o
-endif
-
-ifeq ($(CONFIG_HISAX_DIEHLDIVA),y)
-	 O_OBJS += diva.o
-	 ISAC_OBJ := isac.o
-	 HSCX_OBJ := hscx.o
-endif
-
-ifeq ($(CONFIG_HISAX_ASUSCOM),y)
-	 O_OBJS += asuscom.o
-	 ISAC_OBJ := isac.o
-	 HSCX_OBJ := hscx.o
-endif
-
-ifeq ($(CONFIG_HISAX_TELEINT),y)
-	 O_OBJS += teleint.o
-	 ISAC_OBJ := isac.o
-	 HFC_OBJ := hfc_2bs0.o
-endif
-
-ifeq ($(CONFIG_HISAX_SEDLBAUER),y)
-	 O_OBJS += sedlbauer.o
-	 ISAC_OBJ := isac.o
-	 HSCX_OBJ := hscx.o
-	 ISAR_OBJ := isar.o
-endif
-
-ifeq ($(CONFIG_HISAX_SPORTSTER),y)
-	 O_OBJS += sportster.o
-	 ISAC_OBJ := isac.o
-	 HSCX_OBJ := hscx.o
-endif
-
-ifeq ($(CONFIG_HISAX_MIC),y)
-	 O_OBJS += mic.o
-	 ISAC_OBJ := isac.o
-	 HSCX_OBJ := hscx.o
-endif
-
-ifeq ($(CONFIG_HISAX_NETJET),y)
-	 O_OBJS += netjet.o
-	 ISAC_OBJ := isac.o
-endif
-
-ifeq ($(CONFIG_HISAX_HFCS),y)
-	 O_OBJS += hfcscard.o
-	 HFC_2BDS0 := hfc_2bds0.o
-endif
-
-ifeq ($(CONFIG_HISAX_HFC_PCI),y)
-	 HFC_2BDS0 += hfc_pci.o
-endif
-
-ifeq ($(CONFIG_HISAX_HFC_SX),y)
-	 HFC_2BDS0 += hfc_sx.o
-endif
-
-ifeq ($(CONFIG_HISAX_NICCY),y)
-	 O_OBJS += niccy.o
-	 ISAC_OBJ := isac.o
-	 HSCX_OBJ := hscx.o
-endif
-
-ifeq ($(CONFIG_HISAX_ISURF),y)
-	 O_OBJS += isurf.o
-	 ISAC_OBJ := isac.o
-	 ISAR_OBJ := isar.o
-endif
-
-ifeq ($(CONFIG_HISAX_HSTSAPHIR),y)
-	 O_OBJS += saphir.o
-	 ISAC_OBJ := isac.o
-	 HSCX_OBJ := hscx.o
-endif
-
-ifeq ($(CONFIG_HISAX_BKM_A4T),y)
-	 O_OBJS += bkm_a4t.o
-	 ISAC_OBJ := isac.o
-	 JADE_OBJ := jade.o
-endif
-ifeq ($(CONFIG_HISAX_SCT_QUADRO),y)
-	 O_OBJS += bkm_a8.o
-	 ISAC_OBJ := isac.o
-	 HSCX_OBJ := hscx.o
-endif
-
-ifeq ($(CONFIG_HISAX_GAZEL),y)
-	 O_OBJS += gazel.o
-	 ISAC_OBJ := isac.o
-	 HSCX_OBJ := hscx.o
-endif
-
-ifeq ($(CONFIG_HISAX_W6692),y)
-	W6692_OBJ := w6692.o
-endif
-
-# ifeq ($(CONFIG_HISAX_TESTEMU),y)
-#	 O_OBJS += testemu.o
-# endif
-
-ifeq ($(ISAC_OBJ), isac.o)
-	ISAC_OBJ += arcofi.o
-endif
-
-O_OBJS += $(ISAC_OBJ) $(HSCX_OBJ) $(ISAR_OBJ) $(JADE_OBJ)
-O_OBJS += $(HFC_OBJ) $(HFC_2BDS0) $(W6692_OBJ)
-OX_OBJS += config.o
-
-O_TARGET :=
-
-ifeq ($(CONFIG_ISDN_DRV_HISAX),y)
-  O_TARGET += hisax.o
-else
-  ifeq ($(CONFIG_ISDN_DRV_HISAX),m)
-    O_TARGET += hisax.o
-    M_OBJS += hisax.o
-  endif
-endif
-
-
-include $(TOPDIR)/Rules.make
-
-MD5FILES += isac.c isdnl1.c isdnl2.c isdnl3.c \
-	    tei.c callc.c cert.c l3dss1.c l3_1tr6.c \
-	    elsa.c diva.c
+# Makefile for the hisax ISDN device driver
 
-CERT = $(shell md5sum -c md5sums.asc >> /dev/null;echo $$?)
+# The target object and module list name.
 
-cert.o:	$(MD5FILES) md5sums.asc
-	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -D CERTIFICATION=$(CERT) -c -o cert.o cert.c
+O_TARGET	:= vmlinux-obj.o
 
+# Objects that export symbols.
+
+export-objs	:= config.o
+
+# Multipart objects.
+
+list-multi	:= hisax.o
+hisax-objs	:= config.o isdnl1.o tei.o isdnl2.o isdnl3.o \
+		   lmgr.o q931.o callc.o fsm.o cert.o
+
+# Optional parts of multipart objects.
+
+hisax-objs-$(CONFIG_HISAX_EURO) += l3dss1.o
+hisax-objs-$(CONFIG_HISAX_NI1) += l3ni1.o
+hisax-objs-$(CONFIG_HISAX_1TR6) += l3_1tr6.o
+
+hisax-objs-$(CONFIG_HISAX_16_0) += teles0.o isac.o arcofi.o hscx.o
+hisax-objs-$(CONFIG_HISAX_16_3) += teles3.o isac.o arcofi.o hscx.o
+hisax-objs-$(CONFIG_HISAX_TELESPCI) += telespci.o isac.o arcofi.o hscx.o
+hisax-objs-$(CONFIG_HISAX_S0BOX) += s0box.o isac.o arcofi.o hscx.o
+hisax-objs-$(CONFIG_HISAX_AVM_A1) += avm_a1.o isac.o arcofi.o hscx.o
+hisax-objs-$(CONFIG_HISAX_AVM_A1_PCMCIA) += avm_a1p.o isac.o arcofi.o hscx.o
+hisax-objs-$(CONFIG_HISAX_FRITZPCI) += avm_pci.o isac.o arcofi.o
+hisax-objs-$(CONFIG_HISAX_AVM_A1) += avm_a1.o isac.o arcofi.o hscx.o
+hisax-objs-$(CONFIG_HISAX_ELSA) += elsa.o isac.o arcofi.o hscx.o
+hisax-objs-$(CONFIG_HISAX_IX1MICROR2) += ix1_micro.o isac.o arcofi.o hscx.o
+hisax-objs-$(CONFIG_HISAX_DIEHLDIVA) += diva.o isac.o arcofi.o hscx.o
+hisax-objs-$(CONFIG_HISAX_ASUSCOM) += asuscom.o isac.o arcofi.o hscx.o
+hisax-objs-$(CONFIG_HISAX_TELEINT) += teleint.o isac.o arcofi.o hfc_2bs0.o
+hisax-objs-$(CONFIG_HISAX_SEDLBAUER) += sedlbauer.o isac.o arcofi.o hscx.o isar.o
+hisax-objs-$(CONFIG_HISAX_SPORTSTER) += sportster.o isac.o arcofi.o hscx.o
+hisax-objs-$(CONFIG_HISAX_MIC) += mic.o isac.o arcofi.o hscx.o
+hisax-objs-$(CONFIG_HISAX_NETJET) += nj_s.o netjet.o isac.o arcofi.o
+hisax-objs-$(CONFIG_HISAX_NETJET_U) += nj_u.o netjet.o icc.o
+hisax-objs-$(CONFIG_HISAX_HFCS) += hfcscard.o hfc_2bds0.o
+hisax-objs-$(CONFIG_HISAX_HFC_PCI) += hfc_pci.o
+hisax-objs-$(CONFIG_HISAX_HFC_SX) += hfc_sx.o
+hisax-objs-$(CONFIG_HISAX_NICCY) += niccy.o isac.o arcofi.o hscx.o
+hisax-objs-$(CONFIG_HISAX_ISURF) += isurf.o isac.o arcofi.o isar.o
+hisax-objs-$(CONFIG_HISAX_HSTSAPHIR) += saphir.o isac.o arcofi.o hscx.o
+hisax-objs-$(CONFIG_HISAX_BKM_A4T) += bkm_a4t.o isac.o arcofi.o jade.o
+hisax-objs-$(CONFIG_HISAX_SCT_QUADRO) += bkm_a8.o isac.o arcofi.o hscx.o
+hisax-objs-$(CONFIG_HISAX_GAZEL) += gazel.o isac.o arcofi.o hscx.o
+hisax-objs-$(CONFIG_HISAX_W6692) += w6692.o
+#hisax-objs-$(CONFIG_HISAX_TESTEMU) += testemu.o
+
+hisax-objs += $(sort $(hisax-objs-y))
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_ISDN_DRV_HISAX)	+= hisax.o
+
+MD5FILES 	:= isac.c isdnl1.c isdnl2.c isdnl3.c \
+		   tei.c callc.c cert.c l3dss1.c l3_1tr6.c \
+		   elsa.c diva.c sedlbauer.c
+CERT := $(shell md5sum -c md5sums.asc >> /dev/null;echo $$?)
+CFLAGS_cert.o := -DCERTIFICATION=$(CERT)
+
+include $(TOPDIR)/drivers/isdn/Rules.make
+
+# Link rules for multi-part drivers.
+
+hisax.o: $(hisax-objs)
+	$(LD) -r -o $@ $(hisax-objs)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/amd7930.c linux.19p18/drivers/isdn/hisax/amd7930.c
--- linux.vanilla/drivers/isdn/hisax/amd7930.c	Fri Apr 21 12:46:09 2000
+++ linux.19p18/drivers/isdn/hisax/amd7930.c	Mon Feb 12 15:09:50 2001
@@ -1,25 +1,9 @@
-/* $Id: amd7930.c,v 1.3 1999/07/12 21:04:52 keil Exp $
+/* $Id: amd7930.c,v 1.5 2000/11/24 17:05:37 kai Exp $
  *
  * HiSax ISDN driver - chip specific routines for AMD 7930
  *
  * Author       Brent Baccala (baccala@FreeSoft.org)
  *
- *
- *
- * $Log: amd7930.c,v $
- * Revision 1.3  1999/07/12 21:04:52  keil
- * fix race in IRQ handling
- * added watchdog for lost IRQs
- *
- * Revision 1.2  1998/02/12 23:07:10  keil
- * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
- *
- * Revision 1.1  1998/02/03 23:20:51  keil
- * New files for SPARC isdn support
- *
- * Revision 1.1  1998/01/08 04:17:12  baccala
- * ISDN comes to the Sparc.  Key points:
- *
  *    - Existing ISDN HiSax driver provides all the smarts
  *    - it compiles, runs, talks to an isolated phone switch, connects
  *      to a Cisco, pings go through
@@ -30,6 +14,7 @@
  *
  * The code is unreliable enough to be consider alpha
  *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  * Advanced Micro Devices' Am79C30A is an ISDN/audio chip used in the
  * SparcStation 1+.  The chip provides microphone and speaker interfaces
@@ -109,7 +94,7 @@
 #include "rawhdlc.h"
 #include <linux/interrupt.h>
 
-static const char *amd7930_revision = "$Revision: 1.3 $";
+static const char *amd7930_revision = "$Revision: 1.5 $";
 
 #define RCV_BUFSIZE	1024	/* Size of raw receive buffer in bytes */
 #define RCV_BUFBLKS	4	/* Number of blocks to divide buffer into
@@ -749,8 +734,8 @@
 	return(0);
 }
 
-__initfunc(int
-setup_amd7930(struct IsdnCard *card))
+int __init
+setup_amd7930(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/arcofi.c linux.19p18/drivers/isdn/hisax/arcofi.c
--- linux.vanilla/drivers/isdn/hisax/arcofi.c	Fri Apr 21 12:46:09 2000
+++ linux.19p18/drivers/isdn/hisax/arcofi.c	Mon Feb 12 15:09:50 2001
@@ -1,43 +1,10 @@
-/* $Id: arcofi.c,v 1.10 1999/12/23 15:09:32 keil Exp $
-
+/* $Id: arcofi.c,v 1.12 2000/11/25 17:01:00 kai Exp $
+ *
  * arcofi.c   Ansteuerung ARCOFI 2165
  *
  * Author     Karsten Keil (keil@isdn4linux.de)
  *
- *
- *
- * $Log: arcofi.c,v $
- * Revision 1.10  1999/12/23 15:09:32  keil
- * change email
- *
- * Revision 1.9  1999/12/19 13:09:41  keil
- * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
- * signal proof delays
- *
- * Revision 1.8  1999/08/25 16:50:51  keil
- * Fix bugs which cause 2.3.14 hangs (waitqueue init)
- *
- * Revision 1.7  1999/07/01 08:11:17  keil
- * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
- *
- * Revision 1.6  1998/09/30 22:21:56  keil
- * cosmetics
- *
- * Revision 1.5  1998/09/27 12:52:57  keil
- * cosmetics
- *
- * Revision 1.4  1998/08/20 13:50:24  keil
- * More support for hybrid modem (not working yet)
- *
- * Revision 1.3  1998/05/25 12:57:38  keil
- * HiSax golden code from certification, Don't use !!!
- * No leased lines, no X75, but many changes.
- *
- * Revision 1.2  1998/04/15 16:47:16  keil
- * new interface
- *
- * Revision 1.1  1997/10/29 18:51:20  keil
- * New files
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
  
@@ -161,5 +128,6 @@
 	cs->dc.isac.arcofitimer.function = (void *) arcofi_timer;
 	cs->dc.isac.arcofitimer.data = (long) cs;
 	init_timer(&cs->dc.isac.arcofitimer);
+	init_waitqueue_head(&cs->dc.isac.arcofi_wait);
 	test_and_set_bit(HW_ARCOFI, &cs->HW_Flags);
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/arcofi.h linux.19p18/drivers/isdn/hisax/arcofi.h
--- linux.vanilla/drivers/isdn/hisax/arcofi.h	Fri Apr 21 12:46:09 2000
+++ linux.19p18/drivers/isdn/hisax/arcofi.h	Wed Dec 13 22:06:52 2000
@@ -1,27 +1,10 @@
-/* $Id: arcofi.h,v 1.5 1999/12/23 15:09:32 keil Exp $
-
+/* $Id: arcofi.h,v 1.6 2000/06/26 08:59:12 keil Exp $
+ *
  * arcofi.h   Ansteuerung ARCOFI 2165
  *
  * Author     Karsten Keil (keil@isdn4linux.de)
  *
- *
- *
- * $Log: arcofi.h,v $
- * Revision 1.5  1999/12/23 15:09:32  keil
- * change email
- *
- * Revision 1.4  1999/07/01 08:11:18  keil
- * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
- *
- * Revision 1.3  1998/05/25 12:57:39  keil
- * HiSax golden code from certification, Don't use !!!
- * No leased lines, no X75, but many changes.
- *
- * Revision 1.2  1998/04/15 16:47:17  keil
- * new interface
- *
- * Revision 1.1  1997/10/29 18:51:20  keil
- * New files
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
  
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/asuscom.c linux.19p18/drivers/isdn/hisax/asuscom.c
--- linux.vanilla/drivers/isdn/hisax/asuscom.c	Fri Apr 21 12:46:09 2000
+++ linux.19p18/drivers/isdn/hisax/asuscom.c	Mon Feb 12 15:09:50 2001
@@ -1,43 +1,17 @@
-/* $Id: asuscom.c,v 1.9 1999/12/19 13:09:41 keil Exp $
-
+/* $Id: asuscom.c,v 1.11 2000/11/24 17:05:37 kai Exp $
+ *
  * asuscom.c     low level stuff for ASUSCOM NETWORK INC. ISDNLink cards
  *
  * Author     Karsten Keil (keil@isdn4linux.de)
  *
  * Thanks to  ASUSCOM NETWORK INC. Taiwan and  Dynalink NL for informations
  *
- *
- * $Log: asuscom.c,v $
- * Revision 1.9  1999/12/19 13:09:41  keil
- * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
- * signal proof delays
- *
- * Revision 1.8  1999/09/04 06:20:05  keil
- * Changes from kernel set_current_state()
- *
- * Revision 1.7  1999/07/12 21:04:53  keil
- * fix race in IRQ handling
- * added watchdog for lost IRQs
- *
- * Revision 1.6  1999/07/01 08:11:18  keil
- * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
- *
- * Revision 1.5  1998/11/15 23:54:19  keil
- * changes from 2.0
- *
- * Revision 1.4  1998/06/18 23:18:20  keil
- * Support for new IPAC card
- *
- * Revision 1.3  1998/04/15 16:46:53  keil
- * new init code
- *
- * Revision 1.2  1998/02/02 13:27:06  keil
- * New
- *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "ipac.h"
@@ -46,7 +20,7 @@
 
 extern const char *CardType[];
 
-const char *Asuscom_revision = "$Revision: 1.9 $";
+const char *Asuscom_revision = "$Revision: 1.11 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -295,13 +269,13 @@
 		byteout(cs->hw.asus.adr, ASUS_RESET);	/* Reset On */
 	save_flags(flags);
 	sti();
-	current->state = TASK_UNINTERRUPTIBLE;
+	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout((10*HZ)/1000);
 	if (cs->subtyp == ASUS_IPAC)
 		writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_POTA2, 0x0);
 	else
 		byteout(cs->hw.asus.adr, 0);	/* Reset Off */
-	current->state = TASK_UNINTERRUPTIBLE;
+	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout((10*HZ)/1000);
 	if (cs->subtyp == ASUS_IPAC) {
 		writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_CONF, 0x0);
@@ -333,8 +307,8 @@
 	return(0);
 }
 
-__initfunc(int
-setup_asuscom(struct IsdnCard *card))
+int __init
+setup_asuscom(struct IsdnCard *card)
 {
 	int bytecnt;
 	struct IsdnCardState *cs = card->cs;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/avm_a1.c linux.19p18/drivers/isdn/hisax/avm_a1.c
--- linux.vanilla/drivers/isdn/hisax/avm_a1.c	Fri Apr 21 12:46:09 2000
+++ linux.19p18/drivers/isdn/hisax/avm_a1.c	Mon Feb 12 15:09:50 2001
@@ -1,76 +1,21 @@
-/* $Id: avm_a1.c,v 2.11 1999/07/12 21:04:54 keil Exp $
-
+/* $Id: avm_a1.c,v 2.13 2000/11/24 17:05:37 kai Exp $
+ *
  * avm_a1.c     low level stuff for AVM A1 (Fritz) isdn cards
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *
- *
- * $Log: avm_a1.c,v $
- * Revision 2.11  1999/07/12 21:04:54  keil
- * fix race in IRQ handling
- * added watchdog for lost IRQs
- *
- * Revision 2.10  1998/11/15 23:54:21  keil
- * changes from 2.0
- *
- * Revision 2.9  1998/08/13 23:36:12  keil
- * HiSax 3.1 - don't work stable with current LinkLevel
- *
- * Revision 2.8  1998/04/15 16:44:27  keil
- * new init code
- *
- * Revision 2.7  1998/02/02 13:29:37  keil
- * fast io
- *
- * Revision 2.6  1998/01/13 23:09:46  keil
- * really disable timer
- *
- * Revision 2.5  1998/01/02 06:50:29  calle
- * Perodic timer of A1 now disabled, no need for linux driver.
- *
- * Revision 2.4  1997/11/08 21:35:42  keil
- * new l1 init
- *
- * Revision 2.3  1997/11/06 17:13:32  keil
- * New 2.1 init code
- *
- * Revision 2.2  1997/10/29 18:55:48  keil
- * changes for 2.1.60 (irq2dev_map)
- *
- * Revision 2.1  1997/07/27 21:47:13  keil
- * new interface structures
- *
- * Revision 2.0  1997/06/26 11:02:48  keil
- * New Layer and card interface
- *
- * Revision 1.6  1997/04/13 19:54:07  keil
- * Change in IRQ check delay for SMP
- *
- * Revision 1.5  1997/04/06 22:54:10  keil
- * Using SKB's
- *
- * Revision 1.4  1997/01/27 15:50:21  keil
- * SMP proof,cosmetics
- *
- * Revision 1.3  1997/01/21 22:14:20  keil
- * cleanups
- *
- * Revision 1.2  1996/10/27 22:07:31  keil
- * cosmetic changes
- *
- * Revision 1.1  1996/10/13 20:04:49  keil
- * Initial revision
- *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
 #include "isdnl1.h"
 
 extern const char *CardType[];
-static const char *avm_revision = "$Revision: 2.11 $";
+static const char *avm_revision = "$Revision: 2.13 $";
 
 #define	 AVM_A1_STAT_ISAC	0x01
 #define	 AVM_A1_STAT_HSCX	0x02
@@ -227,8 +172,8 @@
 	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;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/avm_a1p.c linux.19p18/drivers/isdn/hisax/avm_a1p.c
--- linux.vanilla/drivers/isdn/hisax/avm_a1p.c	Fri Apr 21 12:46:09 2000
+++ linux.19p18/drivers/isdn/hisax/avm_a1p.c	Mon Feb 12 15:09:50 2001
@@ -1,4 +1,4 @@
-/* $Id: avm_a1p.c,v 2.5 1999/09/01 08:26:34 calle Exp $
+/* $Id: avm_a1p.c,v 2.7 2000/11/24 17:05:37 kai Exp $
  *
  * avm_a1p.c    low level stuff for the following AVM cards:
  *              A1 PCMCIA
@@ -7,31 +7,10 @@
  *
  * Author       Carsten Paeth (calle@calle.in-berlin.de)
  *
- * $Log: avm_a1p.c,v $
- * Revision 2.5  1999/09/01 08:26:34  calle
- * Patch from Daniel Beichl <dani@ecomag.net> to make A1 PCMCIA work again.
- *
- * Revision 2.4  1999/07/12 21:04:55  keil
- * fix race in IRQ handling
- * added watchdog for lost IRQs
- *
- * Revision 2.3  1998/11/15 23:54:22  keil
- * changes from 2.0
- *
- * Revision 2.2  1998/08/13 23:36:13  keil
- * HiSax 3.1 - don't work stable with current LinkLevel
- *
- * Revision 2.1  1998/07/15 15:01:23  calle
- * Support for AVM passive PCMCIA cards:
- *    A1 PCMCIA, FRITZ!Card PCMCIA and FRITZ!Card PCMCIA 2.0
- *
- * Revision 1.1.2.1  1998/07/15 14:43:26  calle
- * Support for AVM passive PCMCIA cards:
- *    A1 PCMCIA, FRITZ!Card PCMCIA and FRITZ!Card PCMCIA 2.0
- *
- *
+ *  This file is (c) under GNU PUBLIC LICENSE
  */
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
@@ -74,7 +53,7 @@
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
 
-static const char *avm_revision = "$Revision: 2.5 $";
+static const char *avm_revision = "$Revision: 2.7 $";
 
 static inline u_char
 ReadISAC(struct IsdnCardState *cs, u_char offset)
@@ -266,8 +245,8 @@
 	return 0;
 }
 
-__initfunc(int
-setup_avm_a1_pcmcia(struct IsdnCard *card))
+int 
+setup_avm_a1_pcmcia(struct IsdnCard *card)
 {
 	u_char model, vers;
 	struct IsdnCardState *cs = card->cs;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/avm_pci.c linux.19p18/drivers/isdn/hisax/avm_pci.c
--- linux.vanilla/drivers/isdn/hisax/avm_pci.c	Fri Apr 21 12:46:09 2000
+++ linux.19p18/drivers/isdn/hisax/avm_pci.c	Tue Feb 13 18:50:48 2001
@@ -1,76 +1,29 @@
-/* $Id: avm_pci.c,v 1.14 1999/12/19 13:09:41 keil Exp $
-
+/* $Id: avm_pci.c,v 1.22.6.3 2001/02/13 10:33:58 kai Exp $
+ *
  * avm_pci.c    low level stuff for AVM Fritz!PCI and ISA PnP isdn cards
  *              Thanks to AVM, Berlin for informations
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *
- *
- * $Log: avm_pci.c,v $
- * Revision 1.14  1999/12/19 13:09:41  keil
- * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
- * signal proof delays
- *
- * Revision 1.13  1999/12/03 12:10:14  keil
- * Bugfix: Wrong channel use on hangup of channel 2
- *
- * Revision 1.12  1999/09/04 06:20:05  keil
- * Changes from kernel set_current_state()
- *
- * Revision 1.11  1999/08/11 21:01:18  keil
- * new PCI codefix
- *
- * Revision 1.10  1999/08/10 16:01:44  calle
- * struct pci_dev changed in 2.3.13. Made the necessary changes.
- *
- * Revision 1.9  1999/07/12 21:04:57  keil
- * fix race in IRQ handling
- * added watchdog for lost IRQs
- *
- * Revision 1.8  1999/07/01 08:11:19  keil
- * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
- *
- * Revision 1.7  1999/02/22 18:26:30  keil
- * Argh ! ISAC address was only set with PCI
- *
- * Revision 1.6  1998/11/27 19:59:28  keil
- * set subtype for Fritz!PCI
- *
- * Revision 1.5  1998/11/27 12:56:45  keil
- * forgot to update setup function name
- *
- * Revision 1.4  1998/11/15 23:53:19  keil
- * Fritz!PnP; changes from 2.0
- *
- * Revision 1.3  1998/09/27 23:53:39  keil
- * Fix error handling
- *
- * Revision 1.2  1998/09/27 12:54:55  keil
- * bcs assign was lost in setstack, very bad results
- *
- * Revision 1.1  1998/08/20 13:47:30  keil
- * first version
- *
- *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 #define __NO_VERSION__
 #include <linux/config.h>
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "isdnl1.h"
 #include <linux/pci.h>
+#include <linux/isdn_compat.h>
 #include <linux/interrupt.h>
 
 extern const char *CardType[];
-static const char *avm_pci_rev = "$Revision: 1.14 $";
+static const char *avm_pci_rev = "$Revision: 1.22.6.3 $";
 
 #define  AVM_FRITZ_PCI		1
 #define  AVM_FRITZ_PNP		2
 
-#define  PCI_VENDOR_AVM		0x1244
-#define  PCI_FRITZPCI_ID	0xa00
-
 #define  HDLC_FIFO		0x0
 #define  HDLC_STATUS		0x4
 
@@ -339,7 +292,15 @@
 	if (cs->subtyp == AVM_FRITZ_PCI) {
 		outl(idx, cs->hw.avm.cfg_reg + 4);
 		while (cnt < count) {
+#ifdef __powerpc__
+#ifdef CONFIG_APUS
+			*ptr++ = in_le32((unsigned *)(cs->hw.avm.isac +_IO_BASE));
+#else
+			*ptr++ = in_be32((unsigned *)(cs->hw.avm.isac +_IO_BASE));
+#endif /* CONFIG_APUS */
+#else
 			*ptr++ = inl(cs->hw.avm.isac);
+#endif /* __powerpc__ */
 			cnt += 4;
 		}
 	} else {
@@ -395,7 +356,15 @@
 	write_ctrl(bcs, 3);  /* sets the correct index too */
 	if (cs->subtyp == AVM_FRITZ_PCI) {
 		while (cnt<count) {
+#ifdef __powerpc__
+#ifdef CONFIG_APUS
+			out_le32((unsigned *)(cs->hw.avm.isac +_IO_BASE), *ptr++);
+#else
+			out_be32((unsigned *)(cs->hw.avm.isac +_IO_BASE), *ptr++);
+#endif /* CONFIG_APUS */
+#else
 			outl(*ptr++, cs->hw.avm.isac);
+#endif /* __powerpc__ */
 			cnt += 4;
 		}
 	} else {
@@ -675,8 +644,8 @@
 	return (0);
 }
 
-HISAX_INITFUNC(void
-clear_pending_hdlc_ints(struct IsdnCardState *cs))
+void __init
+clear_pending_hdlc_ints(struct IsdnCardState *cs)
 {
 	u_int val;
 
@@ -705,8 +674,8 @@
 	}
 }
 
-HISAX_INITFUNC(void
-inithdlc(struct IsdnCardState *cs))
+void __init
+inithdlc(struct IsdnCardState *cs)
 {
 	cs->bcs[0].BC_SetStack = setstack_hdlc;
 	cs->bcs[1].BC_SetStack = setstack_hdlc;
@@ -751,11 +720,11 @@
 	save_flags(flags);
 	sti();
 	outb(AVM_STATUS0_RESET | AVM_STATUS0_DIS_TIMER, cs->hw.avm.cfg_reg + 2);
-	current->state = TASK_UNINTERRUPTIBLE;
+	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
 	outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER | AVM_STATUS0_ENA_IRQ, cs->hw.avm.cfg_reg + 2);
 	outb(AVM_STATUS1_ENA_IOM | cs->irq, cs->hw.avm.cfg_reg + 3);
-	current->state = TASK_UNINTERRUPTIBLE;
+	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
 	printk(KERN_INFO "AVM PCI/PnP: S1 %x\n", inb(cs->hw.avm.cfg_reg + 3));
 }
@@ -790,10 +759,10 @@
 	return(0);
 }
 
-static 	struct pci_dev *dev_avm __initdata = NULL;
+static struct pci_dev *dev_avm __initdata = NULL;
 
-__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;
@@ -813,17 +782,18 @@
 			printk(KERN_ERR "FritzPCI: no PCI bus present\n");
 			return(0);
 		}
-		if ((dev_avm = pci_find_device(PCI_VENDOR_AVM,
-			PCI_FRITZPCI_ID,  dev_avm))) {
+		if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM,
+			PCI_DEVICE_ID_AVM_A1,  dev_avm))) {
 			cs->irq = dev_avm->irq;
 			if (!cs->irq) {
-				printk(KERN_WARNING "FritzPCI: No IRQ for PCI card found\n");
+				printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n");
 				return(0);
 			}
-			cs->hw.avm.cfg_reg = dev_avm->base_address[ 1] &
-				PCI_BASE_ADDRESS_IO_MASK; 
+			if (pci_enable_device(dev_avm))
+				return(0);
+			cs->hw.avm.cfg_reg = dev_avm->base_address[ 1] & PCI_BASE_ADDRESS_IO_MASK;
 			if (!cs->hw.avm.cfg_reg) {
-				printk(KERN_WARNING "FritzPCI: No IO-Adr for PCI card found\n");
+				printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n");
 				return(0);
 			}
 			cs->subtyp = AVM_FRITZ_PCI;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/bkm_a4t.c linux.19p18/drivers/isdn/hisax/bkm_a4t.c
--- linux.vanilla/drivers/isdn/hisax/bkm_a4t.c	Fri Apr 21 12:46:09 2000
+++ linux.19p18/drivers/isdn/hisax/bkm_a4t.c	Tue Feb 13 18:50:48 2001
@@ -1,4 +1,4 @@
-/* $Id: bkm_a4t.c,v 1.9 1999/12/19 13:09:41 keil Exp $
+/* $Id: bkm_a4t.c,v 1.13.6.3 2001/02/13 10:33:58 kai Exp $
  * bkm_a4t.c    low level stuff for T-Berkom A4T
  *              derived from the original file sedlbauer.c
  *              derived from the original file niccy.c
@@ -6,53 +6,26 @@
  *
  * Author       Roland Klabunde (R.Klabunde@Berkom.de)
  *
- * $Log: bkm_a4t.c,v $
- * Revision 1.9  1999/12/19 13:09:41  keil
- * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
- * signal proof delays
- *
- * Revision 1.8  1999/09/04 06:20:05  keil
- * Changes from kernel set_current_state()
- *
- * Revision 1.7  1999/08/22 20:26:55  calle
- * backported changes from kernel 2.3.14:
- * - several #include "config.h" gone, others come.
- * - "struct device" changed to "struct net_device" in 2.3.14, added a
- *   define in isdn_compat.h for older kernel versions.
- *
- * Revision 1.6  1999/08/11 21:01:22  keil
- * new PCI codefix
- *
- * Revision 1.5  1999/08/10 16:01:46  calle
- * struct pci_dev changed in 2.3.13. Made the necessary changes.
- *
- * Revision 1.4  1999/07/14 11:43:14  keil
- * correct PCI_SUBSYSTEM_VENDOR_ID
- *
- * Revision 1.3  1999/07/12 21:04:58  keil
- * fix race in IRQ handling
- * added watchdog for lost IRQs
- *
- * Revision 1.2  1999/07/01 08:07:53  keil
- * Initial version
- *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 
 #define __NO_VERSION__
 
 #include <linux/config.h>
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
 #include "jade.h"
 #include "isdnl1.h"
-#include "bkm_ax.h"
 #include <linux/pci.h>
+#include <linux/isdn_compat.h>
+#include "bkm_ax.h"
 
 extern const char *CardType[];
 
-const char *bkm_a4t_revision = "$Revision: 1.9 $";
+const char *bkm_a4t_revision = "$Revision: 1.13.6.3 $";
 
 
 static inline u_char
@@ -235,11 +208,11 @@
 		sti();
 		/* Issue the I20 soft reset     */
 		pI20_Regs->i20SysControl = 0xFF;	/* all in */
-		current->state = TASK_UNINTERRUPTIBLE;
+		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout((10 * HZ) / 1000);
 		/* Remove the soft reset */
 		pI20_Regs->i20SysControl = sysRESET | 0xFF;
-		current->state = TASK_UNINTERRUPTIBLE;
+		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout((10 * HZ) / 1000);
 		/* Set our configuration */
 		pI20_Regs->i20SysControl = sysRESET | sysCFG;
@@ -250,14 +223,14 @@
 		    g_A4T_ISAC_RES |
 		    g_A4T_JADE_BOOTR |
 		    g_A4T_ISAR_BOOTR;
-		current->state = TASK_UNINTERRUPTIBLE;
+		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout((10 * HZ) / 1000);
 
 		/* Remove RESET state from ISDN */
 		pI20_Regs->i20GuestControl &= ~(g_A4T_ISAC_RES |
 						g_A4T_JADE_RES |
 						g_A4T_ISAR_RES);
-		current->state = TASK_UNINTERRUPTIBLE;
+		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout((10 * HZ) / 1000);
 		restore_flags(flags);
 	}
@@ -294,8 +267,8 @@
 
 static struct pci_dev *dev_a4t __initdata = NULL;
 
-__initfunc(int
-	   setup_bkm_a4t(struct IsdnCard *card))
+int __init
+setup_bkm_a4t(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
@@ -316,15 +289,20 @@
 		printk(KERN_ERR "bkm_a4t: no PCI bus present\n");
 		return (0);
 	}
-	if ((dev_a4t = pci_find_device(I20_VENDOR_ID, I20_DEVICE_ID, dev_a4t))) {
-		u_int sub_sys_id = 0;
-
-		pci_read_config_dword(dev_a4t, PCI_SUBSYSTEM_VENDOR_ID,
-			&sub_sys_id);
-		if (sub_sys_id == ((A4T_SUBSYS_ID << 16) | A4T_SUBVEN_ID)) {
+	while ((dev_a4t = pci_find_device(PCI_VENDOR_ID_ZORAN,
+		PCI_DEVICE_ID_ZORAN_36120, dev_a4t))) {
+		u16 sub_sys;
+		u16 sub_vendor;
+
+		pci_read_config_word(dev_a4t, PCI_SUBSYSTEM_VENDOR_ID, &sub_vendor);
+		pci_read_config_word(dev_a4t, PCI_SUBSYSTEM_ID, &sub_sys);
+		if ((sub_sys == PCI_DEVICE_ID_BERKOM_A4T) && (sub_vendor == PCI_VENDOR_ID_BERKOM)) {
+			if (pci_enable_device(dev_a4t))
+				return(0);
 			found = 1;
-			pci_memaddr = dev_a4t->base_address[ 0];
+			pci_memaddr = dev_a4t->base_address[ 0] & PCI_BASE_ADDRESS_MEM_MASK;
 			cs->irq = dev_a4t->irq;
+			break;
 		}
 	}
 	if (!found) {
@@ -339,7 +317,6 @@
 		printk(KERN_WARNING "HiSax: %s: No Memory base address\n", CardType[card->typ]);
 		return (0);
 	}
-	pci_memaddr &= PCI_BASE_ADDRESS_MEM_MASK;
 	cs->hw.ax.base = (u_int) ioremap(pci_memaddr, 4096);
 	/* Check suspecious address */
 	pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/bkm_a8.c linux.19p18/drivers/isdn/hisax/bkm_a8.c
--- linux.vanilla/drivers/isdn/hisax/bkm_a8.c	Fri Apr 21 12:46:09 2000
+++ linux.19p18/drivers/isdn/hisax/bkm_a8.c	Tue Feb 13 18:50:48 2001
@@ -1,4 +1,4 @@
-/* $Id: bkm_a8.c,v 1.9 1999/12/19 13:09:41 keil Exp $
+/* $Id: bkm_a8.c,v 1.14.6.3 2001/02/13 10:33:58 kai Exp $
  * bkm_a8.c     low level stuff for Scitel Quadro (4*S0, passive)
  *              derived from the original file sedlbauer.c
  *              derived from the original file niccy.c
@@ -6,69 +6,29 @@
  *
  * Author       Roland Klabunde (R.Klabunde@Berkom.de)
  *
- * $Log: bkm_a8.c,v $
- * Revision 1.9  1999/12/19 13:09:41  keil
- * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
- * signal proof delays
- *
- * Revision 1.8  1999/09/04 06:20:05  keil
- * Changes from kernel set_current_state()
- *
- * Revision 1.7  1999/08/22 20:26:58  calle
- * backported changes from kernel 2.3.14:
- * - several #include "config.h" gone, others come.
- * - "struct device" changed to "struct net_device" in 2.3.14, added a
- *   define in isdn_compat.h for older kernel versions.
- *
- * Revision 1.6  1999/08/11 21:01:24  keil
- * new PCI codefix
- *
- * Revision 1.5  1999/08/10 16:01:48  calle
- * struct pci_dev changed in 2.3.13. Made the necessary changes.
- *
- * Revision 1.4  1999/07/14 11:43:15  keil
- * correct PCI_SUBSYSTEM_VENDOR_ID
- *
- * Revision 1.3  1999/07/12 21:04:59  keil
- * fix race in IRQ handling
- * added watchdog for lost IRQs
- *
- * Revision 1.2  1999/07/01 08:07:54  keil
- * Initial version
- *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 #define __NO_VERSION__
 
 #include <linux/config.h>
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "ipac.h"
 #include "hscx.h"
 #include "isdnl1.h"
-#include "bkm_ax.h"
 #include <linux/pci.h>
+#include <linux/isdn_compat.h>
+#include "bkm_ax.h"
+
+#if CONFIG_PCI
 
 #define	ATTEMPT_PCI_REMAPPING	/* Required for PLX rev 1 */
 
 extern const char *CardType[];
 
-const char sct_quadro_revision[] = "$Revision: 1.9 $";
-
-/* To survive the startup phase */
-typedef struct {
-	u_int active;		/* true/false */
-	u_int base;		/* ipac base address */
-} IPAC_STATE;
-
-static IPAC_STATE ipac_state[4 + 1] __initdata =
-{
-	{0, 0},			/* dummy */
-	{0, 0},			/* SCT_1 */
-	{0, 0},			/* SCT_2 */
-	{0, 0},			/* SCT_3 */
-	{0, 0}			/* SCT_4 */
-};
+const char sct_quadro_revision[] = "$Revision: 1.14.6.3 $";
 
 static const char *sct_quadro_subtypes[] =
 {
@@ -167,19 +127,13 @@
 	writereg(cs->hw.ax.base, cs->hw.ax.data_adr, offset + (hscx ? 0x40 : 0), value);
 }
 
-/* Check whether the specified ipac is already active or not */
-static int
-is_ipac_active(u_int ipac_nr)
-{
-	return (ipac_state[ipac_nr].active);
-}
-
 /* Set the specific ipac to active */
 static void
-set_ipac_active(u_int ipac_nr, u_int active)
+set_ipac_active(struct IsdnCardState *cs, u_int active)
 {
-	/* set activation state */
-	ipac_state[ipac_nr].active = active;
+	/* set irq mask */
+	writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK,
+		active ? 0xc0 : 0xff);
 }
 
 /*
@@ -202,13 +156,14 @@
 {
 	struct IsdnCardState *cs = dev_id;
 	u_char ista, val, icnt = 5;
-	int i;
+
 	if (!cs) {
 		printk(KERN_WARNING "HiSax: Scitel Quadro: Spurious interrupt!\n");
 		return;
 	}
 	ista = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ISTA);
-
+	if (!(ista & 0x3f)) /* not this IPAC */
+		return;
       Start_IPAC:
 	if (cs->debug & L1_DEB_IPAC)
 		debugl1(cs, "IPAC ISTA %02X", ista);
@@ -245,30 +200,15 @@
 		       sct_quadro_subtypes[cs->subtyp]);
 	writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xFF);
 	writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xC0);
-
-	/* Read out all interrupt sources from currently not active ipacs */
-	/* "Handle" all interrupts from currently not active ipac by reading the regs */
-	for (i = SCT_1; i <= SCT_4; i++)
-		if (!is_ipac_active(i)) {
-			u_int base = ipac_state[i].base;
-			if (readreg(base, base + 4, 0xC1)) {
-				readreg(base, base + 4, 0xA0);
-				readreg(base, base + 4, 0xA4);
-				readreg(base, base + 4, 0x20);
-				readreg(base, base + 4, 0x24);
-				readreg(base, base + 4, 0x60);
-				readreg(base, base + 4, 0x64);
-				readreg(base, base + 4, 0xC1);
-				readreg(base, base + 4, ISAC_CIR0 + 0x80);
-			}
-		}
 }
 
 
 void
 release_io_sct_quadro(struct IsdnCardState *cs)
 {
-	/* ?? */
+	release_region(cs->hw.ax.base & 0xffffffc0, 256);
+	if (cs->subtyp == SCT_1)
+		release_region(cs->hw.ax.plx_adr, 256);
 }
 
 static void
@@ -278,11 +218,6 @@
 		if (bEnable)
 			wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) | 0x41));
 		else
-			/* Issue general di only if no ipac is active */
-			if (!is_ipac_active(SCT_1) &&
-			    !is_ipac_active(SCT_2) &&
-			    !is_ipac_active(SCT_3) &&
-			    !is_ipac_active(SCT_4))
 			wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) & ~0x41));
 	}
 }
@@ -292,26 +227,17 @@
 {
 	long flags;
 
-	if (cs->typ == ISDN_CTYPE_SCT_QUADRO) {
-		if (!is_ipac_active(SCT_1) &&
-		    !is_ipac_active(SCT_2) &&
-		    !is_ipac_active(SCT_3) &&
-		    !is_ipac_active(SCT_4)) {
-			/* Issue total reset only if no ipac is active */
-			wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) & ~4));
-
-			save_flags(flags);
-			sti();
-			current->state = TASK_UNINTERRUPTIBLE;
-			schedule_timeout((10 * HZ) / 1000);
-
-			/* Remove the soft reset */
-			wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) | 4));
-
-			current->state = TASK_UNINTERRUPTIBLE;
-			schedule_timeout((10 * HZ) / 1000);
-			restore_flags(flags);
-		}
+	if (cs->subtyp == SCT_1) {
+		wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) & ~4));
+		save_flags(flags);
+		sti();
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout((10 * HZ) / 1000);
+		/* Remove the soft reset */
+		wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) | 4));
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout((10 * HZ) / 1000);
+		restore_flags(flags);
 	}
 }
 
@@ -321,20 +247,19 @@
 	switch (mt) {
 		case CARD_RESET:
 			/* Disable ints */
-			set_ipac_active(cs->subtyp, 0);
+			set_ipac_active(cs, 0);
 			enable_bkm_int(cs, 0);
 			reset_bkm(cs);
 			return (0);
 		case CARD_RELEASE:
 			/* Sanity */
-			set_ipac_active(cs->subtyp, 0);
+			set_ipac_active(cs, 0);
 			enable_bkm_int(cs, 0);
-			reset_bkm(cs);
 			release_io_sct_quadro(cs);
 			return (0);
 		case CARD_INIT:
 			cs->debug |= L1_DEB_IPAC;
-			set_ipac_active(cs->subtyp, 1);
+			set_ipac_active(cs, 1);
 			inithscxisac(cs, 3);
 			/* Enable ints */
 			enable_bkm_int(cs, 1);
@@ -345,18 +270,38 @@
 	return (0);
 }
 
+int __init
+sct_alloc_io(u_int adr, u_int len)
+{
+	if (check_region(adr, len)) {
+		printk(KERN_WARNING
+			"HiSax: Scitel port %#x-%#x already in use\n",
+			adr, adr + len);
+		return (1);
+	} else {
+		request_region(adr, len, "scitel");
+	}
+	return(0);
+}
+
 static struct pci_dev *dev_a8 __initdata = NULL;
+static u16  sub_vendor_id __initdata = 0;
+static u16  sub_sys_id __initdata = 0;
+static u_char pci_bus __initdata = 0;
+static u_char pci_device_fn __initdata = 0;
+static u_char pci_irq __initdata = 0;
+
+#endif /* CONFIG_PCI */
 
-__initfunc(int
-	   setup_sct_quadro(struct IsdnCard *card))
+int __init
+setup_sct_quadro(struct IsdnCard *card)
 {
+#if CONFIG_PCI
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
-#if CONFIG_PCI
-	u_char pci_bus = 0, pci_device_fn = 0, pci_irq = 0, pci_rev_id;
+	u_char pci_rev_id;
 	u_int found = 0;
 	u_int pci_ioaddr1, pci_ioaddr2, pci_ioaddr3, pci_ioaddr4, pci_ioaddr5;
-#endif
 
 	strcpy(tmp, sct_quadro_revision);
 	printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp));
@@ -368,32 +313,61 @@
 	/* Identify subtype by para[0] */
 	if (card->para[0] >= SCT_1 && card->para[0] <= SCT_4)
 		cs->subtyp = card->para[0];
-	else
+	else {
 		printk(KERN_WARNING "HiSax: %s: Invalid subcontroller in configuration, default to 1\n",
-		       CardType[card->typ]);
-#if CONFIG_PCI
-	if (!pci_present()) {
-		printk(KERN_ERR "bkm_a4t: no PCI bus present\n");
+			CardType[card->typ]);
 		return (0);
 	}
-	if ((dev_a8 = pci_find_device(PLX_VENDOR_ID, PLX_DEVICE_ID, dev_a8))) {
-		u_int sub_sys_id = 0;
-
-		pci_read_config_dword(dev_a8, PCI_SUBSYSTEM_VENDOR_ID,
-			&sub_sys_id);
-		if (sub_sys_id == ((SCT_SUBSYS_ID << 16) | SCT_SUBVEN_ID)) {
-			found = 1;
-			pci_ioaddr1 = dev_a8->base_address[ 1];
-			pci_irq = dev_a8->irq;
-			pci_bus = dev_a8->bus->number;
-			pci_device_fn = dev_a8->devfn;
-		}
-	}
-	if (!found) {
-		printk(KERN_WARNING "HiSax: %s (%s): Card not found\n",
-		       CardType[card->typ],
-		       sct_quadro_subtypes[cs->subtyp]);
+	if ((cs->subtyp != SCT_1) && ((sub_sys_id != PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO) ||
+		(sub_vendor_id != PCI_VENDOR_ID_BERKOM)))
 		return (0);
+	if (cs->subtyp == SCT_1) {
+		if (!pci_present()) {
+			printk(KERN_ERR "bkm_a4t: no PCI bus present\n");
+			return (0);
+		}
+		while ((dev_a8 = pci_find_device(PCI_VENDOR_ID_PLX,
+			PCI_DEVICE_ID_PLX_9050, dev_a8))) {
+			
+			pci_read_config_word(dev_a8, PCI_SUBSYSTEM_VENDOR_ID, &sub_vendor_id);
+			pci_read_config_word(dev_a8, PCI_SUBSYSTEM_ID, &sub_sys_id);
+			if ((sub_sys_id == PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO) &&
+				(sub_vendor_id == PCI_VENDOR_ID_BERKOM)) {
+				if (pci_enable_device(dev_a8))
+					return(0);
+				pci_ioaddr1 = dev_a8->base_address[ 1] & PCI_BASE_ADDRESS_IO_MASK;
+				pci_irq = dev_a8->irq;
+				pci_bus = dev_a8->bus->number;
+				pci_device_fn = dev_a8->devfn;
+				found = 1;
+				break;
+			}
+		}
+		if (!found) {
+			printk(KERN_WARNING "HiSax: %s (%s): Card not found\n",
+				CardType[card->typ],
+				sct_quadro_subtypes[cs->subtyp]);
+			return (0);
+		}
+#ifdef ATTEMPT_PCI_REMAPPING
+/* HACK: PLX revision 1 bug: PLX address bit 7 must not be set */
+		pcibios_read_config_byte(pci_bus, pci_device_fn,
+			PCI_REVISION_ID, &pci_rev_id);
+		if ((pci_ioaddr1 & 0x80) && (pci_rev_id == 1)) {
+			printk(KERN_WARNING "HiSax: %s (%s): PLX rev 1, remapping required!\n",
+				CardType[card->typ],
+				sct_quadro_subtypes[cs->subtyp]);
+			/* Restart PCI negotiation */
+			pcibios_write_config_dword(pci_bus, pci_device_fn,
+				PCI_BASE_ADDRESS_1, (u_int) - 1);
+			/* Move up by 0x80 byte */
+			pci_ioaddr1 += 0x80;
+			pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK;
+			pcibios_write_config_dword(pci_bus, pci_device_fn,
+				PCI_BASE_ADDRESS_1, pci_ioaddr1);
+			dev_a8->base_address[ 1] = pci_ioaddr1;
+		}
+#endif /* End HACK */
 	}
 	if (!pci_irq) {		/* IRQ range check ?? */
 		printk(KERN_WARNING "HiSax: %s (%s): No IRQ\n",
@@ -401,25 +375,6 @@
 		       sct_quadro_subtypes[cs->subtyp]);
 		return (0);
 	}
-#ifdef ATTEMPT_PCI_REMAPPING
-/* HACK: PLX revision 1 bug: PLX address bit 7 must not be set */
-	pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_REVISION_ID, &pci_rev_id);
-	if ((pci_ioaddr1 & 0x80) && (pci_rev_id == 1)) {
-		printk(KERN_WARNING "HiSax: %s (%s): PLX rev 1, remapping required!\n",
-			CardType[card->typ],
-			sct_quadro_subtypes[cs->subtyp]);
-		/* Restart PCI negotiation */
-		pcibios_write_config_dword(pci_bus, pci_device_fn,
-			PCI_BASE_ADDRESS_1, (u_int) - 1);
-		/* Move up by 0x80 byte */
-		pci_ioaddr1 += 0x80;
-		pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK;
-		pcibios_write_config_dword(pci_bus, pci_device_fn,
-			PCI_BASE_ADDRESS_1, pci_ioaddr1);
-		dev_a8->base_address[ 1] = pci_ioaddr1;
-	}
-/* End HACK */
-#endif
 	pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &pci_ioaddr1);
 	pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_2, &pci_ioaddr2);
 	pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_3, &pci_ioaddr3);
@@ -446,23 +401,42 @@
 	/* pci_ioaddr5 is for the first subdevice only */
 	cs->hw.ax.plx_adr = pci_ioaddr1;
 	/* Enter all ipac_base addresses */
-	ipac_state[SCT_1].base = pci_ioaddr5 + 0x00;
-	ipac_state[SCT_2].base = pci_ioaddr4 + 0x08;
-	ipac_state[SCT_3].base = pci_ioaddr3 + 0x10;
-	ipac_state[SCT_4].base = pci_ioaddr2 + 0x20;
-	/* For isac and hscx control path */
-	cs->hw.ax.base = ipac_state[cs->subtyp].base;
+	switch(cs->subtyp) {
+		case 1:
+			cs->hw.ax.base = pci_ioaddr5 + 0x00;
+			if (sct_alloc_io(pci_ioaddr1, 256))
+				return(0);
+			if (sct_alloc_io(pci_ioaddr5, 256))
+				return(0);
+			/* disable all IPAC */
+			writereg(pci_ioaddr5, pci_ioaddr5 + 4,
+				IPAC_MASK, 0xFF);
+			writereg(pci_ioaddr4 + 0x08, pci_ioaddr4 + 0x0c,
+				IPAC_MASK, 0xFF);
+			writereg(pci_ioaddr3 + 0x10, pci_ioaddr3 + 0x14,
+				IPAC_MASK, 0xFF);
+			writereg(pci_ioaddr2 + 0x20, pci_ioaddr2 + 0x24,
+				IPAC_MASK, 0xFF);
+			break;
+		case 2:
+			cs->hw.ax.base = pci_ioaddr4 + 0x08;
+			if (sct_alloc_io(pci_ioaddr4, 256))
+				return(0);
+			break;
+		case 3:
+			cs->hw.ax.base = pci_ioaddr3 + 0x10;
+			if (sct_alloc_io(pci_ioaddr3, 256))
+				return(0);
+			break;
+		case 4:
+			cs->hw.ax.base = pci_ioaddr2 + 0x20;
+			if (sct_alloc_io(pci_ioaddr2, 256))
+				return(0);
+			break;
+	}	
 	/* For isac and hscx data path */
 	cs->hw.ax.data_adr = cs->hw.ax.base + 4;
-#else
-	printk(KERN_WARNING "HiSax: %s (%s): NO_PCI_BIOS\n",
-	       CardType[card->typ],
-	       sct_quadro_subtypes[cs->subtyp]);
-	printk(KERN_WARNING "HiSax: %s (%s): Unable to configure\n",
-	       CardType[card->typ],
-	       sct_quadro_subtypes[cs->subtyp]);
-	return (0);
-#endif				/* CONFIG_PCI */
+
 	printk(KERN_INFO "HiSax: %s (%s) configured at 0x%.4X, 0x%.4X, 0x%.4X and IRQ %d\n",
 	       CardType[card->typ],
 	       sct_quadro_subtypes[cs->subtyp],
@@ -473,19 +447,6 @@
 
 	test_and_set_bit(HW_IPAC, &cs->HW_Flags);
 
-	/* Disable all currently not active ipacs */
-	if (!is_ipac_active(SCT_1))
-		set_ipac_active(SCT_1, 0);
-	if (!is_ipac_active(SCT_2))
-		set_ipac_active(SCT_2, 0);
-	if (!is_ipac_active(SCT_3))
-		set_ipac_active(SCT_3, 0);
-	if (!is_ipac_active(SCT_4))
-		set_ipac_active(SCT_4, 0);
-
-	/* Perfom general reset (if possible) */
-	reset_bkm(cs);
-
 	cs->readisac = &ReadISAC;
 	cs->writeisac = &WriteISAC;
 	cs->readisacfifo = &ReadISACfifo;
@@ -502,4 +463,7 @@
 		sct_quadro_subtypes[cs->subtyp],
 		readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ID));
 	return (1);
+#else
+	printk(KERN_ERR "HiSax: bkm_a8 only supported on PCI Systems\n");
+#endif /* CONFIG_PCI */
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/bkm_ax.h linux.19p18/drivers/isdn/hisax/bkm_ax.h
--- linux.vanilla/drivers/isdn/hisax/bkm_ax.h	Fri Apr 21 12:46:09 2000
+++ linux.19p18/drivers/isdn/hisax/bkm_ax.h	Sat Dec 30 19:33:51 2000
@@ -1,13 +1,9 @@
-/* $Id: bkm_ax.h,v 1.2 1999/07/01 08:07:55 keil Exp $
+/* $Id: bkm_ax.h,v 1.5.6.1 2000/11/28 12:02:46 kai Exp $
  * bkm_ax.h   low level decls for T-Berkom cards A4T and Scitel Quadro (4*S0, passive)
  *
  * Author     Roland Klabunde (R.Klabunde@Berkom.de)
  *
- * $Log: bkm_ax.h,v $
- * Revision 1.2  1999/07/01 08:07:55  keil
- * Initial version
- *
- *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 
@@ -20,19 +16,6 @@
 #define	SCT_3		3
 #define	SCT_4		4
 #define BKM_A4T		5
-
-
-/* A4T																*/
-#define I20_DEVICE_ID       	0x6120  /* I20 PCI device ID */
-#define I20_VENDOR_ID       	0x11DE  /* I20 PCI vendor ID */
-#define	A4T_SUBVEN_ID		0x0871	
-#define	A4T_SUBSYS_ID		0xFFA4
-/* Scitel Quadro 																*/
-#define	PLX_DEVICE_ID		0x9050	/* Scitel Quadro PLX */
-#define	PLX_VENDOR_ID		0x10B5
-#define	SCT_SUBVEN_ID		0x0871
-#define	SCT_SUBSYS_ID		0xFFA8
-
 
 #define	PLX_ADDR_PLX		0x14	/* Addr PLX configuration */
 #define	PLX_ADDR_ISAC		0x18	/* Addr ISAC */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/callc.c linux.19p18/drivers/isdn/hisax/callc.c
--- linux.vanilla/drivers/isdn/hisax/callc.c	Fri Apr 21 12:46:09 2000
+++ linux.19p18/drivers/isdn/hisax/callc.c	Tue Feb 13 18:48:23 2001
@@ -1,5 +1,5 @@
-/* $Id: callc.c,v 2.40 1999/12/19 12:59:56 keil Exp $
-
+/* $Id: callc.c,v 2.51 2000/11/24 17:05:37 kai Exp $
+ *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
  *
@@ -10,156 +10,9 @@
  * Thanks to    Jan den Ouden
  *              Fritz Elfert
  *
- * $Log: callc.c,v $
- * Revision 2.40  1999/12/19 12:59:56  keil
- * fix leased line handling
- * and cosmetics
- *
- * Revision 2.39  1999/10/14 20:25:28  keil
- * add a statistic for error monitoring
- *
- * Revision 2.38  1999/10/11 22:16:27  keil
- * Suspend/Resume is possible without explicit ID too
- *
- * Revision 2.37  1999/09/20 19:49:47  keil
- * Fix wrong init of PStack
- *
- * Revision 2.36  1999/09/20 12:13:13  keil
- * Fix hang if no protocol was selected
- *
- * Revision 2.35  1999/09/04 06:20:05  keil
- * Changes from kernel set_current_state()
- *
- * Revision 2.34  1999/08/25 20:02:34  werner
- * Changed return values for stat_icall(w) from 3->4 and 4->5 because of conflicts
- * with existing software definitions. (PtP incomplete called party number)
- *
- * Revision 2.33  1999/08/25 17:00:09  keil
- * Make ISAR V32bis modem running
- * Make LL->HL interface open for additional commands
- *
- * Revision 2.32  1999/08/22 20:27:01  calle
- * backported changes from kernel 2.3.14:
- * - several #include "config.h" gone, others come.
- * - "struct device" changed to "struct net_device" in 2.3.14, added a
- *   define in isdn_compat.h for older kernel versions.
- *
- * Revision 2.31  1999/08/05 20:43:10  keil
- * ISAR analog modem support
- *
- * Revision 2.30  1999/07/25 16:24:04  keil
- * Fixed TEI now working again
- *
- * Revision 2.29  1999/07/13 21:05:41  werner
- * Modified set_channel_limit to use new callback ISDN_STAT_DISCH.
- *
- * Revision 2.28  1999/07/09 08:30:02  keil
- * cosmetics
- *
- * Revision 2.27  1999/07/05 23:51:38  werner
- * Allow limiting of available HiSax B-chans per card. Controlled by hisaxctrl
- * hisaxctrl id 10 <nr. of chans 0-2>
- *
- * Revision 2.26  1999/07/01 08:11:21  keil
- * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
- *
- * Revision 2.25  1999/01/02 11:17:20  keil
- * Changes for 2.2
- *
- * Revision 2.24  1998/11/15 23:54:24  keil
- * changes from 2.0
- *
- * Revision 2.23  1998/09/30 22:21:57  keil
- * cosmetics
- *
- * Revision 2.22  1998/08/20 13:50:29  keil
- * More support for hybrid modem (not working yet)
- *
- * Revision 2.21  1998/08/13 23:36:15  keil
- * HiSax 3.1 - don't work stable with current LinkLevel
- *
- * Revision 2.20  1998/06/26 15:13:05  fritz
- * Added handling of STAT_ICALL with incomplete CPN.
- * Added AT&L for ttyI emulator.
- * Added more locking stuff in tty_write.
- *
- * Revision 2.19  1998/05/25 14:08:06  keil
- * HiSax 3.0
- * fixed X.75 and leased line to work again
- * Point2Point and fixed TEI are runtime options now:
- *    hisaxctrl <id> 7 1  set PTP
- *    hisaxctrl <id> 8 <TEIVALUE *2 >
- *    set fixed TEI to TEIVALUE (0-63)
- *
- * Revision 2.18  1998/05/25 12:57:40  keil
- * HiSax golden code from certification, Don't use !!!
- * No leased lines, no X75, but many changes.
- *
- * Revision 2.17  1998/04/15 16:46:06  keil
- * RESUME support
- *
- * Revision 2.16  1998/04/10 10:35:17  paul
- * fixed (silly?) warnings from egcs on Alpha.
- *
- * Revision 2.15  1998/03/19 13:18:37  keil
- * Start of a CAPI like interface for supplementary Service
- * first service: SUSPEND
- *
- * Revision 2.14  1998/03/07 22:56:54  tsbogend
- * made HiSax working on Linux/Alpha
- *
- * Revision 2.13  1998/02/12 23:07:16  keil
- * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
- *
- * Revision 2.12  1998/02/09 10:55:54  keil
- * New leased line mode
- *
- * Revision 2.11  1998/02/02 13:35:19  keil
- * config B-channel delay
- *
- * Revision 2.10  1997/11/06 17:09:15  keil
- * New 2.1 init code
- *
- * Revision 2.9  1997/10/29 19:01:58  keil
- * new LL interface
- *
- * Revision 2.8  1997/10/10 20:56:44  fritz
- * New HL interface.
- *
- * Revision 2.7  1997/10/01 09:21:28  fritz
- * Removed old compatibility stuff for 2.0.X kernels.
- * From now on, this code is for 2.1.X ONLY!
- * Old stuff is still in the separate branch.
- *
- * Revision 2.6  1997/09/11 17:26:58  keil
- * Open B-channel if here are incomming packets
- *
- * Revision 2.5  1997/08/07 17:46:05  keil
- * Fix Incomming Call without broadcast
- *
- * Revision 2.4  1997/08/03 14:37:58  keil
- * Activate Layer2 in PtP mode
- *
- * Revision 2.3  1997/07/31 19:23:40  keil
- * LAYER2_WATCHING for PtP
- *
- * Revision 2.2  1997/07/31 11:48:18  keil
- * experimental REJECT after ALERTING
- *
- * Revision 2.1  1997/07/30 17:12:59  keil
- * more changes for 'One TEI per card'
- *
- * Revision 2.0  1997/07/27 21:12:21  keil
- * CRef based L3; new channel handling; many other stuff
- *
- * Revision 1.31  1997/06/26 11:09:23  keil
- * New managment and minor changes
- *
- * old logs removed /KKe
- *
  */
-
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "../avmb1/capicmd.h"  /* this should be moved in a common place */
 
@@ -167,7 +20,7 @@
 #define MOD_USE_COUNT ( GET_USE_COUNT (&__this_module))
 #endif	/* MODULE */
 
-const char *lli_revision = "$Revision: 2.40 $";
+const char *lli_revision = "$Revision: 2.51 $";
 
 extern struct IsdnCard cards[];
 extern int nrcards;
@@ -177,10 +30,8 @@
 static int init_b_st(struct Channel *chanp, int incoming);
 static void release_b_st(struct Channel *chanp);
 
-static struct Fsm callcfsm =
-{NULL, 0, 0, NULL, NULL};
-
-static int chancount = 0;
+static struct Fsm callcfsm;
+static int chancount;
 
 /* experimental REJECT after ALERTING for CALLBACK to beat the 4s delay */
 #define ALERT_REJECT 0
@@ -349,6 +200,8 @@
 {
 	isdn_ctrl ic;
 
+	if (!chanp->proc)
+		return;
 	if (chanp->proc->para.cause == NO_CAUSE)
 		return;
 	ic.driver = chanp->cs->myid;
@@ -511,7 +364,7 @@
 		 * No need to return "unknown" for calls without OAD,
 		 * cause that's handled in linklevel now (replaced by '0')
 		 */
-		ic.parm.setup = chanp->proc->para.setup;
+		memcpy(&ic.parm.setup, &chanp->proc->para.setup, sizeof(setup_parm));
 		ret = chanp->cs->iif.statcallb(&ic);
 		if (chanp->debug & 1)
 			link_debug(chanp, 1, "statcallb ret=%d", ret);
@@ -528,12 +381,16 @@
 				FsmChangeState(fi, ST_IN_PROCEED_SEND);
 				chanp->d_st->lli.l4l3(chanp->d_st, CC_PROCEED_SEND | REQUEST, chanp->proc);
 				if (ret == 5) {
-					chanp->setup = ic.parm.setup;
+					memcpy(&chanp->setup, &ic.parm.setup, sizeof(setup_parm));
 					chanp->d_st->lli.l4l3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc);
 				}
 				break;
 			case 2:	/* Rejecting Call */
 				break;
+			case 3:	/* incomplete number */
+				FsmDelTimer(&chanp->drel_timer, 61);
+				chanp->d_st->lli.l4l3(chanp->d_st, CC_MORE_INFO | REQUEST, chanp->proc);
+				break;
 			case 0:	/* OK, nobody likes this call */
 			default:	/* statcallb problems */
 				chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc);
@@ -641,7 +498,8 @@
 		lli_leased_hup(fi, chanp);
 	} else {
 		FsmChangeState(fi, ST_WAIT_DRELEASE);
-		chanp->proc->para.cause = 0x10;	/* Normal Call Clearing */
+		if (chanp->proc)
+			chanp->proc->para.cause = 0x10;	/* Normal Call Clearing */
 		chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST,
 			chanp->proc);
 	}
@@ -656,7 +514,8 @@
 		lli_leased_hup(fi, chanp);
 	} else {
 		FsmChangeState(fi, ST_WAIT_DRELEASE);
-		chanp->proc->para.cause = 0x15;	/* Call Rejected */
+		if (chanp->proc)
+			chanp->proc->para.cause = 0x15;	/* Call Rejected */
 		chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST,
 			chanp->proc);
 	}
@@ -688,7 +547,8 @@
 		return;
 	}
 #ifndef ALERT_REJECT
-	chanp->proc->para.cause = 0x15;	/* Call Rejected */
+	if (chanp->proc)
+		chanp->proc->para.cause = 0x15;	/* Call Rejected */
 	chanp->d_st->lli.l4l3(chanp->d_st, CC_REJECT | REQUEST, chanp->proc);
 	lli_dhup_close(fi, event, arg);
 #else
@@ -920,7 +780,7 @@
 }
 
 /* *INDENT-OFF* */
-static struct FsmNode fnlist[] HISAX_INITDATA =
+static struct FsmNode fnlist[] __initdata =
 {
         {ST_NULL,               EV_DIAL,                lli_prep_dialout},
         {ST_NULL,               EV_RESUME,              lli_resume},
@@ -937,6 +797,8 @@
         {ST_IN_WAIT_LL,         EV_HANGUP,              lli_reject_req},
         {ST_IN_WAIT_LL,         EV_DISCONNECT_IND,      lli_release_req},
         {ST_IN_WAIT_LL,         EV_RELEASE,             lli_dhup_close},
+        {ST_IN_WAIT_LL,         EV_SETUP_IND,           lli_deliver_call},
+        {ST_IN_WAIT_LL,         EV_SETUP_ERR,           lli_error},
         {ST_IN_ALERT_SENT,      EV_SETUP_CMPL_IND,      lli_init_bchan_in},
         {ST_IN_ALERT_SENT,      EV_ACCEPTD,             lli_send_dconnect},
         {ST_IN_ALERT_SENT,      EV_HANGUP,              lli_disconnect_reject},
@@ -988,8 +850,8 @@
 
 #define FNCOUNT (sizeof(fnlist)/sizeof(struct FsmNode))
 
-HISAX_INITFUNC(void
-CallcNew(void))
+void __init
+CallcNew(void)
 {
 	callcfsm.state_count = STATE_COUNT;
 	callcfsm.event_count = EVENT_COUNT;
@@ -1016,6 +878,7 @@
 				releasestack_isdnl2(st);
 				break;
 			case (ISDN_PROTO_L2_HDLC):
+			case (ISDN_PROTO_L2_HDLC_56K):
 			case (ISDN_PROTO_L2_TRANS):
 			case (ISDN_PROTO_L2_MODEM):
 			case (ISDN_PROTO_L2_FAX):
@@ -1098,6 +961,9 @@
 		return;
 
 	switch (pr) {
+		case (CC_MORE_INFO | INDICATION):
+			FsmEvent(&chanp->fi, EV_SETUP_IND, NULL);
+			break;
 		case (CC_DISCONNECT | INDICATION):
 			FsmEvent(&chanp->fi, EV_DISCONNECT_IND, NULL);
 			break;
@@ -1245,7 +1111,7 @@
 	chanp->fi.printdebug = callc_debug;
 	FsmInitTimer(&chanp->fi, &chanp->dial_timer);
 	FsmInitTimer(&chanp->fi, &chanp->drel_timer);
-	if (!chan || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) {
+	if (!chan || (test_bit(FLG_TWO_DCHAN, &csta->HW_Flags) && chan < 2)) {
 		init_d_st(chanp);
 	} else {
 		chanp->d_st = csta->channel->d_st;
@@ -1318,9 +1184,12 @@
 
 	switch (pr) {
 		case (DL_DATA  | INDICATION):
-			if (chanp->data_open)
+			if (chanp->data_open) {
+				if (chanp->debug & 0x800)
+					link_debug(chanp, 0, "lldata: %d", skb->len);
 				chanp->cs->iif.rcvcallb_skb(chanp->cs->myid, chanp->chan, skb);
-			else {
+			} else {
+				link_debug(chanp, 0, "lldata: channel not open");
 				dev_kfree_skb(skb);
 			}
 			break;
@@ -1347,10 +1216,12 @@
 
 	switch (pr) {
 		case (PH_DATA | INDICATION):
-			if (chanp->data_open)
+			if (chanp->data_open) {
+				if (chanp->debug & 0x800)
+					link_debug(chanp, 0, "lltrans: %d", skb->len);
 				chanp->cs->iif.rcvcallb_skb(chanp->cs->myid, chanp->chan, skb);
-			else {
-				link_debug(chanp, 0, "channel not open");
+			} else {
+				link_debug(chanp, 0, "lltrans: channel not open");
 				dev_kfree_skb(skb);
 			}
 			break;
@@ -1375,6 +1246,8 @@
 	struct Channel *chanp = st->lli.userdata;
 	isdn_ctrl ic;
 
+	if (chanp->debug & 0x800)
+		link_debug(chanp, 0, "llwakeup: %d", len);
 	ic.driver = chanp->cs->myid;
 	ic.command = ISDN_STAT_BSENT;
 	ic.arg = chanp->chan;
@@ -1399,6 +1272,9 @@
 		case (ISDN_PROTO_L2_HDLC):
 			st->l1.mode = L1_MODE_HDLC;
 			break;
+		case (ISDN_PROTO_L2_HDLC_56K):
+			st->l1.mode = L1_MODE_HDLC_56K;
+			break;
 		case (ISDN_PROTO_L2_TRANS):
 			st->l1.mode = L1_MODE_TRANS;
 			break;
@@ -1435,6 +1311,7 @@
 			st->l2.debug = chanp->debug & 64;
 			break;
 		case (ISDN_PROTO_L2_HDLC):
+		case (ISDN_PROTO_L2_HDLC_56K):
 		case (ISDN_PROTO_L2_TRANS):
 		case (ISDN_PROTO_L2_MODEM):
 		case (ISDN_PROTO_L2_FAX):
@@ -1648,7 +1525,7 @@
 				link_debug(chanp, 1, "DIAL %s -> %s (%d,%d)",
 					ic->parm.setup.eazmsn, ic->parm.setup.phone,
 					ic->parm.setup.si1, ic->parm.setup.si2);
-			chanp->setup = ic->parm.setup;
+			memcpy(&chanp->setup, &ic->parm.setup, sizeof(setup_parm));
 			if (!strcmp(chanp->setup.eazmsn, "0"))
 				chanp->setup.eazmsn[0] = '\0';
 			/* this solution is dirty and may be change, if
@@ -1668,6 +1545,7 @@
 			break;
 		case (ISDN_CMD_ACCEPTD):
 			chanp = csta->channel + ic->arg;
+			memcpy(&chanp->setup, &ic->parm.setup, sizeof(setup_parm));
 			if (chanp->debug & 1)
 				link_debug(chanp, 1, "ACCEPTD");
 			FsmEvent(&chanp->fi, EV_ACCEPTD, NULL);
@@ -1864,7 +1742,7 @@
 			chanp = csta->channel + ic->arg;
 			if (chanp->debug & 1)
 				link_debug(chanp, 1, "REDIR");
-			chanp->setup = ic->parm.setup;
+			memcpy(&chanp->setup, &ic->parm.setup, sizeof(setup_parm));
 			FsmEvent(&chanp->fi, EV_REDIR, NULL);
 			break;
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/cert.c linux.19p18/drivers/isdn/hisax/cert.c
--- linux.vanilla/drivers/isdn/hisax/cert.c	Fri Apr 21 12:46:09 2000
+++ linux.19p18/drivers/isdn/hisax/cert.c	Wed Dec 13 22:07:05 2000
@@ -1,22 +1,11 @@
-/* $Id: cert.c,v 2.2 1999/08/07 17:35:05 keil Exp $
-
+/* $Id: cert.c,v 2.3 2000/06/26 08:59:12 keil Exp $
+ *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *
  *		This file is (c) under GNU PUBLIC LICENSE
  *		For changes and modifications please read
  *		../../../Documentation/isdn/HiSax.cert
  *
- * $Log: cert.c,v $
- * Revision 2.2  1999/08/07 17:35:05  keil
- * approval for Eicon Technology Diva 2.01 PCI
- *
- * Revision 2.1  1998/11/15 23:51:15  keil
- * certification stuff
- *
- * Revision 1.2.2.1  1998/11/03 21:46:37  keil
- * first version
- *
- *
  */
  
 #include <linux/kernel.h>
@@ -28,11 +17,9 @@
 #if CERTIFICATION == 0
 	if (output) {
 		printk(KERN_INFO "HiSax: Approval certification valid\n");
-		printk(KERN_INFO "HiSax: Approved with ELSA Quickstep series cards\n");
-		printk(KERN_INFO "HiSax: Approval registration numbers:\n");
-		printk(KERN_INFO "HiSax: German D133361J CETECOM ICT Services GmbH\n");
-		printk(KERN_INFO "HiSax: EU (D133362J) CETECOM ICT Services GmbH\n");
+		printk(KERN_INFO "HiSax: Approved with ELSA Microlink PCI cards\n");
 		printk(KERN_INFO "HiSax: Approved with Eicon Technology Diva 2.01 PCI cards\n");
+		printk(KERN_INFO "HiSax: Approved with Sedlbauer Speedfax + cards\n");
 	}
 	return(0);
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/config.c linux.19p18/drivers/isdn/hisax/config.c
--- linux.vanilla/drivers/isdn/hisax/config.c	Mon Dec 11 22:12:45 2000
+++ linux.19p18/drivers/isdn/hisax/config.c	Wed Feb 14 14:28:52 2001
@@ -1,167 +1,16 @@
-/* $Id: config.c,v 2.44 2000/02/26 00:35:12 keil Exp $
-
+/* $Id: config.c,v 2.57.6.9 2001/02/13 10:33:58 kai Exp $
+ *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
  *
- *
- * $Log: config.c,v $
- * Revision 2.44  2000/02/26 00:35:12  keil
- * Fix skb freeing in interrupt context
- *
- * Revision 2.43  2000/01/20 19:49:36  keil
- * Support teles 13.3c vendor version 2.1
- *
- * Revision 2.42  1999/12/19 13:09:41  keil
- * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
- * signal proof delays
- *
- * Revision 2.41  1999/11/18 00:00:43  werner
- *
- * Added support for HFC-S+ and HFC-SP cards
- *
- * Revision 2.40  1999/10/30 13:09:45  keil
- * Version 3.3c
- *
- * Revision 2.39  1999/10/16 14:44:45  keil
- * Fix module parm if only NICCY was selected
- *
- * Revision 2.38  1999/10/14 20:25:28  keil
- * add a statistic for error monitoring
- *
- * Revision 2.37  1999/09/20 12:11:08  keil
- * Fix hang if no protocol was selected
- *
- * Revision 2.36  1999/09/07 05:43:58  werner
- *
- * Added io as parameter 0 for HFC-PCI cards, if manual selection needed.
- *
- * Revision 2.35  1999/09/04 06:35:09  keil
- * Winbond W6692 support
- *
- * Revision 2.34  1999/09/04 06:20:06  keil
- * Changes from kernel set_current_state()
- *
- * Revision 2.33  1999/08/30 11:57:52  keil
- * Fix broken avm pcmcia
- *
- * Revision 2.32  1999/08/28 22:11:10  keil
- * __setup function should be static
- *
- * Revision 2.31  1999/08/25 16:47:43  keil
- * Support new __setup; allow to add FEATURES after register_isdn
- *
- * Revision 2.30  1999/08/05 20:43:14  keil
- * ISAR analog modem support
- *
- * Revision 2.29  1999/07/21 14:46:00  keil
- * changes from EICON certification
- *
- * Revision 2.28  1999/07/14 12:38:36  werner
- * Added changes for echo channel handling
- *
- * Revision 2.27  1999/07/12 21:05:00  keil
- * fix race in IRQ handling
- * added watchdog for lost IRQs
- *
- * Revision 2.26  1999/07/08 21:27:17  keil
- * version 3.2
- *
- * Revision 2.25  1999/07/05 23:51:44  werner
- * Allow limiting of available HiSax B-chans per card. Controlled by hisaxctrl
- * hisaxctrl id 10 <nr. of chans 0-2>
- *
- * Revision 2.24  1999/07/01 08:11:26  keil
- * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
- *
- * Revision 2.23  1999/02/17 10:53:02  cpetig
- * Added Hisax_closecard to exported symbols.
- * As indicated by Oliver Schoett <os@sdm.de>.
- *
- * If anyone is annoyed by exporting symbols deep inside the code, please
- * contact me.
- *
- * Revision 2.22  1999/02/04 21:41:53  keil
- * Fix printk msg
- *
- * Revision 2.21  1999/02/04 10:48:52  keil
- * Fix readstat bug
- *
- * Revision 2.20  1998/11/15 23:54:28  keil
- * changes from 2.0
- *
- * Revision 2.19  1998/08/13 23:36:18  keil
- * HiSax 3.1 - don't work stable with current LinkLevel
- *
- * Revision 2.18  1998/07/30 21:01:37  niemann
- * Fixed Sedlbauer Speed Fax PCMCIA missing isdnl3new
- *
- * Revision 2.17  1998/07/15 15:01:26  calle
- * Support for AVM passive PCMCIA cards:
- *    A1 PCMCIA, FRITZ!Card PCMCIA and FRITZ!Card PCMCIA 2.0
- *
- * Revision 2.16  1998/05/25 14:10:03  keil
- * HiSax 3.0
- * X.75 and leased are working again.
- *
- * Revision 2.15  1998/05/25 12:57:43  keil
- * HiSax golden code from certification, Don't use !!!
- * No leased lines, no X75, but many changes.
- *
- * Revision 2.14  1998/04/15 16:38:25  keil
- * Add S0Box and Teles PCI support
- *
- * Revision 2.13  1998/03/09 23:19:23  keil
- * Changes for PCMCIA
- *
- * Revision 2.12  1998/02/11 17:28:02  keil
- * Niccy PnP/PCI support
- *
- * Revision 2.11  1998/02/09 21:26:13  keil
- * fix export module for 2.1
- *
- * Revision 2.10  1998/02/09 18:46:05  keil
- * Support for Sedlbauer PCMCIA (Marcus Niemann)
- *
- * Revision 2.9  1998/02/03 23:31:28  keil
- * add AMD7930 support
- *
- * Revision 2.8  1998/02/02 13:32:59  keil
- * New card support
- *
- * Revision 2.7  1998/01/31 21:41:44  keil
- * changes for newer 2.1 kernels
- *
- * Revision 2.6  1997/11/08 21:35:43  keil
- * new l1 init
- *
- * Revision 2.5  1997/11/06 17:15:08  keil
- * New 2.1 init; PCMCIA wrapper changes
- *
- * Revision 2.4  1997/10/29 19:07:52  keil
- * changes for 2.1
- *
- * Revision 2.3  1997/10/01 09:21:33  fritz
- * Removed old compatibility stuff for 2.0.X kernels.
- * From now on, this code is for 2.1.X ONLY!
- * Old stuff is still in the separate branch.
- *
- * Revision 2.2  1997/09/11 17:24:46  keil
- * Add new cards
- *
- * Revision 2.1  1997/07/27 21:41:35  keil
- * version change
- *
- * Revision 2.0  1997/06/26 11:06:28  keil
- * New card and L1 interface.
- * Eicon.Diehl Diva and Dynalink IS64PH support
- *
- * old changes removed /KKe
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 #include <linux/types.h>
 #include <linux/stddef.h>
 #include <linux/timer.h>
 #include <linux/config.h>
+#include <linux/init.h>
 #include "hisax.h"
 #include <linux/module.h>
 #include <linux/kernel_stat.h>
@@ -198,7 +47,7 @@
  *   17 MIC card                p0=irq  p1=iobase
  *   18 ELSA Quickstep 1000PCI  no parameter
  *   19 Compaq ISDN S0 ISA card p0=irq  p1=IO0 (HSCX)  p2=IO1 (ISAC) p3=IO2
- *   20 Travers Technologies NETjet PCI card
+ *   20 Travers Technologies NETjet-S PCI card
  *   21 TELES PCI               no parameter
  *   22 Sedlbauer Speed Star    p0=irq p1=iobase
  *   23 reserved
@@ -216,6 +65,8 @@
  *   35 HFC 2BDS0 PCI           none
  *   36 Winbond 6692 PCI        none
  *   37 HFC 2BDS0 S+/SP         p0=irq p1=iobase
+ *   38 Travers Technologies NETspider-U PCI card
+ *   39 HFC 2BDS0-SP PCMCIA     p0=irq p1=iobase
  *
  * protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6 or ISDN_PTYPE_NI1
  *
@@ -227,11 +78,11 @@
  "AVM A1", "Elsa ML", "Elsa Quickstep", "Teles PCMCIA", "ITK ix1-micro Rev.2",
  "Elsa PCMCIA", "Eicon.Diehl Diva", "ISDNLink", "TeleInt", "Teles 16.3c",
  "Sedlbauer Speed Card", "USR Sportster", "ith mic Linux", "Elsa PCI",
- "Compaq ISA", "NETjet", "Teles PCI", "Sedlbauer Speed Star (PCMCIA)",
+ "Compaq ISA", "NETjet-S", "Teles PCI", "Sedlbauer Speed Star (PCMCIA)",
  "AMD 7930", "NICCY", "S0Box", "AVM A1 (PCMCIA)", "AVM Fritz PnP/PCI",
  "Sedlbauer Speed Fax +", "Siemens I-Surf", "Acer P10", "HST Saphir",
  "Telekom A4T", "Scitel Quadro", "Gazel", "HFC 2BDS0 PCI", "Winbond 6692",
- "HFC 2BDS0 SX",
+ "HFC 2BDS0 SX", "NETspider-U", "HFC-2BDS0-SP PCMCIA",
 };
 
 void HiSax_closecard(int cardnr);
@@ -257,7 +108,6 @@
 #define DEFAULT_CFG {11,0x170,0,0}
 int avm_a1_init_pcmcia(void*, int, int*, int);
 EXPORT_SYMBOL(avm_a1_init_pcmcia);
-EXPORT_SYMBOL(HiSax_closecard);
 #endif /* CONFIG_HISAX_AVM_A1_PCMCIA */
 
 #ifdef CONFIG_HISAX_FRITZPCI
@@ -349,7 +199,7 @@
 #ifdef CONFIG_HISAX_NETJET
 #undef DEFAULT_CARD
 #undef DEFAULT_CFG
-#define DEFAULT_CARD ISDN_CTYPE_NETJET
+#define DEFAULT_CARD ISDN_CTYPE_NETJET_S
 #define DEFAULT_CFG {0,0,0,0}
 #endif
 
@@ -372,6 +222,8 @@
 #undef DEFAULT_CFG
 #define DEFAULT_CARD ISDN_CTYPE_HFC_SX
 #define DEFAULT_CFG {5,0x2E0,0,0}
+int hfc_init_pcmcia(void*, int, int*, int);
+EXPORT_SYMBOL(hfc_init_pcmcia);
 #endif
 
 
@@ -431,22 +283,29 @@
 #define DEFAULT_CFG {0,0,0,0}
 #endif
 
+#ifdef CONFIG_HISAX_NETJET_U
+#undef DEFAULT_CARD
+#undef DEFAULT_CFG
+#define DEFAULT_CARD ISDN_CTYPE_NETJET_U
+#define DEFAULT_CFG {0,0,0,0}
+#endif
+
 #ifdef CONFIG_HISAX_1TR6
 #define DEFAULT_PROTO ISDN_PTYPE_1TR6
 #define DEFAULT_PROTO_NAME "1TR6"
 #endif
-#ifdef CONFIG_HISAX_EURO
-#undef DEFAULT_PROTO
-#define DEFAULT_PROTO ISDN_PTYPE_EURO
-#undef DEFAULT_PROTO_NAME
-#define DEFAULT_PROTO_NAME "EURO"
-#endif
 #ifdef CONFIG_HISAX_NI1
 #undef DEFAULT_PROTO
 #define DEFAULT_PROTO ISDN_PTYPE_NI1
 #undef DEFAULT_PROTO_NAME
 #define DEFAULT_PROTO_NAME "NI1"
 #endif
+#ifdef CONFIG_HISAX_EURO
+#undef DEFAULT_PROTO
+#define DEFAULT_PROTO ISDN_PTYPE_EURO
+#undef DEFAULT_PROTO_NAME
+#define DEFAULT_PROTO_NAME "EURO"
+#endif
 #ifndef DEFAULT_PROTO
 #define DEFAULT_PROTO ISDN_PTYPE_UNKNOWN
 #define DEFAULT_PROTO_NAME "UNKNOWN"
@@ -455,6 +314,10 @@
 #error "HiSax: No cards configured"
 #endif
 
+int hisax_init_pcmcia(void *, int *, struct IsdnCard *);
+EXPORT_SYMBOL(hisax_init_pcmcia);
+EXPORT_SYMBOL(HiSax_closecard);
+
 #define FIRST_CARD { \
 	DEFAULT_CARD, \
 	DEFAULT_PROTO, \
@@ -476,18 +339,14 @@
 	EMPTY_CARD,
 };
 
-static char HiSaxID[64] HISAX_INITDATA = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" \
-"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" \
-"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
-char *HiSax_id HISAX_INITDATA = HiSaxID;
+static char HiSaxID[64]  = { 0, };
+
+char *HiSax_id  = HiSaxID;
 #ifdef MODULE
 /* Variables for insmod */
-static int type[] HISAX_INITDATA =
-{0, 0, 0, 0, 0, 0, 0, 0};
-static int protocol[] HISAX_INITDATA =
-{0, 0, 0, 0, 0, 0, 0, 0};
-static int io[] HISAX_INITDATA =
-{0, 0, 0, 0, 0, 0, 0, 0};
+static int type[8]  = { 0, };
+static int protocol[8]  = { 0, };
+static int io[8]  = { 0, };
 #undef IO0_IO1
 #ifdef CONFIG_HISAX_16_3
 #define IO0_IO1
@@ -497,16 +356,12 @@
 #define IO0_IO1
 #endif
 #ifdef IO0_IO1
-static int io0[] HISAX_INITDATA =
-{0, 0, 0, 0, 0, 0, 0, 0};
-static int io1[] HISAX_INITDATA =
-{0, 0, 0, 0, 0, 0, 0, 0};
-#endif
-static int irq[] HISAX_INITDATA =
-{0, 0, 0, 0, 0, 0, 0, 0};
-static int mem[] HISAX_INITDATA =
-{0, 0, 0, 0, 0, 0, 0, 0};
-static char *id HISAX_INITDATA = HiSaxID;
+static int io0[8]  = { 0, };
+static int io1[8]  = { 0, };
+#endif
+static int irq[8]  = { 0, };
+static int mem[8]  = { 0, };
+static char *id  = HiSaxID;
 
 MODULE_AUTHOR("Karsten Keil");
 MODULE_PARM(type, "1-8i");
@@ -529,8 +384,8 @@
 extern char *lli_revision;
 extern char *tei_revision;
 
-HISAX_INITFUNC(char *
-HiSax_getrev(const char *revision))
+char *
+HiSax_getrev(const char *revision)
 {
 	char *rev;
 	char *p;
@@ -544,16 +399,16 @@
 	return rev;
 }
 
-HISAX_INITFUNC(void
-HiSaxVersion(void))
+void __init
+HiSaxVersion(void)
 {
 	char tmp[64];
 
 	printk(KERN_INFO "HiSax: Linux Driver for passive ISDN cards\n");
 #ifdef MODULE
-	printk(KERN_INFO "HiSax: Version 3.3e (module)\n");
+	printk(KERN_INFO "HiSax: Version 3.5 (module)\n");
 #else
-	printk(KERN_INFO "HiSax: Version 3.3e (kernel)\n");
+	printk(KERN_INFO "HiSax: Version 3.5 (kernel)\n");
 #endif
 	strcpy(tmp, l1_revision);
 	printk(KERN_INFO "HiSax: Layer1 Revision %s\n", HiSax_getrev(tmp));
@@ -580,11 +435,9 @@
 	MOD_INC_USE_COUNT;
 }
 
-#ifdef MODULE
-#define HiSax_init init_module
-#else
-__initfunc(void
-HiSax_setup(char *str, int *ints))
+#ifndef MODULE
+static void __init
+HiSax_setup(char *str, int *ints)
 {
 	int i, j, argc;
 	argc = ints[0];
@@ -689,8 +542,8 @@
 extern int setup_mic(struct IsdnCard *card);
 #endif
 
-#if CARD_NETJET
-extern int setup_netjet(struct IsdnCard *card);
+#if CARD_NETJET_S
+extern int setup_netjet_s(struct IsdnCard *card);
 #endif
 
 #if CARD_HFCS
@@ -741,6 +594,10 @@
 extern int setup_w6692(struct IsdnCard *card);
 #endif
 
+#if CARD_NETJET_U
+extern int setup_netjet_u(struct IsdnCard *card);
+#endif
+
 /*
  * Find card with given driverId
  */
@@ -943,7 +800,7 @@
 	ic.command = ISDN_STAT_STOP;
 	ic.driver = cs->myid;
 	cs->iif.statcallb(&ic);
-	CallcFreeChan(cs);
+//	CallcFreeChan(cs);
 }
 
 static void
@@ -991,7 +848,8 @@
 	ll_unload(csta);
 }
 
-HISAX_INITFUNC(static int init_card(struct IsdnCardState *cs))
+static int 
+init_card(struct IsdnCardState *cs)
 {
 	int irq_cnt, cnt = 3;
 	long flags;
@@ -1012,7 +870,7 @@
 	while (cnt) {
 		cs->cardmsg(cs, CARD_INIT, NULL);
 		sti();
-		current->state = TASK_UNINTERRUPTIBLE;
+		set_current_state(TASK_UNINTERRUPTIBLE);
 		/* Timeout 10ms */
 		schedule_timeout((10*HZ)/1000);
 		restore_flags(flags);
@@ -1038,8 +896,8 @@
 	return(3);
 }
 
-HISAX_INITFUNC(static int
-checkcard(int cardnr, char *id, int *busy_flag))
+static int 
+checkcard(int cardnr, char *id, int *busy_flag)
 {
 	long flags;
 	int ret = 0;
@@ -1066,6 +924,8 @@
 	cs->busy_flag = busy_flag;
 	cs->irq_flags = I4L_IRQ_FLAG;
 #if TEI_PER_CARD
+	if (card->protocol == ISDN_PTYPE_NI1)
+		test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags);
 #else
 	test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags);
 #endif
@@ -1099,6 +959,7 @@
 		cs->iif.features =
 			ISDN_FEATURE_L2_X75I |
 			ISDN_FEATURE_L2_HDLC |
+			ISDN_FEATURE_L2_HDLC_56K |
 			ISDN_FEATURE_L2_TRANS |
 			ISDN_FEATURE_L3_TRANS |
 #ifdef	CONFIG_HISAX_1TR6
@@ -1210,9 +1071,9 @@
 				ret = setup_mic(card);
 				break;
 #endif
-#if CARD_NETJET
-			case ISDN_CTYPE_NETJET:
-				ret = setup_netjet(card);
+#if CARD_NETJET_S
+			case ISDN_CTYPE_NETJET_S:
+				ret = setup_netjet_s(card);
 				break;
 #endif
 #if CARD_HFCS
@@ -1276,6 +1137,11 @@
 			ret = setup_w6692(card);
 			break;
 #endif
+#if CARD_NETJET_U
+			case ISDN_CTYPE_NETJET_U:
+				ret = setup_netjet_u(card);
+				break;
+#endif
 		default:
 			printk(KERN_WARNING
 				"HiSax: Support for %s Card not selected\n",
@@ -1305,7 +1171,6 @@
 	cs->tx_skb = NULL;
 	cs->tx_cnt = 0;
 	cs->event = 0;
-	cs->tqueue.next = 0;
 	cs->tqueue.sync = 0;
 	cs->tqueue.data = cs;
 
@@ -1329,8 +1194,8 @@
 	return (1);
 }
 
-HISAX_INITFUNC(void
-HiSax_shiftcards(int idx))
+void 
+HiSax_shiftcards(int idx)
 {
 	int i;
 
@@ -1338,8 +1203,8 @@
 		memcpy(&cards[i], &cards[i + 1], sizeof(cards[i]));
 }
 
-HISAX_INITFUNC(int
-HiSax_inithardware(int *busy_flag))
+int 
+HiSax_inithardware(int *busy_flag)
 {
 	int foundcards = 0;
 	int i = 0;
@@ -1395,6 +1260,9 @@
 	if (cards[cardnr].cs) {
 		ll_stop(cards[cardnr].cs);
 		release_tei(cards[cardnr].cs);
+		
+		CallcFreeChan(cards[cardnr].cs);
+		
 		closecard(cardnr);
 		if (cards[cardnr].cs->irq)
 			free_irq(cards[cardnr].cs->irq, cards[cardnr].cs);
@@ -1420,7 +1288,7 @@
 	printk(KERN_DEBUG "HiSax: HiSax_reportcard address 0x%lX\n",
 		(ulong) & HiSax_reportcard);
 	printk(KERN_DEBUG "HiSax: cs 0x%lX\n", (ulong) cs);
-	printk(KERN_DEBUG "HiSax: HW_Flags %x bc0 flg %x bc1 flg %x\n",
+	printk(KERN_DEBUG "HiSax: HW_Flags %lx bc0 flg %lx bc1 flg %lx\n",
 		cs->HW_Flags, cs->bcs[0].Flag, cs->bcs[1].Flag);
 	printk(KERN_DEBUG "HiSax: bcs 0 mode %d ch%d\n",
 		cs->bcs[0].mode, cs->bcs[0].channel);
@@ -1449,14 +1317,23 @@
 #endif
 }
 
-
-__initfunc(int
-HiSax_init(void))
+static int __init HiSax_init(void)
 {
-	int i;
+	int i,j;
+	int nzproto = 0;
+
+	HiSaxVersion();
+	CallcNew();
+	Isdnl3New();
+	Isdnl2New();
+	TeiNew();
+	Isdnl1New();
 
 #ifdef MODULE
-	int nzproto = 0;
+	if (!type[0]) {
+		/* We 'll register drivers later, but init basic functions*/
+		return 0;
+	}
 #ifdef CONFIG_HISAX_ELSA
 	if (type[0] == ISDN_CTYPE_ELSA_PCMCIA) {
 		/* we have exported  and return in this case */
@@ -1475,47 +1352,52 @@
 		return 0;
 	}
 #endif
+#ifdef CONFIG_HISAX_HFC_SX
+	if (type[0] == ISDN_CTYPE_HFC_SP_PCMCIA) {
+		/* we have to export  and return in this case */
+		return 0;
+	}
+#endif
 #endif
 	nrcards = 0;
-	HiSaxVersion();
 #ifdef MODULE
 	if (id)			/* If id= string used */
 		HiSax_id = id;
-	for (i = 0; i < HISAX_MAX_CARDS; i++) {
-		cards[i].typ = type[i];
+	for (i = j = 0; j < HISAX_MAX_CARDS; i++) {
+		cards[j].typ = type[i];
 		if (protocol[i]) {
-			cards[i].protocol = protocol[i];
+			cards[j].protocol = protocol[i];
 			nzproto++;
 		}
 		switch (type[i]) {
 			case ISDN_CTYPE_16_0:
-				cards[i].para[0] = irq[i];
-				cards[i].para[1] = mem[i];
-				cards[i].para[2] = io[i];
+				cards[j].para[0] = irq[i];
+				cards[j].para[1] = mem[i];
+				cards[j].para[2] = io[i];
 				break;
 
 			case ISDN_CTYPE_8_0:
-				cards[i].para[0] = irq[i];
-				cards[i].para[1] = mem[i];
+				cards[j].para[0] = irq[i];
+				cards[j].para[1] = mem[i];
 				break;
 
 #ifdef IO0_IO1
 			case ISDN_CTYPE_PNP:
 			case ISDN_CTYPE_NICCY:
-				cards[i].para[0] = irq[i];
-				cards[i].para[1] = io0[i];
-				cards[i].para[2] = io1[i];
+				cards[j].para[0] = irq[i];
+				cards[j].para[1] = io0[i];
+				cards[j].para[2] = io1[i];
 				break;
 			case ISDN_CTYPE_COMPAQ_ISA:
-				cards[i].para[0] = irq[i];
-				cards[i].para[1] = io0[i];
-				cards[i].para[2] = io1[i];
-				cards[i].para[3] = io[i];
+				cards[j].para[0] = irq[i];
+				cards[j].para[1] = io0[i];
+				cards[j].para[2] = io1[i];
+				cards[j].para[3] = io[i];
 				break;
 #endif
 			case ISDN_CTYPE_ELSA:
 			case ISDN_CTYPE_HFC_PCI:
-				cards[i].para[0] = io[i];
+				cards[j].para[0] = io[i];
 				break;
 			case ISDN_CTYPE_16_3:
 			case ISDN_CTYPE_TELESPCMCIA:
@@ -1539,30 +1421,46 @@
 			case ISDN_CTYPE_HSTSAPHIR:
 			case ISDN_CTYPE_GAZEL:
 		        case ISDN_CTYPE_HFC_SX:
-				cards[i].para[0] = irq[i];
-				cards[i].para[1] = io[i];
+		        case ISDN_CTYPE_HFC_SP_PCMCIA:
+				cards[j].para[0] = irq[i];
+				cards[j].para[1] = io[i];
 				break;
 			case ISDN_CTYPE_ISURF:
-				cards[i].para[0] = irq[i];
-				cards[i].para[1] = io[i];
-				cards[i].para[2] = mem[i];
+				cards[j].para[0] = irq[i];
+				cards[j].para[1] = io[i];
+				cards[j].para[2] = mem[i];
 				break;
 			case ISDN_CTYPE_ELSA_PCI:
-			case ISDN_CTYPE_NETJET:
+			case ISDN_CTYPE_NETJET_S:
 			case ISDN_CTYPE_AMD7930:
 			case ISDN_CTYPE_TELESPCI:
 			case ISDN_CTYPE_W6692:
+			case ISDN_CTYPE_NETJET_U:
 				break;
 			case ISDN_CTYPE_BKM_A4T:
-	  		   	break;
+	  			break;
 			case ISDN_CTYPE_SCT_QUADRO:
-	          	cards[i].para[0] = irq[i];
+				if (irq[i]) {
+					cards[j].para[0] = irq[i];
+				} else {
+				        /* QUADRO is a 4 BRI card */
+					cards[j++].para[0] = 1;
+					cards[j].typ = ISDN_CTYPE_SCT_QUADRO; 
+					cards[j].protocol = protocol[i];
+					cards[j++].para[0] = 2;
+					cards[j].typ = ISDN_CTYPE_SCT_QUADRO; 
+					cards[j].protocol = protocol[i];
+					cards[j++].para[0] = 3;
+					cards[j].typ = ISDN_CTYPE_SCT_QUADRO; 
+					cards[j].protocol = protocol[i];
+					cards[j].para[0] = 4;
+				}
 				break;
 		}
+		j++;
 	}
 	if (!nzproto) {
 		printk(KERN_WARNING "HiSax: Warning - no protocol specified\n");
-		printk(KERN_WARNING "HiSax: Note! module load syntax has changed.\n");
 		printk(KERN_WARNING "HiSax: using protocol %s\n", DEFAULT_PROTO_NAME);
 	}
 #endif
@@ -1576,15 +1474,8 @@
 	printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
 	       nrcards, (nrcards > 1) ? "s" : "");
 
-	CallcNew();
-	Isdnl3New();
-	Isdnl2New();
-	TeiNew();
-	Isdnl1New();
 	if (HiSax_inithardware(NULL)) {
 		/* Install only, if at least one card found */
-#ifdef MODULE
-#endif /* MODULE */
 		return (0);
 	} else {
 		Isdnl1Free();
@@ -1596,9 +1487,7 @@
 	}
 }
 
-#ifdef MODULE
-void
-cleanup_module(void)
+static void  HiSax_exit(void)
 {
 	int cardnr = nrcards -1;
 	long flags;
@@ -1615,17 +1504,55 @@
 	restore_flags(flags);
 	printk(KERN_INFO "HiSax module removed\n");
 }
-#endif
 
 #ifdef CONFIG_HISAX_ELSA
 int elsa_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
 {
 #ifdef MODULE
 	int i;
+
+	nrcards = 0;
+	/* Initialize all structs, even though we only accept
+	   two pcmcia cards
+	   */
+	for (i = 0; i < HISAX_MAX_CARDS; i++) {
+		cards[i].para[0] = irq[i];
+		cards[i].para[1] = io[i];
+		cards[i].typ = type[i];
+		if (protocol[i]) {
+			cards[i].protocol = protocol[i];
+		}
+	}
+	cards[0].para[0] = pcm_irq;
+	cards[0].para[1] = (int)pcm_iob;
+	cards[0].protocol = prot;
+	cards[0].typ = ISDN_CTYPE_ELSA_PCMCIA;
+
+	if (!HiSax_id)
+		HiSax_id = HiSaxID;
+	if (!HiSaxID[0])
+		strcpy(HiSaxID, "HiSax");
+	for (i = 0; i < HISAX_MAX_CARDS; i++)
+		if (cards[i].typ > 0)
+			nrcards++;
+	printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
+	       nrcards, (nrcards > 1) ? "s" : "");
+
+	HiSax_inithardware(busy_flag);
+	printk(KERN_NOTICE "HiSax: module installed\n");
+#endif
+	return (0);
+}
+#endif
+
+#ifdef CONFIG_HISAX_HFC_SX
+int hfc_init_pcmcia(void *pcm_iob, int pcm_irq, int *busy_flag, int prot)
+{
+#ifdef MODULE
+	int i;
 	int nzproto = 0;
 
 	nrcards = 0;
-	HiSaxVersion();
 	/* Initialize all structs, even though we only accept
 	   two pcmcia cards
 	   */
@@ -1641,7 +1568,7 @@
 	cards[0].para[0] = pcm_irq;
 	cards[0].para[1] = (int)pcm_iob;
 	cards[0].protocol = prot;
-	cards[0].typ = 10;
+	cards[0].typ = ISDN_CTYPE_HFC_SP_PCMCIA;
 	nzproto = 1;
 
 	if (!HiSax_id)
@@ -1654,11 +1581,6 @@
 	printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
 	       nrcards, (nrcards > 1) ? "s" : "");
 
-	Isdnl1New();
-	CallcNew();
-	Isdnl3New();
-	Isdnl2New();
-	TeiNew();
 	HiSax_inithardware(busy_flag);
 	printk(KERN_NOTICE "HiSax: module installed\n");
 #endif
@@ -1674,7 +1596,6 @@
 	int nzproto = 0;
 
 	nrcards = 0;
-	HiSaxVersion();
 	/* Initialize all structs, even though we only accept
 	   two pcmcia cards
 	   */
@@ -1703,11 +1624,6 @@
 	printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
 	       nrcards, (nrcards > 1) ? "s" : "");
 
-	CallcNew();
-	Isdnl3New();
-	Isdnl2New();
-	Isdnl1New();
-	TeiNew();
 	HiSax_inithardware(busy_flag);
 	printk(KERN_NOTICE "HiSax: module installed\n");
 #endif
@@ -1723,7 +1639,6 @@
 	int nzproto = 0;
 
 	nrcards = 0;
-	HiSaxVersion();
 	/* Initialize all structs, even though we only accept
 	   two pcmcia cards
 	   */
@@ -1752,14 +1667,31 @@
 	printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
 	       nrcards, (nrcards > 1) ? "s" : "");
 
-	Isdnl1New();
-	CallcNew();
-	Isdnl3New();
-	Isdnl2New();
-	TeiNew();
 	HiSax_inithardware(busy_flag);
 	printk(KERN_NOTICE "HiSax: module installed\n");
 #endif
 	return (0);
 }
 #endif
+
+int  hisax_init_pcmcia(void *pcm_iob, int *busy_flag, struct IsdnCard *card)
+{
+	u_char ids[16];
+	int ret = -1;
+
+	cards[nrcards] = *card;
+	if (nrcards)
+		sprintf(ids, "HiSax%d", nrcards);
+	else
+		sprintf(ids, "HiSax");
+	if (!checkcard(nrcards, ids, busy_flag)) {
+		return(-1);
+	}
+	ret = nrcards;
+	nrcards++;
+	return (ret);
+}
+
+
+module_init(HiSax_init);
+module_exit(HiSax_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/diva.c linux.19p18/drivers/isdn/hisax/diva.c
--- linux.vanilla/drivers/isdn/hisax/diva.c	Fri Apr 21 12:46:09 2000
+++ linux.19p18/drivers/isdn/hisax/diva.c	Tue Feb 13 18:50:48 2001
@@ -1,5 +1,5 @@
-/* $Id: diva.c,v 1.18 1999/12/19 13:09:41 keil Exp $
-
+/* $Id: diva.c,v 1.25.6.3 2001/02/13 10:33:58 kai Exp $
+ *
  * diva.c     low level stuff for Eicon.Diehl Diva Family ISDN cards
  *
  * Author     Karsten Keil (keil@isdn4linux.de)
@@ -10,70 +10,10 @@
  *
  * Thanks to Eicon Technology for documents and informations
  *
- *
- * $Log: diva.c,v $
- * Revision 1.18  1999/12/19 13:09:41  keil
- * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
- * signal proof delays
- *
- * Revision 1.17  1999/09/04 06:20:06  keil
- * Changes from kernel set_current_state()
- *
- * Revision 1.16  1999/08/11 21:01:25  keil
- * new PCI codefix
- *
- * Revision 1.15  1999/08/10 16:01:49  calle
- * struct pci_dev changed in 2.3.13. Made the necessary changes.
- *
- * Revision 1.14  1999/08/07 17:35:08  keil
- * approval for Eicon Technology Diva 2.01 PCI
- *
- * Revision 1.13  1999/07/21 14:46:07  keil
- * changes from EICON certification
- *
- * Revision 1.12  1999/07/12 21:05:04  keil
- * fix race in IRQ handling
- * added watchdog for lost IRQs
- *
- * Revision 1.11  1999/07/01 08:11:29  keil
- * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
- *
- * Revision 1.10  1998/11/15 23:54:31  keil
- * changes from 2.0
- *
- * Revision 1.9  1998/06/27 22:52:03  keil
- * support for Diva 2.01
- *
- * Revision 1.8  1998/05/25 12:57:46  keil
- * HiSax golden code from certification, Don't use !!!
- * No leased lines, no X75, but many changes.
- *
- * Revision 1.7  1998/04/15 16:42:36  keil
- * new init code
- * new PCI init (2.1.94)
- *
- * Revision 1.6  1998/03/07 22:56:57  tsbogend
- * made HiSax working on Linux/Alpha
- *
- * Revision 1.5  1998/02/02 13:29:38  keil
- * fast io
- *
- * Revision 1.4  1997/11/08 21:35:44  keil
- * new l1 init
- *
- * Revision 1.3  1997/11/06 17:13:33  keil
- * New 2.1 init code
- *
- * Revision 1.2  1997/10/29 18:55:55  keil
- * changes for 2.1.60 (irq2dev_map)
- *
- * Revision 1.1  1997/09/18 17:11:20  keil
- * first version
- *
- *
  */
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include <linux/config.h>
 #include "hisax.h"
 #include "isac.h"
@@ -81,10 +21,11 @@
 #include "ipac.h"
 #include "isdnl1.h"
 #include <linux/pci.h>
+#include <linux/isdn_compat.h>
 
 extern const char *CardType[];
 
-const char *Diva_revision = "$Revision: 1.18 $";
+const char *Diva_revision = "$Revision: 1.25.6.3 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -107,14 +48,6 @@
 #define DIVA_IPAC_ISA	3
 #define DIVA_IPAC_PCI	4
 
-/* PCI stuff */
-#define PCI_VENDOR_EICON_DIEHL	0x1133
-#define PCI_DIVA20PRO_ID	0xe001
-#define PCI_DIVA20_ID		0xe002
-#define PCI_DIVA20PRO_U_ID	0xe003
-#define PCI_DIVA20_U_ID		0xe004
-#define PCI_DIVA_201		0xe005
-
 /* CTRL (Read) */
 #define DIVA_IRQ_STAT	0x01
 #define DIVA_EEPROM_SDA	0x02
@@ -131,10 +64,16 @@
 
 /* Siemens PITA */
 #define PITA_MISC_REG		0x1c
+#ifdef __BIG_ENDIAN
+#define PITA_PARA_SOFTRESET	0x00000001
+#define PITA_PARA_MPX_MODE	0x00000004
+#define PITA_INT0_ENABLE	0x00000200
+#else
 #define PITA_PARA_SOFTRESET	0x01000000
 #define PITA_PARA_MPX_MODE	0x04000000
 #define PITA_INT0_ENABLE	0x00020000
-#define PITA_INT0_STATUS	0x00000002
+#endif
+#define PITA_INT0_STATUS	0x02
 
 static inline u_char
 readreg(unsigned int ale, unsigned int adr, u_char off)
@@ -183,7 +122,7 @@
 static inline u_char
 memreadreg(unsigned long adr, u_char off)
 {
-	return(0xff & *((unsigned int *)
+	return(*((unsigned char *)
 		(((unsigned int *)adr) + off)));
 }
 
@@ -754,30 +693,30 @@
 	sti();
 	if (cs->subtyp == DIVA_IPAC_ISA) {
 		writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x20);
-		current->state = TASK_UNINTERRUPTIBLE;
+		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout((10*HZ)/1000);
 		writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x00);
-		current->state = TASK_UNINTERRUPTIBLE;
+		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout((10*HZ)/1000);
 		writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xc0);
 	} else if (cs->subtyp == DIVA_IPAC_PCI) {
 		unsigned int *ireg = (unsigned int *)(cs->hw.diva.pci_cfg +
 					PITA_MISC_REG);
 		*ireg = PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE;
-		current->state = TASK_UNINTERRUPTIBLE;
+		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout((10*HZ)/1000);
 		*ireg = PITA_PARA_MPX_MODE;
-		current->state = TASK_UNINTERRUPTIBLE;
+		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout((10*HZ)/1000);
 		memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xc0);
 	} else { /* DIVA 2.0 */
 		cs->hw.diva.ctrl_reg = 0;        /* Reset On */
 		byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
-		current->state = TASK_UNINTERRUPTIBLE;
+		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout((10*HZ)/1000);
 		cs->hw.diva.ctrl_reg |= DIVA_RESET;  /* Reset Off */
 		byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
-		current->state = TASK_UNINTERRUPTIBLE;
+		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout((10*HZ)/1000);
 		if (cs->subtyp == DIVA_ISA)
 			cs->hw.diva.ctrl_reg |= DIVA_ISA_LED_A;
@@ -882,12 +821,12 @@
 	return(0);
 }
 
-static 	struct pci_dev *dev_diva __initdata = NULL;
-static 	struct pci_dev *dev_diva_u __initdata = NULL;
-static 	struct pci_dev *dev_diva201 __initdata = NULL;
+static struct pci_dev *dev_diva __initdata = NULL;
+static struct pci_dev *dev_diva_u __initdata = NULL;
+static struct pci_dev *dev_diva201 __initdata = NULL;
 
-__initfunc(int
-setup_diva(struct IsdnCard *card))
+int __init
+setup_diva(struct IsdnCard *card)
 {
 	int bytecnt;
 	u_char val;
@@ -931,28 +870,30 @@
 		}
 
 		cs->subtyp = 0;
-		if ((dev_diva = pci_find_device(PCI_VENDOR_EICON_DIEHL,
-			PCI_DIVA20_ID, dev_diva))) {
+		if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON,
+			PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) {
+			if (pci_enable_device(dev_diva))
+				return(0);
 			cs->subtyp = DIVA_PCI;
 			cs->irq = dev_diva->irq;
-			cs->hw.diva.cfg_reg = dev_diva->base_address[ 2]
-				& PCI_BASE_ADDRESS_IO_MASK;
-		} else if ((dev_diva_u = pci_find_device(PCI_VENDOR_EICON_DIEHL,
-			PCI_DIVA20_U_ID, dev_diva_u))) {
+			cs->hw.diva.cfg_reg = dev_diva->base_address[ 2] & PCI_BASE_ADDRESS_IO_MASK;
+		} else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON,
+			PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) {
+			if (pci_enable_device(dev_diva_u))
+				return(0);
 			cs->subtyp = DIVA_PCI;
 			cs->irq = dev_diva_u->irq;
-			cs->hw.diva.cfg_reg = dev_diva_u->base_address[ 2]
-				& PCI_BASE_ADDRESS_IO_MASK;
-		} else if ((dev_diva201 = pci_find_device(PCI_VENDOR_EICON_DIEHL,
-			PCI_DIVA_201, dev_diva201))) {
+			cs->hw.diva.cfg_reg = dev_diva_u->base_address[ 2] & PCI_BASE_ADDRESS_IO_MASK;
+		} else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON,
+			PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) {
+			if (pci_enable_device(dev_diva201))
+				return(0);
 			cs->subtyp = DIVA_IPAC_PCI;
 			cs->irq = dev_diva201->irq;
 			cs->hw.diva.pci_cfg =
-				(ulong) ioremap((dev_diva201->base_address[ 0]
-					& PCI_BASE_ADDRESS_IO_MASK), 4096);
+				(ulong) ioremap(dev_diva201->base_address[ 0] & PCI_BASE_ADDRESS_MEM_MASK, 4096);
 			cs->hw.diva.cfg_reg =
-				(ulong) ioremap((dev_diva201->base_address[ 1]
-					& PCI_BASE_ADDRESS_IO_MASK), 4096);
+				(ulong) ioremap(dev_diva201->base_address[ 1] & PCI_BASE_ADDRESS_MEM_MASK, 4096);
 		} else {
 			printk(KERN_WARNING "Diva: No PCI card found\n");
 			return(0);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/elsa.c linux.19p18/drivers/isdn/hisax/elsa.c
--- linux.vanilla/drivers/isdn/hisax/elsa.c	Fri Apr 21 12:46:09 2000
+++ linux.19p18/drivers/isdn/hisax/elsa.c	Tue Feb 13 18:50:48 2001
@@ -1,5 +1,5 @@
-/* $Id: elsa.c,v 2.20 1999/12/19 13:09:42 keil Exp $
-
+/* $Id: elsa.c,v 2.26.6.2 2001/02/13 10:33:58 kai Exp $
+ *
  * elsa.c     low level stuff for Elsa isdn cards
  *
  * Author     Karsten Keil (keil@isdn4linux.de)
@@ -13,83 +13,10 @@
  *              Klaus Lichtenwalder (Klaus.Lichtenwalder@WebForum.DE)
  *              for ELSA PCMCIA support
  *
- * $Log: elsa.c,v $
- * Revision 2.20  1999/12/19 13:09:42  keil
- * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
- * signal proof delays
- *
- * Revision 2.19  1999/09/04 06:20:06  keil
- * Changes from kernel set_current_state()
- *
- * Revision 2.18  1999/08/25 16:50:54  keil
- * Fix bugs which cause 2.3.14 hangs (waitqueue init)
- *
- * Revision 2.17  1999/08/11 20:57:40  keil
- * bugfix IPAC version 1.1
- * new PCI codefix
- *
- * Revision 2.16  1999/08/10 16:01:51  calle
- * struct pci_dev changed in 2.3.13. Made the necessary changes.
- *
- * Revision 2.15  1999/08/09 19:25:21  keil
- * Support (alpha version) for the '98 model of ELSA Microlink ISDN/MC
- * by Christer Weinigel, Cendio Systems AB <wingel@cendio.se>
- * Add support for IPAC 1.2
- *
- * Revision 2.14  1999/07/12 21:05:07  keil
- * fix race in IRQ handling
- * added watchdog for lost IRQs
- *
- * Revision 2.13  1999/07/01 08:11:31  keil
- * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
- *
- * Revision 2.12  1998/11/15 23:54:35  keil
- * changes from 2.0
- *
- * Revision 2.11  1998/08/20 13:50:34  keil
- * More support for hybrid modem (not working yet)
- *
- * Revision 2.10  1998/08/13 23:36:22  keil
- * HiSax 3.1 - don't work stable with current LinkLevel
- *
- * Revision 2.9  1998/05/25 12:57:48  keil
- * HiSax golden code from certification, Don't use !!!
- * No leased lines, no X75, but many changes.
- *
- * Revision 2.8  1998/04/15 16:41:42  keil
- * QS3000 PCI support
- * new init code
- * new PCI init (2.1.94)
- *
- * Revision 2.7  1998/03/07 22:56:58  tsbogend
- * made HiSax working on Linux/Alpha
- *
- * Revision 2.6  1998/02/02 13:29:40  keil
- * fast io
- *
- * Revision 2.5  1998/01/31 21:41:45  keil
- * changes for newer 2.1 kernels
- *
- * Revision 2.4  1997/11/08 21:35:46  keil
- * new l1 init
- *
- * Revision 2.3  1997/11/06 17:15:09  keil
- * New 2.1 init; PCMCIA wrapper changes
- *
- * Revision 2.2  1997/10/29 18:57:09  keil
- * changes for 2.1.60, arcofi support
- *
- * Revision 2.1  1997/07/27 21:47:08  keil
- * new interface structures
- *
- * Revision 2.0  1997/06/26 11:02:40  keil
- * New Layer and card interface
- *
- * old changes removed KKe
- *
  */
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include <linux/config.h>
 #include "hisax.h"
 #include "arcofi.h"
@@ -98,15 +25,16 @@
 #include "hscx.h"
 #include "isdnl1.h"
 #include <linux/pci.h>
+#include <linux/isdn_compat.h>
 #include <linux/serial.h>
 #include <linux/serial_reg.h>
 
 extern const char *CardType[];
 
-const char *Elsa_revision = "$Revision: 2.20 $";
+const char *Elsa_revision = "$Revision: 2.26.6.2 $";
 const char *Elsa_Types[] =
 {"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro",
- "PCMCIA", "QS 1000", "QS 3000", "QS 1000 PCI", "QS 3000 PCI", 
+ "PCMCIA", "QS 1000", "QS 3000", "Microlink PCI", "QS 3000 PCI", 
  "PCMCIA-IPAC" };
 
 const char *ITACVer[] =
@@ -140,9 +68,6 @@
 #define ELSA_PCMCIA_IPAC 11
 
 /* PCI stuff */
-#define PCI_VENDOR_ELSA	0x1048
-#define PCI_QS1000_ID	0x1000
-#define PCI_QS3000_ID	0x3000
 #define ELSA_PCI_IRQ_MASK	0x04
 
 /* ITAC Registeradressen (only Microlink PC) */
@@ -582,10 +507,10 @@
 		save_flags(flags);
 		sti();
 		writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x20);
-		current->state = TASK_UNINTERRUPTIBLE;
+		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
 		writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x00);
-		current->state = TASK_UNINTERRUPTIBLE;
+		set_current_state(TASK_UNINTERRUPTIBLE);
 		writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xc0);
 		schedule_timeout((10*HZ)/1000); /* Timeout 10ms */
 		restore_flags(flags);
@@ -789,7 +714,7 @@
 				cs->hw.elsa.status |= ELSA_TIMER_AKTIV;
 				byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
 				byteout(cs->hw.elsa.timer, 0);
-				current->state = TASK_UNINTERRUPTIBLE;
+				set_current_state(TASK_UNINTERRUPTIBLE);
 				schedule_timeout((110*HZ)/1000);
 				restore_flags(flags);
 				cs->hw.elsa.ctrl_reg &= ~ELSA_ENA_TIMER_INT;
@@ -797,7 +722,8 @@
 				cs->hw.elsa.status &= ~ELSA_TIMER_AKTIV;
 				printk(KERN_INFO "Elsa: %d timer tics in 110 msek\n",
 				       cs->hw.elsa.counter);
-				if (abs(cs->hw.elsa.counter - 13) < 3) {
+				if ((cs->hw.elsa.counter > 10) &&
+					(cs->hw.elsa.counter < 16)) {
 					printk(KERN_INFO "Elsa: timer and irq OK\n");
 					ret = 0;
 				} else {
@@ -932,10 +858,10 @@
 	return (CARD_portlist[i]);
 }
 
-static 	struct pci_dev *dev_qs1000 __initdata = NULL;
-static 	struct pci_dev *dev_qs3000 __initdata = NULL;
+static 	struct pci_dev *dev_qs1000  = NULL;
+static 	struct pci_dev *dev_qs3000  = NULL;
 
-int
+int 
 setup_elsa(struct IsdnCard *card)
 {
 	long flags;
@@ -1056,22 +982,22 @@
 			return(0);
 		}
 		cs->subtyp = 0;
-		if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ELSA, PCI_QS1000_ID,
-			 dev_qs1000))) {
-				cs->subtyp = ELSA_QS1000PCI;
+		if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA,
+			PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) {
+			if (pci_enable_device(dev_qs1000))
+				return(0);
+			cs->subtyp = ELSA_QS1000PCI;
 			cs->irq = dev_qs1000->irq;
-			cs->hw.elsa.cfg = dev_qs1000->base_address[ 1] & 
-				PCI_BASE_ADDRESS_IO_MASK;
-			cs->hw.elsa.base = dev_qs1000->base_address[ 3] & 
-				PCI_BASE_ADDRESS_IO_MASK;
-		} else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ELSA,
-			PCI_QS3000_ID, dev_qs3000))) {
+			cs->hw.elsa.cfg = dev_qs1000->base_address[ 1] & PCI_BASE_ADDRESS_IO_MASK;
+			cs->hw.elsa.base = dev_qs1000->base_address[ 3] & PCI_BASE_ADDRESS_IO_MASK;
+		} else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ID_ELSA,
+			PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) {
+			if (pci_enable_device(dev_qs3000))
+				return(0);
 			cs->subtyp = ELSA_QS3000PCI;
 			cs->irq = dev_qs3000->irq;
-			cs->hw.elsa.cfg = dev_qs3000->base_address[ 1] & 
-				PCI_BASE_ADDRESS_IO_MASK;
-			cs->hw.elsa.base = dev_qs3000->base_address[ 3] & 
-				PCI_BASE_ADDRESS_IO_MASK;
+			cs->hw.elsa.cfg = dev_qs3000->base_address[ 1] & PCI_BASE_ADDRESS_IO_MASK;
+			cs->hw.elsa.base = dev_qs3000->base_address[ 3] & PCI_BASE_ADDRESS_IO_MASK;
 		} else {
 			printk(KERN_WARNING "Elsa: No PCI card found\n");
 			return(0);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/elsa_ser.c linux.19p18/drivers/isdn/hisax/elsa_ser.c
--- linux.vanilla/drivers/isdn/hisax/elsa_ser.c	Fri Apr 21 12:46:09 2000
+++ linux.19p18/drivers/isdn/hisax/elsa_ser.c	Sat Dec 30 19:33:52 2000
@@ -1,3 +1,10 @@
+/* $Id: elsa_ser.c,v 2.10 2000/11/19 17:02:47 kai Exp $
+ *
+ * stuff for the serial modem on ELSA cards
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
 #include <linux/config.h>
 #include <linux/serial.h>
 #include <linux/serial_reg.h>
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/fsm.c linux.19p18/drivers/isdn/hisax/fsm.c
--- linux.vanilla/drivers/isdn/hisax/fsm.c	Fri Apr 21 12:46:09 2000
+++ linux.19p18/drivers/isdn/hisax/fsm.c	Mon Feb 12 15:09:50 2001
@@ -1,58 +1,22 @@
-/* $Id: fsm.c,v 1.11 1999/12/23 15:09:32 keil Exp $
-
+/* $Id: fsm.c,v 1.14 2000/11/24 17:05:37 kai Exp $
+ *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
  *
  * Thanks to    Jan den Ouden
  *              Fritz Elfert
  *
- * $Log: fsm.c,v $
- * Revision 1.11  1999/12/23 15:09:32  keil
- * change email
- *
- * Revision 1.10  1998/11/15 23:54:39  keil
- * changes from 2.0
- *
- * Revision 1.9  1998/03/26 07:10:02  paul
- * The jumpmatrix table in struct Fsm was an array of "int". This is not
- * large enough for pointers to functions on Linux/Alpha (instant crash
- * on "insmod hisax). Now there is a typedef for the pointer to function.
- * This also prevents warnings about "incompatible pointer types".
- *
- * Revision 1.8  1998/03/07 22:56:59  tsbogend
- * made HiSax working on Linux/Alpha
- *
- * Revision 1.7  1997/11/06 17:09:13  keil
- * New 2.1 init code
- *
- * Revision 1.6  1997/07/27 21:42:25  keil
- * proof Fsm routines
- *
- * Revision 1.5  1997/06/26 11:10:05  keil
- * Restart timer function added
- *
- * Revision 1.4  1997/04/06 22:56:42  keil
- * Some cosmetic changes
- *
- * Revision 1.3  1997/02/16 01:04:08  fritz
- * Bugfix: Changed timer handling caused hang with 2.1.X
- *
- * Revision 1.2  1997/01/09 20:57:27  keil
- * cleanup & FSM_TIMER_DEBUG
- *
- * Revision 1.1  1996/10/13 20:04:52  keil
- * Initial revision
- *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 
 #define FSM_TIMER_DEBUG 0
 
-HISAX_INITFUNC(void
-FsmNew(struct Fsm *fsm,
-       struct FsmNode *fnlist, int fncount))
+void __init
+FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount)
 {
 	int i;
 
@@ -156,7 +120,7 @@
 			(long) ft, millisec, where);
 #endif
 
-	if (ft->tl.next || ft->tl.prev) {
+	if (timer_pending(&ft->tl)) {
 		printk(KERN_WARNING "FsmAddTimer: timer already active!\n");
 		ft->fi->printdebug(ft->fi, "FsmAddTimer already active!");
 		return -1;
@@ -180,7 +144,7 @@
 			(long) ft, millisec, where);
 #endif
 
-	if (ft->tl.next || ft->tl.prev)
+	if (timer_pending(&ft->tl))
 		del_timer(&ft->tl);
 	init_timer(&ft->tl);
 	ft->event = event;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/gazel.c linux.19p18/drivers/isdn/hisax/gazel.c
--- linux.vanilla/drivers/isdn/hisax/gazel.c	Fri Apr 21 12:46:09 2000
+++ linux.19p18/drivers/isdn/hisax/gazel.c	Tue Feb 13 18:50:48 2001
@@ -1,35 +1,15 @@
-/* $Id: gazel.c,v 2.6 1999/08/22 20:27:03 calle Exp $
-
+/* $Id: gazel.c,v 2.11.6.3 2001/02/13 10:33:58 kai Exp $
+ *
  * gazel.c     low level stuff for Gazel isdn cards
  *
  * Author       BeWan Systems
  *              based on source code from Karsten Keil
  *
- * $Log: gazel.c,v $
- * Revision 2.6  1999/08/22 20:27:03  calle
- * backported changes from kernel 2.3.14:
- * - several #include "config.h" gone, others come.
- * - "struct device" changed to "struct net_device" in 2.3.14, added a
- *   define in isdn_compat.h for older kernel versions.
- *
- * Revision 2.5  1999/08/11 21:01:26  keil
- * new PCI codefix
- *
- * Revision 2.4  1999/08/10 16:01:54  calle
- * struct pci_dev changed in 2.3.13. Made the necessary changes.
- *
- * Revision 2.3  1999/07/12 21:05:09  keil
- * fix race in IRQ handling
- * added watchdog for lost IRQs
- *
- * Revision 2.1  1999/07/08 21:26:17  keil
- * new card
- *
- * Revision 1.0  1999/28/06
- * Initial revision
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 #include <linux/config.h>
+#include <linux/init.h>
 #define __NO_VERSION__
 #include "hisax.h"
 #include "isac.h"
@@ -37,21 +17,16 @@
 #include "isdnl1.h"
 #include "ipac.h"
 #include <linux/pci.h>
+#include <linux/isdn_compat.h>
 
 extern const char *CardType[];
-const char *gazel_revision = "$Revision: 2.6 $";
+const char *gazel_revision = "$Revision: 2.11.6.3 $";
 
 #define R647      1
 #define R685      2
 #define R753      3
 #define R742      4
 
-/* Gazel R685 stuff */
-#define GAZEL_MANUFACTURER     0x10b5
-#define GAZEL_R685             0x1030
-#define GAZEL_R753             0x1152
-#define GAZEL_DJINN_ITOO       0x1151
-
 #define PLX_CNTRL    0x50	/* registre de controle PLX */
 #define RESET_GAZEL  0x4
 #define RESET_9050   0x40000000
@@ -586,24 +561,25 @@
 		printk(KERN_WARNING "Gazel: No PCI bus present\n");
 		return 1;
 	}
-	seekcard = GAZEL_R685;
+	seekcard = PCI_DEVICE_ID_PLX_R685;
 	for (nbseek = 0; nbseek < 3; nbseek++) {
-		if ((dev_tel = pci_find_device(GAZEL_MANUFACTURER, seekcard, dev_tel))) {
-
+		if ((dev_tel = pci_find_device(PCI_VENDOR_ID_PLX, seekcard, dev_tel))) {
+			if (pci_enable_device(dev_tel))
+				return 1;
 			pci_irq = dev_tel->irq;
-			pci_ioaddr0 = dev_tel->base_address[ 1];
-			pci_ioaddr1 = dev_tel->base_address[ 2];
+			pci_ioaddr0 = dev_tel->base_address[ 1] & PCI_BASE_ADDRESS_IO_MASK;
+			pci_ioaddr1 = dev_tel->base_address[ 2] & PCI_BASE_ADDRESS_IO_MASK;
 			found = 1;
 		}
 		if (found)
 			break;
 		else {
 			switch (seekcard) {
-				case GAZEL_R685:
-					seekcard = GAZEL_R753;
+				case PCI_DEVICE_ID_PLX_R685:
+					seekcard = PCI_DEVICE_ID_PLX_R753;
 					break;
-				case GAZEL_R753:
-					seekcard = GAZEL_DJINN_ITOO;
+				case PCI_DEVICE_ID_PLX_R753:
+					seekcard = PCI_DEVICE_ID_PLX_DJINN_ITOO;
 					break;
 			}
 		}
@@ -632,7 +608,7 @@
 	cs->irq_flags |= SA_SHIRQ;
 
 	switch (seekcard) {
-		case GAZEL_R685:
+		case PCI_DEVICE_ID_PLX_R685:
 			printk(KERN_INFO "Gazel: Card PCI R685 found\n");
 			cs->subtyp = R685;
 			cs->dc.isac.adf2 = 0x87;
@@ -643,8 +619,8 @@
 			       "Gazel: hscx A:0x%X  hscx B:0x%X\n",
 			     cs->hw.gazel.hscx[0], cs->hw.gazel.hscx[1]);
 			break;
-		case GAZEL_R753:
-		case GAZEL_DJINN_ITOO:
+		case PCI_DEVICE_ID_PLX_R753:
+		case PCI_DEVICE_ID_PLX_DJINN_ITOO:
 			printk(KERN_INFO "Gazel: Card PCI R753 found\n");
 			cs->subtyp = R753;
 			test_and_set_bit(HW_IPAC, &cs->HW_Flags);
@@ -657,8 +633,8 @@
 	return (0);
 }
 
-__initfunc(int
-	   setup_gazel(struct IsdnCard *card))
+int __init
+setup_gazel(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/hfc_2bds0.c linux.19p18/drivers/isdn/hisax/hfc_2bds0.c
--- linux.vanilla/drivers/isdn/hisax/hfc_2bds0.c	Fri Apr 21 12:46:09 2000
+++ linux.19p18/drivers/isdn/hisax/hfc_2bds0.c	Mon Feb 12 15:09:50 2001
@@ -1,46 +1,14 @@
-/* $Id: hfc_2bds0.c,v 1.11 1999/12/23 15:09:32 keil Exp $
+/* $Id: hfc_2bds0.c,v 1.15 2000/11/24 17:05:37 kai Exp $
  *
  *  specific routines for CCD's HFC 2BDS0
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *
- *
- * $Log: hfc_2bds0.c,v $
- * Revision 1.11  1999/12/23 15:09:32  keil
- * change email
- *
- * Revision 1.10  1999/10/14 20:25:28  keil
- * add a statistic for error monitoring
- *
- * Revision 1.9  1999/07/01 08:11:35  keil
- * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
- *
- * Revision 1.8  1998/11/15 23:54:40  keil
- * changes from 2.0
- *
- * Revision 1.7  1998/09/30 22:24:45  keil
- * Fix missing line in setstack*
- *
- * Revision 1.6  1998/08/13 23:36:26  keil
- * HiSax 3.1 - don't work stable with current LinkLevel
- *
- * Revision 1.5  1998/06/27 22:52:58  keil
- * make 16.3c working with 3.0
- *
- * Revision 1.4  1998/05/25 12:57:52  keil
- * HiSax golden code from certification, Don't use !!!
- * No leased lines, no X75, but many changes.
- *
- * Revision 1.3  1998/02/12 23:07:22  keil
- * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
- *
- * Revision 1.2  1998/02/02 13:26:13  keil
- * New
- *
- *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "hfc_2bds0.h"
 #include "isdnl1.h"
@@ -1137,8 +1105,8 @@
 {
 }
 
-__initfunc(unsigned int
-*init_send_hfcd(int cnt))
+unsigned int __init
+*init_send_hfcd(int cnt)
 {
 	int i, *send;
 
@@ -1152,8 +1120,8 @@
 	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;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/hfc_2bds0.h linux.19p18/drivers/isdn/hisax/hfc_2bds0.h
--- linux.vanilla/drivers/isdn/hisax/hfc_2bds0.h	Fri Apr 21 12:46:09 2000
+++ linux.19p18/drivers/isdn/hisax/hfc_2bds0.h	Wed Dec 13 22:07:14 2000
@@ -1,18 +1,10 @@
-/* $Id: hfc_2bds0.h,v 1.3 1999/12/23 15:09:32 keil Exp $
-
+/* $Id: hfc_2bds0.h,v 1.4 2000/06/26 08:59:12 keil Exp $
+ *
  *  specific defines for CCD's HFC 2BDS0
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *
- *
- * $Log: hfc_2bds0.h,v $
- * Revision 1.3  1999/12/23 15:09:32  keil
- * change email
- *
- * Revision 1.2  1998/02/02 13:26:15  keil
- * New
- *
- *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/hfc_2bs0.c linux.19p18/drivers/isdn/hisax/hfc_2bs0.c
--- linux.vanilla/drivers/isdn/hisax/hfc_2bs0.c	Fri Apr 21 12:46:09 2000
+++ linux.19p18/drivers/isdn/hisax/hfc_2bs0.c	Mon Feb 12 15:09:50 2001
@@ -1,53 +1,15 @@
-/* $Id: hfc_2bs0.c,v 1.12 1999/12/19 14:17:12 keil Exp $
-
+/* $Id: hfc_2bs0.c,v 1.17 2000/11/24 17:05:37 kai Exp $
+ *
  *  specific routines for CCD's HFC 2BS0
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *
- *
- * $Log: hfc_2bs0.c,v $
- * Revision 1.12  1999/12/19 14:17:12  keil
- * fix compiler warning
- *
- * Revision 1.11  1999/11/21 12:41:18  werner
- *
- * Implemented full audio support
- *
- * Revision 1.10  1999/10/14 20:25:28  keil
- * add a statistic for error monitoring
- *
- * Revision 1.9  1999/07/01 08:11:36  keil
- * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
- *
- * Revision 1.8  1998/11/15 23:54:43  keil
- * changes from 2.0
- *
- * Revision 1.7  1998/09/30 22:24:46  keil
- * Fix missing line in setstack*
- *
- * Revision 1.6  1998/08/13 23:36:28  keil
- * HiSax 3.1 - don't work stable with current LinkLevel
- *
- * Revision 1.5  1998/05/25 12:57:54  keil
- * HiSax golden code from certification, Don't use !!!
- * No leased lines, no X75, but many changes.
- *
- * Revision 1.4  1998/02/12 23:07:29  keil
- * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
- *
- * Revision 1.3  1997/11/06 17:13:35  keil
- * New 2.1 init code
- *
- * Revision 1.2  1997/10/29 19:04:47  keil
- * changes for 2.1
- *
- * Revision 1.1  1997/09/11 17:31:33  keil
- * Common part for HFC 2BS0 based cards
- *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "hfc_2bs0.h"
 #include "isac.h"
@@ -242,7 +204,7 @@
 		ptr = skb_put(skb, count);
 		idx = 0;
 		cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel);
-		while ((idx < count - 3) && WaitNoBusy(cs)) {
+		while ((idx < count) && WaitNoBusy(cs)) {
 			*ptr++ = cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip);
 			idx++;
 		}
@@ -609,8 +571,8 @@
 	return (0);
 }
 
-__initfunc(void
-init_send(struct BCState *bcs))
+void __init
+init_send(struct BCState *bcs)
 {
 	int i;
 
@@ -623,8 +585,8 @@
 		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]);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/hfc_2bs0.h linux.19p18/drivers/isdn/hisax/hfc_2bs0.h
--- linux.vanilla/drivers/isdn/hisax/hfc_2bs0.h	Fri Apr 21 12:46:09 2000
+++ linux.19p18/drivers/isdn/hisax/hfc_2bs0.h	Wed Dec 13 22:07:49 2000
@@ -1,17 +1,10 @@
-/* $Id: hfc_2bs0.h,v 1.2 1999/12/23 15:09:32 keil Exp $
-
+/* $Id: hfc_2bs0.h,v 1.3 2000/06/26 08:59:13 keil Exp $
+ *
  *  specific defines for CCD's HFC 2BS0
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *
- *
- * $Log: hfc_2bs0.h,v $
- * Revision 1.2  1999/12/23 15:09:32  keil
- * change email
- *
- * Revision 1.1  1997/09/11 17:31:34  keil
- * Common part for HFC 2BS0 based cards
- *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/hfc_pci.c linux.19p18/drivers/isdn/hisax/hfc_pci.c
--- linux.vanilla/drivers/isdn/hisax/hfc_pci.c	Mon Dec 11 22:12:45 2000
+++ linux.19p18/drivers/isdn/hisax/hfc_pci.c	Tue Feb 13 18:50:48 2001
@@ -1,4 +1,4 @@
-/* $Id: hfc_pci.c,v 1.27 2000/02/26 00:35:12 keil Exp $
+/* $Id: hfc_pci.c,v 1.34.6.4 2001/02/13 10:33:58 kai Exp $
 
  * hfc_pci.c     low level driver for CCD´s hfc-pci based cards
  *
@@ -22,114 +22,21 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * $Log: hfc_pci.c,v $
- * Revision 1.27  2000/02/26 00:35:12  keil
- * Fix skb freeing in interrupt context
- *
- * Revision 1.26  2000/02/09 20:22:55  werner
- *
- * Updated PCI-ID table
- *
- * Revision 1.25  1999/12/19 13:09:42  keil
- * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
- * signal proof delays
- *
- * Revision 1.24  1999/11/17 23:59:55  werner
- *
- * removed unneeded data
- *
- * Revision 1.23  1999/11/07 17:01:55  keil
- * fix for 2.3 pci structs
- *
- * Revision 1.22  1999/10/10 20:14:27  werner
- *
- * Correct B2-chan usage in conjuntion with echo mode. First implementation of NT-leased line mode.
- *
- * Revision 1.21  1999/10/02 17:47:49  werner
- *
- * Changed init order, added correction for page alignment with shared mem
- *
- * Revision 1.20  1999/09/07 06:18:55  werner
- *
- * Added io parameter for HFC-PCI based cards. Needed only with multiple cards
- * when initialisation/selection order needs to be set.
- *
- * Revision 1.19  1999/09/04 06:20:06  keil
- * Changes from kernel set_current_state()
- *
- * Revision 1.18  1999/08/29 17:05:44  werner
- * corrected tx_lo line setup. Datasheet is not correct.
- *
- * Revision 1.17  1999/08/28 21:04:27  werner
- * Implemented full audio support (transparent mode)
- *
- * Revision 1.16  1999/08/25 17:01:27  keil
- * Use new LL->HL auxcmd call
- *
- * Revision 1.15  1999/08/22 20:27:05  calle
- * backported changes from kernel 2.3.14:
- * - several #include "config.h" gone, others come.
- * - "struct device" changed to "struct net_device" in 2.3.14, added a
- *   define in isdn_compat.h for older kernel versions.
- *
- * Revision 1.14  1999/08/12 18:59:45  werner
- * Added further manufacturer and device ids to PCI list
- *
- * Revision 1.13  1999/08/11 21:01:28  keil
- * new PCI codefix
- *
- * Revision 1.12  1999/08/10 16:01:58  calle
- * struct pci_dev changed in 2.3.13. Made the necessary changes.
- *
- * Revision 1.11  1999/08/09 19:13:32  werner
- * moved constant pci ids to pci id table
- *
- * Revision 1.10  1999/08/08 10:17:34  werner
- * added new PCI vendor and card ids for Manufacturer 0x1043
- *
- * Revision 1.9  1999/08/07 21:09:10  werner
- * Fixed another memcpy problem in fifo handling.
- * Thanks for debugging aid by Olaf Kordwittenborg.
- *
- * Revision 1.8  1999/07/23 14:25:15  werner
- * Some smaller bug fixes and prepared support for GCI/IOM bus
- *
- * Revision 1.7  1999/07/14 21:24:20  werner
- * fixed memcpy problem when using E-channel feature
- *
- * Revision 1.6  1999/07/13 21:08:08  werner
- * added echo channel logging feature.
- *
- * Revision 1.5  1999/07/12 21:05:10  keil
- * fix race in IRQ handling
- * added watchdog for lost IRQs
- *
- * Revision 1.4  1999/07/04 21:51:39  werner
- * Changes to solve problems with irq sharing and smp machines
- * Thanks to Karsten Keil and Alex Holden for giving aid with
- * testing and debugging
- *
- * Revision 1.3  1999/07/01 09:43:19  keil
- * removed additional schedules in timeouts
- *
- * Revision 1.2  1999/07/01 08:07:51  keil
- * Initial version
- *
- *
- *
  */
 
+#include <linux/init.h>
 #include <linux/config.h>
 #define __NO_VERSION__
 #include "hisax.h"
 #include "hfc_pci.h"
 #include "isdnl1.h"
 #include <linux/pci.h>
+#include <linux/isdn_compat.h>
 #include <linux/interrupt.h>
 
 extern const char *CardType[];
 
-static const char *hfcpci_revision = "$Revision: 1.27 $";
+static const char *hfcpci_revision = "$Revision: 1.34.6.4 $";
 
 /* table entry in the PCI devices list */
 typedef struct {
@@ -139,26 +46,32 @@
 	char *card_name;
 } PCI_ENTRY;
 
-#define NT_T1_COUNT 20		/* number of 3.125ms interrupts for G2 timeout */
+#define NT_T1_COUNT	20	/* number of 3.125ms interrupts for G2 timeout */
+#define CLKDEL_TE	0x0e	/* CLKDEL in TE mode */
+#define CLKDEL_NT	0x6c	/* CLKDEL in NT mode */
 
 static const PCI_ENTRY id_list[] =
 {
-	{0x1397, 0x2BD0, "CCD/Billion/Asuscom", "2BD0"},
-	{0x1397, 0xB000, "Billion", "B000"},
-	{0x1397, 0xB006, "Billion", "B006"},
-	{0x1397, 0xB007, "Billion", "B007"},
-	{0x1397, 0xB008, "Billion", "B008"},
-	{0x1397, 0xB009, "Billion", "B009"},
-	{0x1397, 0xB00A, "Billion", "B00A"},
-	{0x1397, 0xB00B, "Billion", "B00B"},
-	{0x1397, 0xB00C, "Billion", "B00C"},
-	{0x1043, 0x0675, "Asuscom/Askey", "675"},
-	{0x0871, 0xFFA2, "German telekom", "T-Concept"},
-	{0x0871, 0xFFA1, "German telekom", "A1T"},
-	{0x1051, 0x0100, "Motorola MC145575", "MC145575"},
-	{0x1397, 0xB100, "Seyeon", "B100"},
-	{0x15B0, 0x2BD0, "Zoltrix", "2BD0"},
-	{0x114f, 0x71,   "Digi intl.","Digicom"}, 
+	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_2BD0, "CCD/Billion/Asuscom", "2BD0"},
+	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B000, "Billion", "B000"},
+	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B006, "Billion", "B006"},
+	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B007, "Billion", "B007"},
+	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B008, "Billion", "B008"},
+	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B009, "Billion", "B009"},
+	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00A, "Billion", "B00A"},
+	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00B, "Billion", "B00B"},
+	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00C, "Billion", "B00C"},
+	{PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B100, "Seyeon", "B100"},
+	{PCI_VENDOR_ID_ABOCOM, PCI_DEVICE_ID_ABOCOM_2BD1, "Abocom/Magitek", "2BD1"},
+	{PCI_VENDOR_ID_ASUSTEK, PCI_DEVICE_ID_ASUSTEK_0675, "Asuscom/Askey", "675"},
+	{PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_T_CONCEPT, "German telekom", "T-Concept"},
+	{PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_A1T, "German telekom", "A1T"},
+	{PCI_VENDOR_ID_ANIGMA, PCI_DEVICE_ID_ANIGMA_MC145575, "Motorola MC145575", "MC145575"},
+	{PCI_VENDOR_ID_ZOLTRIX, PCI_DEVICE_ID_ZOLTRIX_2BD0, "Zoltrix", "2BD0"},
+	{PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_E,"Digi International", "Digi DataFire Micro V IOM2 (Europe)"},
+	{PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_E,"Digi International", "Digi DataFire Micro V (Europe)"},
+	{PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_A,"Digi International", "Digi DataFire Micro V IOM2 (North America)"},
+	{PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_A,"Digi International", "Digi DataFire Micro V (North America)"},
 	{0, 0, NULL, NULL},
 };
 
@@ -180,7 +93,7 @@
 	restore_flags(flags);
 	Write_hfc(cs, HFCPCI_CIRM, HFCPCI_RESET);	/* Reset On */
 	sti();
-	current->state = TASK_UNINTERRUPTIBLE;
+	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout((30 * HZ) / 1000);	/* Timeout 30ms */
 	Write_hfc(cs, HFCPCI_CIRM, 0);	/* Reset Off */
 #if CONFIG_PCI
@@ -211,10 +124,10 @@
 	pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, PCI_ENA_MEMIO + PCI_ENA_MASTER);	/* enable memory ports + busmaster */
 	Write_hfc(cs, HFCPCI_CIRM, HFCPCI_RESET);	/* Reset On */
 	sti();
-	current->state = TASK_UNINTERRUPTIBLE;
+	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout((30 * HZ) / 1000);	/* Timeout 30ms */
 	Write_hfc(cs, HFCPCI_CIRM, 0);	/* Reset Off */
-	current->state = TASK_UNINTERRUPTIBLE;
+	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout((20 * HZ) / 1000);	/* Timeout 20ms */
 	if (Read_hfc(cs, HFCPCI_STATUS) & 2)
 		printk(KERN_WARNING "HFC-PCI init bit busy\n");
@@ -225,7 +138,7 @@
 	cs->hw.hfcpci.trm = 0 + HFCPCI_BTRANS_THRESMASK;	/* no echo connect , threshold */
 	Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm);
 
-	Write_hfc(cs, HFCPCI_CLKDEL, 0x0e);	/* ST-Bit delay for TE-Mode */
+	Write_hfc(cs, HFCPCI_CLKDEL, CLKDEL_TE); /* ST-Bit delay for TE-Mode */
 	cs->hw.hfcpci.sctrl_e = HFCPCI_AUTO_AWAKE;
 	Write_hfc(cs, HFCPCI_SCTRL_E, cs->hw.hfcpci.sctrl_e);	/* S/T Auto awake */
 	cs->hw.hfcpci.bswapped = 0;	/* no exchange */
@@ -349,6 +262,9 @@
 	    (*(bdata + (zp->z1 - B_SUB_VAL)))) {
 		if (cs->debug & L1_DEB_WARN)
 			debugl1(cs, "hfcpci_empty_fifo: incoming packet invalid length %d or crc", count);
+#ifdef ERROR_STATISTIC
+		bcs->err_inv++;
+#endif
 		bz->za[new_f2].z2 = new_z2;
 		bz->f2 = new_f2;	/* next buffer */
 		skb = NULL;
@@ -415,6 +331,9 @@
 		    (df->data[zp->z1])) {
 			if (cs->debug & L1_DEB_WARN)
 				debugl1(cs, "empty_fifo hfcpci paket inv. len %d or crc %d", rcnt, df->data[zp->z1]);
+#ifdef ERROR_STATISTIC
+			cs->err_rx++;
+#endif
 			df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | (MAX_D_FRAMES + 1);	/* next buffer */
 			df->za[df->f2 & D_FREG_MASK].z2 = (zp->z2 + rcnt) & (D_FIFO_SIZE - 1);
 		} else if ((skb = dev_alloc_skb(rcnt - 3))) {
@@ -601,6 +520,9 @@
 	if (fcnt > (MAX_D_FRAMES - 1)) {
 		if (cs->debug & L1_DEB_ISAC)
 			debugl1(cs, "hfcpci_fill_Dfifo more as 14 frames");
+#ifdef ERROR_STATISTIC
+		cs->err_tx++;
+#endif
 		return;
 	}
 	/* now determine free bytes in FIFO buffer */
@@ -835,6 +757,7 @@
 	    (!(cs->hw.hfcpci.int_m1 & (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC + HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC)))) {
 		save_flags(flags);
 		cli();
+		Write_hfc(cs, HFCPCI_CLKDEL, CLKDEL_NT); /* ST-Bit delay for NT-Mode */
 		Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 0);	/* HFC ST G0 */
 		udelay(10);
 		cs->hw.hfcpci.sctrl |= SCTRL_MODE_NT;
@@ -1650,8 +1573,8 @@
 /********************************/
 /* 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;
@@ -1690,7 +1613,7 @@
 			inithfcpci(cs);
 			save_flags(flags);
 			sti();
-			current->state = TASK_UNINTERRUPTIBLE;
+			set_current_state(TASK_UNINTERRUPTIBLE);
 			schedule_timeout((80 * HZ) / 1000);	/* Timeout 80ms */
 			/* now switch timer interrupt off */
 			cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_TIMER;
@@ -1711,26 +1634,23 @@
 
 #endif				/* CONFIG_PCI */
 
-__initfunc(int
-	   setup_hfcpci(struct IsdnCard *card))
+int __init setup_hfcpci(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
-	unsigned short cmd;
 	char tmp[64];
 	int i;
 	struct pci_dev *tmp_hfcpci = NULL;
 
+#ifdef __BIG_ENDIAN
+#error "not running on big endian machines now"
+#endif
 	strcpy(tmp, hfcpci_revision);
 	printk(KERN_INFO "HiSax: HFC-PCI driver Rev. %s\n", HiSax_getrev(tmp));
-#if CONFIG_PCI
+#ifdef CONFIG_PCI
 	cs->hw.hfcpci.int_s1 = 0;
 	cs->dc.hfcpci.ph_state = 0;
 	cs->hw.hfcpci.fifo = 255;
 	if (cs->typ == ISDN_CTYPE_HFC_PCI) {
-		if (!pci_present()) {
-			printk(KERN_ERR "HFC-PCI: no PCI bus present\n");
-			return (0);
-		}
 		i = 0;
 		while (id_list[i].vendor_id) {
 			tmp_hfcpci = pci_find_device(id_list[i].vendor_id,
@@ -1738,6 +1658,8 @@
 						     dev_hfcpci);
 			i++;
 			if (tmp_hfcpci) {
+				if (pci_enable_device(tmp_hfcpci))
+					continue;
 				if ((card->para[0]) && (card->para[0] != (tmp_hfcpci->base_address[ 0] & PCI_BASE_ADDRESS_IO_MASK)))
 					continue;
 				else
@@ -1761,41 +1683,6 @@
 			printk(KERN_WARNING "HFC-PCI: No PCI card found\n");
 			return (0);
 		}
-#ifdef notdef
-		if (((int) cs->hw.hfcpci.pci_io & (PAGE_SIZE - 1))) {
-			printk(KERN_WARNING "HFC-PCI shared mem address will be corrected\n");
-			pcibios_write_config_word(cs->hw.hfcpci.pci_bus,
-					     cs->hw.hfcpci.pci_device_fn,
-						  PCI_COMMAND,
-						  0x0103);	/* set SERR */
-			pcibios_read_config_word(cs->hw.hfcpci.pci_bus,
-					     cs->hw.hfcpci.pci_device_fn,
-						 PCI_COMMAND,
-						 &cmd);
-			pcibios_write_config_word(cs->hw.hfcpci.pci_bus,
-					     cs->hw.hfcpci.pci_device_fn,
-						  PCI_COMMAND,
-						  cmd & ~2);
-			(int) cs->hw.hfcpci.pci_io &= ~(PAGE_SIZE - 1);
-			pcibios_write_config_dword(cs->hw.hfcpci.pci_bus,
-					     cs->hw.hfcpci.pci_device_fn,
-						   PCI_BASE_ADDRESS_1,
-					     (int) cs->hw.hfcpci.pci_io);
-			pcibios_write_config_word(cs->hw.hfcpci.pci_bus,
-					     cs->hw.hfcpci.pci_device_fn,
-						  PCI_COMMAND,
-						  cmd);
-			pcibios_read_config_dword(cs->hw.hfcpci.pci_bus,
-					     cs->hw.hfcpci.pci_device_fn,
-						  PCI_BASE_ADDRESS_1,
-					 (void *) &cs->hw.hfcpci.pci_io);
-			if (((int) cs->hw.hfcpci.pci_io & (PAGE_SIZE - 1))) {
-				printk(KERN_WARNING "HFC-PCI unable to align address %x\n", (unsigned) cs->hw.hfcpci.pci_io);
-				return (0);
-			}
-			dev_hfcpci->base_address[1] = (int) cs->hw.hfcpci.pci_io;
-		}
-#endif
 		if (!cs->hw.hfcpci.pci_io) {
 			printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n");
 			return (0);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/hfc_pci.h linux.19p18/drivers/isdn/hisax/hfc_pci.h
--- linux.vanilla/drivers/isdn/hisax/hfc_pci.h	Fri Apr 21 12:46:10 2000
+++ linux.19p18/drivers/isdn/hisax/hfc_pci.h	Wed Dec 13 22:07:49 2000
@@ -1,5 +1,5 @@
-/* $Id: hfc_pci.h,v 1.7 1999/10/10 20:13:06 werner Exp $
-
+/* $Id: hfc_pci.h,v 1.8 2000/06/26 08:59:13 keil Exp $
+ *
  *  specific defines for CCD's HFC 2BDS0 PCI chips
  *
  * Author     Werner Cornelius (werner@isdn4linux.de)      
@@ -19,28 +19,6 @@
  * 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.
- *
- * $Log: hfc_pci.h,v $
- * Revision 1.7  1999/10/10 20:13:06  werner
- *
- * Corrected timer constant
- *
- * Revision 1.6  1999/08/28 21:04:29  werner
- * Implemented full audio support (transparent mode)
- *
- * Revision 1.5  1999/08/09 19:13:34  werner
- * moved constant pci ids to pci id table
- *
- * Revision 1.4  1999/08/08 10:17:33  werner
- * added new PCI vendor and card ids for Manufacturer 0x1043
- *
- * Revision 1.3  1999/07/14 12:39:34  werner
- * Added changes for echo handling.
- *
- * Revision 1.2  1999/07/01 08:07:52  keil
- * Initial version
- *
- *
  *
  */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/hfc_sx.c linux.19p18/drivers/isdn/hisax/hfc_sx.c
--- linux.vanilla/drivers/isdn/hisax/hfc_sx.c	Fri Apr 21 12:46:10 2000
+++ linux.19p18/drivers/isdn/hisax/hfc_sx.c	Mon Feb 12 15:09:50 2001
@@ -1,4 +1,4 @@
-/* $Id: hfc_sx.c,v 1.3 2000/01/20 19:49:36 keil Exp $
+/* $Id: hfc_sx.c,v 1.9 2000/11/24 17:05:37 kai Exp $
 
  * hfc_sx.c     low level driver for CCD´s hfc-s+/sp based cards
  *
@@ -21,25 +21,10 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * $Log: hfc_sx.c,v $
- * Revision 1.3  2000/01/20 19:49:36  keil
- * Support teles 13.3c vendor version 2.1
- *
- * Revision 1.2  1999/12/19 13:09:42  keil
- * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
- * signal proof delays
- *
- * Revision 1.1  1999/11/18 00:09:18  werner
- *
- * Initial release of files for HFC-S+ and HFC-SP cards with 32K-RAM.
- * Audio and Echo are supported.
- *
- *
- *
  */
 
-#include <linux/config.h>
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "hfc_sx.h"
 #include "isdnl1.h"
@@ -47,7 +32,7 @@
 
 extern const char *CardType[];
 
-static const char *hfcsx_revision = "$Revision: 1.3 $";
+static const char *hfcsx_revision = "$Revision: 1.9 $";
 
 /***************************************/
 /* IRQ-table for CCDs demo board       */
@@ -361,7 +346,7 @@
 	restore_flags(flags);
 	Write_hfc(cs, HFCSX_CIRM, HFCSX_RESET);	/* Reset On */
 	sti();
-	current->state = TASK_UNINTERRUPTIBLE;
+	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout((30 * HZ) / 1000);	/* Timeout 30ms */
 	Write_hfc(cs, HFCSX_CIRM, 0);	/* Reset Off */
 	del_timer(&cs->hw.hfcsx.timer);
@@ -408,10 +393,10 @@
 	while (1) {
 	  Write_hfc(cs, HFCSX_CIRM, HFCSX_RESET | cs->hw.hfcsx.cirm ); /* Reset */
 	  sti();
-	  current->state = TASK_UNINTERRUPTIBLE;
+	  set_current_state(TASK_UNINTERRUPTIBLE);
 	  schedule_timeout((30 * HZ) / 1000);	/* Timeout 30ms */
 	  Write_hfc(cs, HFCSX_CIRM, cs->hw.hfcsx.cirm); /* Reset Off */
-	  current->state = TASK_UNINTERRUPTIBLE;
+	  set_current_state(TASK_UNINTERRUPTIBLE);
 	  schedule_timeout((20 * HZ) / 1000);	/* Timeout 20ms */
 	  if (Read_hfc(cs, HFCSX_STATUS) & 2)
 	    printk(KERN_WARNING "HFC-SX init bit busy\n");
@@ -1431,8 +1416,8 @@
 /********************************/
 /* called for card init message */
 /********************************/
-__initfunc(void
-	   inithfcsx(struct IsdnCardState *cs))
+void 
+inithfcsx(struct IsdnCardState *cs)
 {
 	cs->setstack_d = setstack_hfcsx;
 	cs->dbusytimer.function = (void *) hfcsx_dbusy_timer;
@@ -1471,7 +1456,7 @@
 			inithfcsx(cs);
 			save_flags(flags);
 			sti();
-			current->state = TASK_UNINTERRUPTIBLE;
+			set_current_state(TASK_UNINTERRUPTIBLE);
 			schedule_timeout((80 * HZ) / 1000);	/* Timeout 80ms */
 			/* now switch timer interrupt off */
 			cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER;
@@ -1488,8 +1473,8 @@
 
 
 
-__initfunc(int
-	   setup_hfcsx(struct IsdnCard *card))
+int 
+setup_hfcsx(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
@@ -1502,7 +1487,8 @@
 	cs->hw.hfcsx.int_s1 = 0;
 	cs->dc.hfcsx.ph_state = 0;
 	cs->hw.hfcsx.fifo = 255;
-	if (cs->typ == ISDN_CTYPE_HFC_SX) {
+	if ((cs->typ == ISDN_CTYPE_HFC_SX) || 
+	    (cs->typ == ISDN_CTYPE_HFC_SP_PCMCIA)) {
 	        if ((!cs->hw.hfcsx.base) || 
 		    check_region((cs->hw.hfcsx.base), 2)) {
 		  printk(KERN_WARNING
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/hfc_sx.h linux.19p18/drivers/isdn/hisax/hfc_sx.h
--- linux.vanilla/drivers/isdn/hisax/hfc_sx.h	Fri Apr 21 12:46:10 2000
+++ linux.19p18/drivers/isdn/hisax/hfc_sx.h	Wed Dec 13 22:07:49 2000
@@ -1,5 +1,5 @@
-/* $Id: hfc_sx.h,v 1.1 1999/11/18 00:09:18 werner Exp $
-
+/* $Id: hfc_sx.h,v 1.2 2000/06/26 08:59:13 keil Exp $
+ *
  *  specific defines for CCD's HFC 2BDS0 S+,SP chips
  *
  * Author     Werner Cornelius (werner@isdn4linux.de)      
@@ -19,14 +19,6 @@
  * 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.
- *
- * $Log: hfc_sx.h,v $
- * Revision 1.1  1999/11/18 00:09:18  werner
- *
- * Initial release of files for HFC-S+ and HFC-SP cards with 32K-RAM.
- * Audio and Echo are supported.
- *
- *
  *
  */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/hfcscard.c linux.19p18/drivers/isdn/hisax/hfcscard.c
--- linux.vanilla/drivers/isdn/hisax/hfcscard.c	Fri Apr 21 12:46:09 2000
+++ linux.19p18/drivers/isdn/hisax/hfcscard.c	Mon Feb 12 15:09:50 2001
@@ -1,40 +1,22 @@
-/* $Id: hfcscard.c,v 1.6 1999/12/19 13:09:42 keil Exp $
-
+/* $Id: hfcscard.c,v 1.8 2000/11/24 17:05:37 kai Exp $
+ *
  * hfcscard.c     low level stuff for hfcs based cards (Teles3c, ACER P10)
  *
  * Author     Karsten Keil (keil@isdn4linux.de)
  *
- *
- * $Log: hfcscard.c,v $
- * Revision 1.6  1999/12/19 13:09:42  keil
- * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
- * signal proof delays
- *
- * Revision 1.5  1999/09/04 06:20:06  keil
- * Changes from kernel set_current_state()
- *
- * Revision 1.4  1999/08/09 18:59:59  keil
- * Fix S0 init - Thanks to Stefan Gybas
- *
- * Revision 1.3  1999/07/12 21:05:12  keil
- * fix race in IRQ handling
- * added watchdog for lost IRQs
- *
- * Revision 1.2  1999/07/01 08:16:03  keil
- * teles3c ---> hfcscard
- *
- *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "hfc_2bds0.h"
 #include "isdnl1.h"
 
 extern const char *CardType[];
 
-static const char *hfcs_revision = "$Revision: 1.6 $";
+static const char *hfcs_revision = "$Revision: 1.8 $";
 
 static void
 hfcs_interrupt(int intno, void *dev_id, struct pt_regs *regs)
@@ -89,13 +71,13 @@
 	cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm);	/* Reset On */
 	save_flags(flags);
 	sti();
-	current->state = TASK_UNINTERRUPTIBLE;
+	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout((30*HZ)/1000);
 	cs->hw.hfcD.cirm = 0;
 	if (cs->typ == ISDN_CTYPE_TELES3C)
 		cs->hw.hfcD.cirm |= HFCD_MEM8K;
 	cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm);	/* Reset Off */
-	current->state = TASK_UNINTERRUPTIBLE;
+	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout((10*HZ)/1000);
 	if (cs->typ == ISDN_CTYPE_TELES3C)
 		cs->hw.hfcD.cirm |= HFCD_INTB;
@@ -142,7 +124,7 @@
 			init2bds0(cs);
 			save_flags(flags);
 			sti();
-			current->state = TASK_UNINTERRUPTIBLE;
+			set_current_state(TASK_UNINTERRUPTIBLE);
 			schedule_timeout((80*HZ)/1000);
 			cs->hw.hfcD.ctmt |= HFCD_TIM800;
 			cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt); 
@@ -155,8 +137,8 @@
 	return(0);
 }
 
-__initfunc(int
-setup_hfcs(struct IsdnCard *card))
+int __init
+setup_hfcs(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/hisax.h linux.19p18/drivers/isdn/hisax/hisax.h
--- linux.vanilla/drivers/isdn/hisax/hisax.h	Wed May  3 22:33:45 2000
+++ linux.19p18/drivers/isdn/hisax/hisax.h	Sun Mar 11 13:13:01 2001
@@ -1,143 +1,8 @@
-/* $Id: hisax.h,v 2.41 2000/02/26 00:35:13 keil Exp $
-
- *   Basic declarations, defines and prototypes
- *
- * $Log: hisax.h,v $
- * Revision 2.41  2000/02/26 00:35:13  keil
- * Fix skb freeing in interrupt context
- *
- * Revision 2.40  2000/01/20 19:51:46  keil
- * Fix AddTimer message
- * Change CONFIG defines
- *
- * Revision 2.39  1999/11/18 00:00:43  werner
- *
- * Added support for HFC-S+ and HFC-SP cards
- *
- * Revision 2.38  1999/11/14 23:37:03  keil
- * new ISA memory mapped IO
- *
- * Revision 2.37  1999/10/14 20:25:28  keil
- * add a statistic for error monitoring
- *
- * Revision 2.36  1999/10/10 20:16:15  werner
- *
- * Added variable to hfcpci union.
- *
- * Revision 2.35  1999/09/04 06:35:09  keil
- * Winbond W6692 support
- *
- * Revision 2.34  1999/08/25 17:00:04  keil
- * Make ISAR V32bis modem running
- * Make LL->HL interface open for additional commands
- *
- * Revision 2.33  1999/08/05 20:43:16  keil
- * ISAR analog modem support
- *
- * Revision 2.31  1999/07/21 14:46:11  keil
- * changes from EICON certification
- *
- * Revision 2.30  1999/07/14 12:38:38  werner
- * Added changes for echo channel handling
- *
- * Revision 2.29  1999/07/12 21:05:14  keil
- * fix race in IRQ handling
- * added watchdog for lost IRQs
- *
- * Revision 2.28  1999/07/05 23:51:46  werner
- * Allow limiting of available HiSax B-chans per card. Controlled by hisaxctrl
- * hisaxctrl id 10 <nr. of chans 0-2>
- *
- * Revision 2.27  1999/07/01 08:11:38  keil
- * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
- *
- * Revision 2.26  1998/11/15 23:54:45  keil
- * changes from 2.0
- *
- * Revision 2.25  1998/09/30 22:28:42  keil
- * More work for ISAR support
- *
- * Revision 2.24  1998/08/20 13:50:39  keil
- * More support for hybrid modem (not working yet)
- *
- * Revision 2.23  1998/08/13 23:36:31  keil
- * HiSax 3.1 - don't work stable with current LinkLevel
- *
- * Revision 2.22  1998/07/15 15:01:28  calle
- * Support for AVM passive PCMCIA cards:
- *    A1 PCMCIA, FRITZ!Card PCMCIA and FRITZ!Card PCMCIA 2.0
- *
- * Revision 2.21  1998/05/25 14:10:05  keil
- * HiSax 3.0
- * X.75 and leased are working again.
- *
- * Revision 2.20  1998/05/25 12:57:57  keil
- * HiSax golden code from certification, Don't use !!!
- * No leased lines, no X75, but many changes.
- *
- * Revision 2.19  1998/04/15 16:39:15  keil
- * Add S0Box and Teles PCI support
- *
- * Revision 2.18  1998/03/26 07:10:04  paul
- * The jumpmatrix table in struct Fsm was an array of "int". This is not
- * large enough for pointers to functions on Linux/Alpha (instant crash
- * on "insmod hisax). Now there is a typedef for the pointer to function.
- * This also prevents warnings about "incompatible pointer types".
- *
- * Revision 2.17  1998/03/19 13:18:43  keil
- * Start of a CAPI like interface for supplementary Service
- * first service: SUSPEND
- *
- * Revision 2.16  1998/03/09 23:19:25  keil
- * Changes for PCMCIA
- *
- * Revision 2.14  1998/02/11 17:28:04  keil
- * Niccy PnP/PCI support
- *
- * Revision 2.13  1998/02/09 18:46:02  keil
- * Support for Sedlbauer PCMCIA (Marcus Niemann)
- *
- * Revision 2.12  1998/02/03 23:31:30  keil
- * add AMD7930 support
- *
- * Revision 2.11  1998/02/02 13:33:00  keil
- * New card support
- *
- * Revision 2.10  1997/11/08 21:37:52  keil
- * new l1 init;new Compaq card
- *
- * Revision 2.9  1997/11/06 17:09:09  keil
- * New 2.1 init code
- *
- * Revision 2.8  1997/10/29 19:04:13  keil
- * new L1; changes for 2.1
- *
- * Revision 2.7  1997/10/10 20:56:47  fritz
- * New HL interface.
- *
- * Revision 2.6  1997/09/11 17:25:51  keil
- * Add new cards
- *
- * Revision 2.5  1997/08/03 14:36:31  keil
- * Implement RESTART procedure
- *
- * Revision 2.4  1997/07/31 19:25:20  keil
- * PTP_DATA_LINK support
+/* $Id: hisax.h,v 2.52.6.2 2001/02/10 14:41:22 kai Exp $
  *
- * Revision 2.3  1997/07/31 11:50:17  keil
- * ONE TEI and FIXED TEI handling
- *
- * Revision 2.2  1997/07/30 17:13:02  keil
- * more changes for 'One TEI per card'
- *
- * Revision 2.1  1997/07/27 21:45:13  keil
- * new main structures
- *
- * Revision 2.0  1997/06/26 11:06:27  keil
- * New card and L1 interface.
- * Eicon.Diehl Diva and Dynalink IS64PH support
+ *   Basic declarations, defines and prototypes
  *
- * old changes removed KKe
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 #include <linux/config.h>
@@ -151,7 +16,7 @@
 #include <linux/delay.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
 #include <linux/ioport.h>
@@ -173,8 +38,11 @@
 #define HW_POWERUP	0x0008
 #define HW_ACTIVATE	0x0010
 #define HW_DEACTIVATE	0x0018
+
+#define HW_INFO1	0x0010
 #define HW_INFO2	0x0020
 #define HW_INFO3	0x0030
+#define HW_INFO4	0x0040
 #define HW_INFO4_P8	0x0040
 #define HW_INFO4_P10	0x0048
 #define HW_RSYNC	0x0060
@@ -224,6 +92,7 @@
 #define CC_SUSPEND	0x0370
 #define CC_PROCEED_SEND 0x0374
 #define CC_REDIR        0x0378
+#define CC_T302		0x0382
 #define CC_T303		0x0383
 #define CC_T304		0x0384
 #define CC_T305		0x0385
@@ -234,6 +103,7 @@
 #define CC_T313		0x0393
 #define CC_T318		0x0398
 #define CC_T319		0x0399
+#define CC_TSPID	0x03A0
 #define CC_NOSETUP_RSP	0x03E0
 #define CC_SETUP_ERR	0x03E1
 #define CC_SUSPEND_ERR	0x03E2
@@ -242,6 +112,7 @@
 #define CC_RELEASE_ERR	0x03E5
 #define CC_RESTART	0x03F4
 #define CC_TDSS1_IO     0x13F4    /* DSS1 IO user timer */
+#define CC_TNI1_IO      0x13F5    /* NI1 IO user timer */
 
 /* define maximum number of possible waiting incoming calls */
 #define MAX_WAITING_CALLS 2
@@ -249,13 +120,19 @@
 
 #ifdef __KERNEL__
 
-/* include only l3dss1 specific process structures, but no other defines */
+/* include l3dss1 & ni1 specific process structures, but no other defines */
 #ifdef CONFIG_HISAX_EURO
   #define l3dss1_process
   #include "l3dss1.h" 
   #undef  l3dss1_process
 #endif CONFIG_HISAX_EURO
 
+#ifdef CONFIG_HISAX_NI1
+  #define l3ni1_process
+  #include "l3ni1.h" 
+  #undef  l3ni1_process
+#endif CONFIG_HISAX_NI1
+
 #define MAX_DFRAME_LEN	260
 #define MAX_DFRAME_LEN_L1	300
 #define HSCX_BUFMAX	4096
@@ -318,12 +195,13 @@
 #define FLG_L1_ACTTIMER		4
 #define FLG_L1_T3RUN		5
 #define FLG_L1_PULL_REQ		6
+#define FLG_L1_UINT		7
 
 struct Layer1 {
 	void *hardware;
 	struct BCState *bcs;
 	struct PStack **stlistp;
-	int Flags;
+	long Flags;
 	struct FsmInst l1m;
 	struct FsmTimer	timer;
 	void (*l1l2) (struct PStack *, int, void *);
@@ -362,7 +240,7 @@
 	int tei;
 	int sap;
 	int maxlen;
-	unsigned int flag;
+	unsigned long flag;
 	unsigned int vs, va, vr;
 	int rc;
 	unsigned int window;
@@ -432,7 +310,7 @@
 	struct Layer3 l3;
 	struct LLInterface lli;
 	struct Management ma;
-	int protocol;		/* EDSS1 or 1TR6 */
+	int protocol;		/* EDSS1, 1TR6 or NI1 */
 
         /* protocol specific data fields */
         union
@@ -440,6 +318,9 @@
 #ifdef CONFIG_HISAX_EURO
            dss1_stk_priv dss1; /* private dss1 data */
 #endif CONFIG_HISAX_EURO              
+#ifdef CONFIG_HISAX_NI1
+           ni1_stk_priv ni1; /* private ni1 data */
+#endif CONFIG_HISAX_NI1              
 	 } prot;
 };
 
@@ -461,6 +342,9 @@
 #ifdef CONFIG_HISAX_EURO 
            dss1_proc_priv dss1; /* private dss1 data */
 #endif CONFIG_HISAX_EURO            
+#ifdef CONFIG_HISAX_NI1
+           ni1_proc_priv ni1; /* private ni1 data */
+#endif CONFIG_HISAX_NI1              
 	 } prot;
 };
 
@@ -481,7 +365,7 @@
 };
 
 struct isar_reg {
-	unsigned int Flags;
+	unsigned long Flags;
 	volatile u_char bstat;
 	volatile u_char iis;
 	volatile u_char cmsb;
@@ -499,6 +383,7 @@
 	u_char mod;
 	u_char newcmd;
 	u_char newmod;
+	char try_mod;
 	struct timer_list ftimer;
 	u_char *rcvbuf;         /* B-Channel receive Buffer */
 	u_char conmsg[16];
@@ -506,10 +391,17 @@
 };
 
 struct hdlc_stat_reg {
+#ifdef __BIG_ENDIAN
+	u_char fill __attribute__((packed));
+	u_char mode __attribute__((packed));
+	u_char xml  __attribute__((packed));
+	u_char cmd  __attribute__((packed));
+#else
 	u_char cmd  __attribute__((packed));
 	u_char xml  __attribute__((packed));
 	u_char mode __attribute__((packed));
 	u_char fill __attribute__((packed));
+#endif
 };
 
 struct hdlc_hw {
@@ -583,6 +475,7 @@
 #define L1_MODE_TRANS	1
 #define L1_MODE_HDLC	2
 #define L1_MODE_EXTRN	3
+#define L1_MODE_HDLC_56K 4
 #define L1_MODE_MODEM	7
 #define L1_MODE_V32	8
 #define L1_MODE_FAX	9
@@ -590,7 +483,7 @@
 struct BCState {
 	int channel;
 	int mode;
-	int Flag;
+	long Flag; /* long req'd for set_bit --RR */
 	struct IsdnCardState *cs;
 	int tx_cnt;		/* B-Channel transmit counter */
 	struct sk_buff *tx_skb; /* B-Channel transmit Buffer */
@@ -635,7 +528,8 @@
 	int data_open;
 	struct l3_process *proc;
 	setup_parm setup;	/* from isdnif.h numbers and Serviceindicator */
-	int Flags;		/* for remembering action done in l4 */
+	long Flags;		/* for remembering action done in l4 */
+				/* long req'd for set_bit --RR */
 	int leased;
 };
 
@@ -894,8 +788,8 @@
 	unsigned char *sfifo_e;
 	int sfifo_cnt;
 	unsigned int stat;
-	struct wait_queue *rwaitq;
-	struct wait_queue *swaitq;
+	wait_queue_head_t rwaitq;
+	wait_queue_head_t swaitq;
 };
 #endif
 
@@ -915,7 +809,7 @@
 	int mon_rxp;
 	struct arcofi_msg *arcofi_list;
 	struct timer_list arcofitimer;
-	struct wait_queue *arcofi_wait;
+	wait_queue_head_t arcofi_wait;
 	u_char arcofi_bc;
 	u_char arcofi_state;
 	u_char mocr;
@@ -938,6 +832,22 @@
 	int ph_state;
 };
 
+struct icc_chip {
+	int ph_state;
+	u_char *mon_tx;
+	u_char *mon_rx;
+	int mon_txp;
+	int mon_txc;
+	int mon_rxp;
+	struct arcofi_msg *arcofi_list;
+	struct timer_list arcofitimer;
+	wait_queue_head_t arcofi_wait;
+	u_char arcofi_bc;
+	u_char arcofi_state;
+	u_char mocr;
+	u_char adf2;
+};
+
 #define HW_IOM1			0
 #define HW_IPAC			1
 #define HW_ISAR			2
@@ -948,6 +858,7 @@
 #define FLG_LOCK_ATOMIC 	7
 #define FLG_ARCOFI_TIMER	8
 #define FLG_ARCOFI_ERROR	9
+#define FLG_HW_L1_UINT		10
 
 struct IsdnCardState {
 	unsigned char typ;
@@ -955,7 +866,7 @@
 	int protocol;
 	unsigned int irq;
 	unsigned long irq_flags;
-	int HW_Flags;
+	long HW_Flags;
 	int *busy_flag;
         int chanlimit; /* limited number of B-chans to use */
         int logecho; /* log echo if supported by card */
@@ -1016,12 +927,13 @@
 		struct hfcpci_chip hfcpci;
 		struct hfcsx_chip hfcsx;
 		struct w6692_chip w6692;
+		struct icc_chip icc;
 	} dc;
 	u_char *rcvbuf;
 	int rcvidx;
 	struct sk_buff *tx_skb;
 	int tx_cnt;
-	int event;
+	long event;
 	struct tq_struct tqueue;
 	struct timer_list dbusytimer;
 #ifdef ERROR_STATISTIC
@@ -1057,7 +969,7 @@
 #define  ISDN_CTYPE_MIC		17
 #define  ISDN_CTYPE_ELSA_PCI	18
 #define  ISDN_CTYPE_COMPAQ_ISA	19
-#define  ISDN_CTYPE_NETJET	20
+#define  ISDN_CTYPE_NETJET_S	20
 #define  ISDN_CTYPE_TELESPCI	21
 #define  ISDN_CTYPE_SEDLBAUER_PCMCIA	22
 #define  ISDN_CTYPE_AMD7930	23
@@ -1075,24 +987,15 @@
 #define  ISDN_CTYPE_HFC_PCI	35
 #define  ISDN_CTYPE_W6692	36
 #define  ISDN_CTYPE_HFC_SX      37
-#define  ISDN_CTYPE_COUNT	37
+#define  ISDN_CTYPE_NETJET_U	38
+#define  ISDN_CTYPE_HFC_SP_PCMCIA      39
+#define  ISDN_CTYPE_COUNT	39
 
 
 #ifdef ISDN_CHIP_ISAC
 #undef ISDN_CHIP_ISAC
 #endif
 
-#ifndef __initfunc
-#define __initfunc(__arginit) __arginit
-#endif
-
-#ifndef __initdata
-#define __initdata
-#endif
-
-#define HISAX_INITFUNC(__arginit) __initfunc(__arginit)
-#define HISAX_INITDATA __initdata
-
 #ifdef	CONFIG_HISAX_16_0
 #define  CARD_TELES0 1
 #ifndef ISDN_CHIP_ISAC
@@ -1152,10 +1055,6 @@
 #ifndef ISDN_CHIP_ISAC
 #define ISDN_CHIP_ISAC 1
 #endif
-#undef HISAX_INITFUNC
-#define HISAX_INITFUNC(__arginit) __arginit
-#undef HISAX_INITDATA
-#define HISAX_INITDATA
 #else
 #define  CARD_ELSA  0
 #endif
@@ -1224,12 +1123,12 @@
 #endif
 
 #ifdef  CONFIG_HISAX_NETJET
-#define CARD_NETJET 1
+#define CARD_NETJET_S 1
 #ifndef ISDN_CHIP_ISAC
 #define ISDN_CHIP_ISAC 1
 #endif
 #else
-#define CARD_NETJET 0
+#define CARD_NETJET_S 0
 #endif
 
 #ifdef	CONFIG_HISAX_HFCS
@@ -1337,17 +1236,19 @@
 #define	CARD_W6692	0
 #endif
 
-#define TEI_PER_CARD 0
-
-#ifdef CONFIG_HISAX_1TR6
-#undef TEI_PER_CARD
-#define TEI_PER_CARD 1
+#ifdef  CONFIG_HISAX_NETJET_U
+#define CARD_NETJET_U 1
+#ifndef ISDN_CHIP_ICC
+#define ISDN_CHIP_ICC 1
+#endif
+#ifndef HISAX_UINTERFACE
+#define HISAX_UINTERFACE 1
+#endif
+#else
+#define CARD_NETJET_U 0
 #endif
 
-#ifdef CONFIG_HISAX_EURO
-#undef TEI_PER_CARD
 #define TEI_PER_CARD 1
-#endif
 
 /* L1 Debug */
 #define	L1_DEB_WARN		0x01
@@ -1371,7 +1272,7 @@
 
 struct IsdnCard {
 	int typ;
-	int protocol;		/* EDSS1 or 1TR6 */
+	int protocol;		/* EDSS1, 1TR6 or NI1 */
 	unsigned int para[4];
 	struct IsdnCardState *cs;
 };
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/hscx.c linux.19p18/drivers/isdn/hisax/hscx.c
--- linux.vanilla/drivers/isdn/hisax/hscx.c	Fri Apr 21 12:46:10 2000
+++ linux.19p18/drivers/isdn/hisax/hscx.c	Mon Feb 12 15:09:50 2001
@@ -1,77 +1,27 @@
-/* $Id: hscx.c,v 1.17 1999/07/01 08:11:41 keil Exp $
-
+/* $Id: hscx.c,v 1.21 2000/11/24 17:05:37 kai Exp $
+ *
  * hscx.c   HSCX specific routines
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *
- *
- * $Log: hscx.c,v $
- * Revision 1.17  1999/07/01 08:11:41  keil
- * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
- *
- * Revision 1.16  1998/11/15 23:54:48  keil
- * changes from 2.0
- *
- * Revision 1.15  1998/08/20 13:50:42  keil
- * More support for hybrid modem (not working yet)
- *
- * Revision 1.14  1998/08/13 23:36:33  keil
- * HiSax 3.1 - don't work stable with current LinkLevel
- *
- * Revision 1.13  1998/06/26 22:03:28  keil
- * send flags between hdlc frames
- *
- * Revision 1.12  1998/06/09 18:26:01  keil
- * PH_DEACTIVATE B-channel every time signaled to higher layer
- *
- * Revision 1.11  1998/05/25 14:10:07  keil
- * HiSax 3.0
- * X.75 and leased are working again.
- *
- * Revision 1.10  1998/05/25 12:57:59  keil
- * HiSax golden code from certification, Don't use !!!
- * No leased lines, no X75, but many changes.
- *
- * Revision 1.9  1998/04/15 16:45:33  keil
- * new init code
- *
- * Revision 1.8  1998/03/19 13:16:24  keil
- * fix the correct release of the hscx
- *
- * Revision 1.7  1998/02/12 23:07:36  keil
- * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
- *
- * Revision 1.6  1998/02/02 13:41:12  keil
- * new init
- *
- * Revision 1.5  1997/11/06 17:09:34  keil
- * New 2.1 init code
- *
- * Revision 1.4  1997/10/29 19:01:06  keil
- * changes for 2.1
- *
- * Revision 1.3  1997/07/27 21:38:34  keil
- * new B-channel interface
- *
- * Revision 1.2  1997/06/26 11:16:17  keil
- * first version
- *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "hscx.h"
 #include "isac.h"
 #include "isdnl1.h"
 #include <linux/interrupt.h>
 
-static char *HSCXVer[] HISAX_INITDATA =
+static char *HSCXVer[] __initdata =
 {"A1", "?1", "A2", "?3", "A3", "V2.1", "?6", "?7",
  "?8", "?9", "?10", "?11", "?12", "?13", "?14", "???"};
 
-HISAX_INITFUNC(int
-HscxVersion(struct IsdnCardState *cs, char *s))
+int __init
+HscxVersion(struct IsdnCardState *cs, char *s)
 {
 	int verA, verB;
 
@@ -269,8 +219,8 @@
 	return (0);
 }
 
-HISAX_INITFUNC(void
-clear_pending_hscx_ints(struct IsdnCardState *cs))
+void __init
+clear_pending_hscx_ints(struct IsdnCardState *cs)
 {
 	int val, eval;
 
@@ -295,8 +245,8 @@
 	cs->BC_Write_Reg(cs, 1, HSCX_MASK, 0xFF);
 }
 
-HISAX_INITFUNC(void
-inithscx(struct IsdnCardState *cs))
+void __init
+inithscx(struct IsdnCardState *cs)
 {
 	cs->bcs[0].BC_SetStack = setstack_hscx;
 	cs->bcs[1].BC_SetStack = setstack_hscx;
@@ -312,8 +262,8 @@
 	modehscx(cs->bcs + 1, 0, 0);
 }
 
-HISAX_INITFUNC(void
-inithscxisac(struct IsdnCardState *cs, int part))
+void __init
+inithscxisac(struct IsdnCardState *cs, int part)
 {
 	if (part & 1) {
 		clear_pending_isac_ints(cs);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/hscx.h linux.19p18/drivers/isdn/hisax/hscx.h
--- linux.vanilla/drivers/isdn/hisax/hscx.h	Fri Apr 21 12:46:10 2000
+++ linux.19p18/drivers/isdn/hisax/hscx.h	Wed Dec 13 22:07:56 2000
@@ -1,23 +1,10 @@
-/* $Id: hscx.h,v 1.5 1999/12/23 15:09:32 keil Exp $
-
+/* $Id: hscx.h,v 1.6 2000/06/26 08:59:13 keil Exp $
+ *
  * hscx.h   HSCX specific defines
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *
- *
- * $Log: hscx.h,v $
- * Revision 1.5  1999/12/23 15:09:32  keil
- * change email
- *
- * Revision 1.4  1998/04/15 16:45:34  keil
- * new init code
- *
- * Revision 1.3  1997/07/27 21:38:35  keil
- * new B-channel interface
- *
- * Revision 1.2  1997/06/26 11:16:18  keil
- * first version
- *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/hscx_irq.c linux.19p18/drivers/isdn/hisax/hscx_irq.c
--- linux.vanilla/drivers/isdn/hisax/hscx_irq.c	Fri Apr 21 12:46:10 2000
+++ linux.19p18/drivers/isdn/hisax/hscx_irq.c	Sat Dec 30 19:33:52 2000
@@ -1,50 +1,12 @@
-/* $Id: hscx_irq.c,v 1.13 1999/10/14 20:25:28 keil Exp $
-
+/* $Id: hscx_irq.c,v 1.16 2000/11/19 17:02:47 kai Exp $
+ *
  * hscx_irq.c     low level b-channel stuff for Siemens HSCX
  *
  * Author     Karsten Keil (keil@isdn4linux.de)
  *
  * This is an include file for fast inline IRQ stuff
  *
- * $Log: hscx_irq.c,v $
- * Revision 1.13  1999/10/14 20:25:28  keil
- * add a statistic for error monitoring
- *
- * Revision 1.12  1999/07/01 08:11:42  keil
- * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
- *
- * Revision 1.11  1998/11/15 23:54:49  keil
- * changes from 2.0
- *
- * Revision 1.10  1998/08/13 23:36:35  keil
- * HiSax 3.1 - don't work stable with current LinkLevel
- *
- * Revision 1.9  1998/06/24 14:44:51  keil
- * Fix recovery of TX IRQ loss
- *
- * Revision 1.8  1998/04/10 10:35:22  paul
- * fixed (silly?) warnings from egcs on Alpha.
- *
- * Revision 1.7  1998/02/12 23:07:37  keil
- * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
- *
- * Revision 1.6  1997/10/29 19:01:07  keil
- * changes for 2.1
- *
- * Revision 1.5  1997/10/01 09:21:35  fritz
- * Removed old compatibility stuff for 2.0.X kernels.
- * From now on, this code is for 2.1.X ONLY!
- * Old stuff is still in the separate branch.
- *
- * Revision 1.4  1997/08/15 17:48:02  keil
- * cosmetic
- *
- * Revision 1.3  1997/07/27 21:38:36  keil
- * new B-channel interface
- *
- * Revision 1.2  1997/06/26 11:16:19  keil
- * first version
- *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/icc.c linux.19p18/drivers/isdn/hisax/icc.c
--- linux.vanilla/drivers/isdn/hisax/icc.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/hisax/icc.c	Mon Feb 12 15:09:50 2001
@@ -0,0 +1,686 @@
+// $Id: icc.c,v 1.5 2000/11/24 17:05:37 kai Exp $
+//-----------------------------------------------------------------------------
+//
+// ICC specific routines
+//
+// Author       Matt Henderson & Guy Ellis - Traverse Tecnologies Pty Ltd
+//              www.traverse.com.au
+//
+// 1999.6.25 Initial implementation of routines for Siemens ISDN
+// Communication Controler PEB 2070 based on the ISAC routines
+// written by Karsten Keil.
+//
+// This file is (c) under GNU PUBLIC LICENSE
+//
+//-----------------------------------------------------------------------------
+
+#define __NO_VERSION__
+#include <linux/init.h>
+#include "hisax.h"
+#include "icc.h"
+// #include "arcofi.h"
+#include "isdnl1.h"
+#include <linux/interrupt.h>
+
+#define DBUSY_TIMER_VALUE 80
+#define ARCOFI_USE 0
+
+static char *ICCVer[] __initdata =
+{"2070 A1/A3", "2070 B1", "2070 B2/B3", "2070 V2.4"};
+
+void
+ICCVersion(struct IsdnCardState *cs, char *s)
+{
+	int val;
+
+	val = cs->readisac(cs, ICC_RBCH);
+	printk(KERN_INFO "%s ICC version (%x): %s\n", s, val, ICCVer[(val >> 5) & 3]);
+}
+
+static void
+ph_command(struct IsdnCardState *cs, unsigned int command)
+{
+	if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "ph_command %x", command);
+	cs->writeisac(cs, ICC_CIX0, (command << 2) | 3);
+}
+
+
+static void
+icc_new_ph(struct IsdnCardState *cs)
+{
+	switch (cs->dc.icc.ph_state) {
+		case (ICC_IND_EI1):
+			ph_command(cs, ICC_CMD_DI);
+			l1_msg(cs, HW_RESET | INDICATION, NULL);
+			break;
+		case (ICC_IND_DC):
+			l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
+			break;
+		case (ICC_IND_DR):
+			l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
+			break;
+		case (ICC_IND_PU):
+			l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
+			break;
+		case (ICC_IND_FJ):
+			l1_msg(cs, HW_RSYNC | INDICATION, NULL);
+			break;
+		case (ICC_IND_AR):
+			l1_msg(cs, HW_INFO2 | INDICATION, NULL);
+			break;
+		case (ICC_IND_AI):
+			l1_msg(cs, HW_INFO4 | INDICATION, NULL);
+			break;
+		default:
+			break;
+	}
+}
+
+static void
+icc_bh(struct IsdnCardState *cs)
+{
+	struct PStack *stptr;
+	
+	if (!cs)
+		return;
+	if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
+		if (cs->debug)
+			debugl1(cs, "D-Channel Busy cleared");
+		stptr = cs->stlist;
+		while (stptr != NULL) {
+			stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
+			stptr = stptr->next;
+		}
+	}
+	if (test_and_clear_bit(D_L1STATECHANGE, &cs->event))
+		icc_new_ph(cs);		
+	if (test_and_clear_bit(D_RCVBUFREADY, &cs->event))
+		DChannel_proc_rcv(cs);
+	if (test_and_clear_bit(D_XMTBUFREADY, &cs->event))
+		DChannel_proc_xmt(cs);
+#if ARCOFI_USE
+	if (!test_bit(HW_ARCOFI, &cs->HW_Flags))
+		return;
+	if (test_and_clear_bit(D_RX_MON1, &cs->event))
+		arcofi_fsm(cs, ARCOFI_RX_END, NULL);
+	if (test_and_clear_bit(D_TX_MON1, &cs->event))
+		arcofi_fsm(cs, ARCOFI_TX_END, NULL);
+#endif
+}
+
+void
+icc_empty_fifo(struct IsdnCardState *cs, int count)
+{
+	u_char *ptr;
+	long flags;
+
+	if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
+		debugl1(cs, "icc_empty_fifo");
+
+	if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
+		if (cs->debug & L1_DEB_WARN)
+			debugl1(cs, "icc_empty_fifo overrun %d",
+				cs->rcvidx + count);
+		cs->writeisac(cs, ICC_CMDR, 0x80);
+		cs->rcvidx = 0;
+		return;
+	}
+	ptr = cs->rcvbuf + cs->rcvidx;
+	cs->rcvidx += count;
+	save_flags(flags);
+	cli();
+	cs->readisacfifo(cs, ptr, count);
+	cs->writeisac(cs, ICC_CMDR, 0x80);
+	restore_flags(flags);
+	if (cs->debug & L1_DEB_ISAC_FIFO) {
+		char *t = cs->dlog;
+
+		t += sprintf(t, "icc_empty_fifo cnt %d", count);
+		QuickHex(t, ptr, count);
+		debugl1(cs, cs->dlog);
+	}
+}
+
+static void
+icc_fill_fifo(struct IsdnCardState *cs)
+{
+	int count, more;
+	u_char *ptr;
+	long flags;
+
+	if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
+		debugl1(cs, "icc_fill_fifo");
+
+	if (!cs->tx_skb)
+		return;
+
+	count = cs->tx_skb->len;
+	if (count <= 0)
+		return;
+
+	more = 0;
+	if (count > 32) {
+		more = !0;
+		count = 32;
+	}
+	save_flags(flags);
+	cli();
+	ptr = cs->tx_skb->data;
+	skb_pull(cs->tx_skb, count);
+	cs->tx_cnt += count;
+	cs->writeisacfifo(cs, ptr, count);
+	cs->writeisac(cs, ICC_CMDR, more ? 0x8 : 0xa);
+	if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
+		debugl1(cs, "icc_fill_fifo dbusytimer running");
+		del_timer(&cs->dbusytimer);
+	}
+	init_timer(&cs->dbusytimer);
+	cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
+	add_timer(&cs->dbusytimer);
+	restore_flags(flags);
+	if (cs->debug & L1_DEB_ISAC_FIFO) {
+		char *t = cs->dlog;
+
+		t += sprintf(t, "icc_fill_fifo cnt %d", count);
+		QuickHex(t, ptr, count);
+		debugl1(cs, cs->dlog);
+	}
+}
+
+void
+icc_sched_event(struct IsdnCardState *cs, int event)
+{
+	test_and_set_bit(event, &cs->event);
+	queue_task(&cs->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+}
+
+void
+icc_interrupt(struct IsdnCardState *cs, u_char val)
+{
+	u_char exval, v1;
+	struct sk_buff *skb;
+	unsigned int count;
+	long flags;
+
+	if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "ICC interrupt %x", val);
+	if (val & 0x80) {	/* RME */
+		exval = cs->readisac(cs, ICC_RSTA);
+		if ((exval & 0x70) != 0x20) {
+			if (exval & 0x40) {
+				if (cs->debug & L1_DEB_WARN)
+					debugl1(cs, "ICC RDO");
+#ifdef ERROR_STATISTIC
+				cs->err_rx++;
+#endif
+			}
+			if (!(exval & 0x20)) {
+				if (cs->debug & L1_DEB_WARN)
+					debugl1(cs, "ICC CRC error");
+#ifdef ERROR_STATISTIC
+				cs->err_crc++;
+#endif
+			}
+			cs->writeisac(cs, ICC_CMDR, 0x80);
+		} else {
+			count = cs->readisac(cs, ICC_RBCL) & 0x1f;
+			if (count == 0)
+				count = 32;
+			icc_empty_fifo(cs, count);
+			save_flags(flags);
+			cli();
+			if ((count = cs->rcvidx) > 0) {
+				cs->rcvidx = 0;
+				if (!(skb = alloc_skb(count, GFP_ATOMIC)))
+					printk(KERN_WARNING "HiSax: D receive out of memory\n");
+				else {
+					memcpy(skb_put(skb, count), cs->rcvbuf, count);
+					skb_queue_tail(&cs->rq, skb);
+				}
+			}
+			restore_flags(flags);
+		}
+		cs->rcvidx = 0;
+		icc_sched_event(cs, D_RCVBUFREADY);
+	}
+	if (val & 0x40) {	/* RPF */
+		icc_empty_fifo(cs, 32);
+	}
+	if (val & 0x20) {	/* RSC */
+		/* never */
+		if (cs->debug & L1_DEB_WARN)
+			debugl1(cs, "ICC RSC interrupt");
+	}
+	if (val & 0x10) {	/* XPR */
+		if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+			del_timer(&cs->dbusytimer);
+		if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+			icc_sched_event(cs, D_CLEARBUSY);
+		if (cs->tx_skb) {
+			if (cs->tx_skb->len) {
+				icc_fill_fifo(cs);
+				goto afterXPR;
+			} else {
+				dev_kfree_skb(cs->tx_skb);
+				cs->tx_cnt = 0;
+				cs->tx_skb = NULL;
+			}
+		}
+		if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
+			cs->tx_cnt = 0;
+			icc_fill_fifo(cs);
+		} else
+			icc_sched_event(cs, D_XMTBUFREADY);
+	}
+      afterXPR:
+	if (val & 0x04) {	/* CISQ */
+		exval = cs->readisac(cs, ICC_CIR0);
+		if (cs->debug & L1_DEB_ISAC)
+			debugl1(cs, "ICC CIR0 %02X", exval );
+		if (exval & 2) {
+			cs->dc.icc.ph_state = (exval >> 2) & 0xf;
+			if (cs->debug & L1_DEB_ISAC)
+				debugl1(cs, "ph_state change %x", cs->dc.icc.ph_state);
+			icc_sched_event(cs, D_L1STATECHANGE);
+		}
+		if (exval & 1) {
+			exval = cs->readisac(cs, ICC_CIR1);
+			if (cs->debug & L1_DEB_ISAC)
+				debugl1(cs, "ICC CIR1 %02X", exval );
+		}
+	}
+	if (val & 0x02) {	/* SIN */
+		/* never */
+		if (cs->debug & L1_DEB_WARN)
+			debugl1(cs, "ICC SIN interrupt");
+	}
+	if (val & 0x01) {	/* EXI */
+		exval = cs->readisac(cs, ICC_EXIR);
+		if (cs->debug & L1_DEB_WARN)
+			debugl1(cs, "ICC EXIR %02x", exval);
+		if (exval & 0x80) {  /* XMR */
+			debugl1(cs, "ICC XMR");
+			printk(KERN_WARNING "HiSax: ICC XMR\n");
+		}
+		if (exval & 0x40) {  /* XDU */
+			debugl1(cs, "ICC XDU");
+			printk(KERN_WARNING "HiSax: ICC XDU\n");
+#ifdef ERROR_STATISTIC
+			cs->err_tx++;
+#endif
+			if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+				del_timer(&cs->dbusytimer);
+			if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+				icc_sched_event(cs, D_CLEARBUSY);
+			if (cs->tx_skb) { /* Restart frame */
+				skb_push(cs->tx_skb, cs->tx_cnt);
+				cs->tx_cnt = 0;
+				icc_fill_fifo(cs);
+			} else {
+				printk(KERN_WARNING "HiSax: ICC XDU no skb\n");
+				debugl1(cs, "ICC XDU no skb");
+			}
+		}
+		if (exval & 0x04) {  /* MOS */
+			v1 = cs->readisac(cs, ICC_MOSR);
+			if (cs->debug & L1_DEB_MONITOR)
+				debugl1(cs, "ICC MOSR %02x", v1);
+#if ARCOFI_USE
+			if (v1 & 0x08) {
+				if (!cs->dc.icc.mon_rx) {
+					if (!(cs->dc.icc.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
+						if (cs->debug & L1_DEB_WARN)
+							debugl1(cs, "ICC MON RX out of memory!");
+						cs->dc.icc.mocr &= 0xf0;
+						cs->dc.icc.mocr |= 0x0a;
+						cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
+						goto afterMONR0;
+					} else
+						cs->dc.icc.mon_rxp = 0;
+				}
+				if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) {
+					cs->dc.icc.mocr &= 0xf0;
+					cs->dc.icc.mocr |= 0x0a;
+					cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
+					cs->dc.icc.mon_rxp = 0;
+					if (cs->debug & L1_DEB_WARN)
+						debugl1(cs, "ICC MON RX overflow!");
+					goto afterMONR0;
+				}
+				cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR0);
+				if (cs->debug & L1_DEB_MONITOR)
+					debugl1(cs, "ICC MOR0 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp -1]);
+				if (cs->dc.icc.mon_rxp == 1) {
+					cs->dc.icc.mocr |= 0x04;
+					cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
+				}
+			}
+		      afterMONR0:
+			if (v1 & 0x80) {
+				if (!cs->dc.icc.mon_rx) {
+					if (!(cs->dc.icc.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) {
+						if (cs->debug & L1_DEB_WARN)
+							debugl1(cs, "ICC MON RX out of memory!");
+						cs->dc.icc.mocr &= 0x0f;
+						cs->dc.icc.mocr |= 0xa0;
+						cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
+						goto afterMONR1;
+					} else
+						cs->dc.icc.mon_rxp = 0;
+				}
+				if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) {
+					cs->dc.icc.mocr &= 0x0f;
+					cs->dc.icc.mocr |= 0xa0;
+					cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
+					cs->dc.icc.mon_rxp = 0;
+					if (cs->debug & L1_DEB_WARN)
+						debugl1(cs, "ICC MON RX overflow!");
+					goto afterMONR1;
+				}
+				cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR1);
+				if (cs->debug & L1_DEB_MONITOR)
+					debugl1(cs, "ICC MOR1 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp -1]);
+				cs->dc.icc.mocr |= 0x40;
+				cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
+			}
+		      afterMONR1:
+			if (v1 & 0x04) {
+				cs->dc.icc.mocr &= 0xf0;
+				cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
+				cs->dc.icc.mocr |= 0x0a;
+				cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
+				icc_sched_event(cs, D_RX_MON0);
+			}
+			if (v1 & 0x40) {
+				cs->dc.icc.mocr &= 0x0f;
+				cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
+				cs->dc.icc.mocr |= 0xa0;
+				cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
+				icc_sched_event(cs, D_RX_MON1);
+			}
+			if (v1 & 0x02) {
+				if ((!cs->dc.icc.mon_tx) || (cs->dc.icc.mon_txc && 
+					(cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) && 
+					!(v1 & 0x08))) {
+					cs->dc.icc.mocr &= 0xf0;
+					cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
+					cs->dc.icc.mocr |= 0x0a;
+					cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
+					if (cs->dc.icc.mon_txc &&
+						(cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc))
+						icc_sched_event(cs, D_TX_MON0);
+					goto AfterMOX0;
+				}
+				if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) {
+					icc_sched_event(cs, D_TX_MON0);
+					goto AfterMOX0;
+				}
+				cs->writeisac(cs, ICC_MOX0,
+					cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]);
+				if (cs->debug & L1_DEB_MONITOR)
+					debugl1(cs, "ICC %02x -> MOX0", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp -1]);
+			}
+		      AfterMOX0:
+			if (v1 & 0x20) {
+				if ((!cs->dc.icc.mon_tx) || (cs->dc.icc.mon_txc && 
+					(cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) && 
+					!(v1 & 0x80))) {
+					cs->dc.icc.mocr &= 0x0f;
+					cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
+					cs->dc.icc.mocr |= 0xa0;
+					cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr);
+					if (cs->dc.icc.mon_txc &&
+						(cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc))
+						icc_sched_event(cs, D_TX_MON1);
+					goto AfterMOX1;
+				}
+				if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) {
+					icc_sched_event(cs, D_TX_MON1);
+					goto AfterMOX1;
+				}
+				cs->writeisac(cs, ICC_MOX1,
+					cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]);
+				if (cs->debug & L1_DEB_MONITOR)
+					debugl1(cs, "ICC %02x -> MOX1", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp -1]);
+			}
+		      AfterMOX1:
+#endif
+		}
+	}
+}
+
+static void
+ICC_l1hw(struct PStack *st, int pr, void *arg)
+{
+	struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
+	struct sk_buff *skb = arg;
+	int  val;
+
+	switch (pr) {
+		case (PH_DATA |REQUEST):
+			if (cs->debug & DEB_DLOG_HEX)
+				LogFrame(cs, skb->data, skb->len);
+			if (cs->debug & DEB_DLOG_VERBOSE)
+				dlogframe(cs, skb, 0);
+			if (cs->tx_skb) {
+				skb_queue_tail(&cs->sq, skb);
+#ifdef L2FRAME_DEBUG		/* psa */
+				if (cs->debug & L1_DEB_LAPD)
+					Logl2Frame(cs, skb, "PH_DATA Queued", 0);
+#endif
+			} else {
+				cs->tx_skb = skb;
+				cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG		/* psa */
+				if (cs->debug & L1_DEB_LAPD)
+					Logl2Frame(cs, skb, "PH_DATA", 0);
+#endif
+				icc_fill_fifo(cs);
+			}
+			break;
+		case (PH_PULL |INDICATION):
+			if (cs->tx_skb) {
+				if (cs->debug & L1_DEB_WARN)
+					debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
+				skb_queue_tail(&cs->sq, skb);
+				break;
+			}
+			if (cs->debug & DEB_DLOG_HEX)
+				LogFrame(cs, skb->data, skb->len);
+			if (cs->debug & DEB_DLOG_VERBOSE)
+				dlogframe(cs, skb, 0);
+			cs->tx_skb = skb;
+			cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG		/* psa */
+			if (cs->debug & L1_DEB_LAPD)
+				Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
+#endif
+			icc_fill_fifo(cs);
+			break;
+		case (PH_PULL | REQUEST):
+#ifdef L2FRAME_DEBUG		/* psa */
+			if (cs->debug & L1_DEB_LAPD)
+				debugl1(cs, "-> PH_REQUEST_PULL");
+#endif
+			if (!cs->tx_skb) {
+				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+				st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
+			} else
+				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+			break;
+		case (HW_RESET | REQUEST):
+			if ((cs->dc.icc.ph_state == ICC_IND_EI1) ||
+				(cs->dc.icc.ph_state == ICC_IND_DR))
+			        ph_command(cs, ICC_CMD_DI);
+			else
+				ph_command(cs, ICC_CMD_RES);
+			break;
+		case (HW_ENABLE | REQUEST):
+			ph_command(cs, ICC_CMD_DI);
+			break;
+		case (HW_INFO1 | REQUEST):
+			ph_command(cs, ICC_CMD_AR);
+			break;
+		case (HW_INFO3 | REQUEST):
+			ph_command(cs, ICC_CMD_AI);
+			break;
+		case (HW_TESTLOOP | REQUEST):
+			val = 0;
+			if (1 & (long) arg)
+				val |= 0x0c;
+			if (2 & (long) arg)
+				val |= 0x3;
+			if (test_bit(HW_IOM1, &cs->HW_Flags)) {
+				/* IOM 1 Mode */
+				if (!val) {
+					cs->writeisac(cs, ICC_SPCR, 0xa);
+					cs->writeisac(cs, ICC_ADF1, 0x2);
+				} else {
+					cs->writeisac(cs, ICC_SPCR, val);
+					cs->writeisac(cs, ICC_ADF1, 0xa);
+				}
+			} else {
+				/* IOM 2 Mode */
+				cs->writeisac(cs, ICC_SPCR, val);
+				if (val)
+					cs->writeisac(cs, ICC_ADF1, 0x8);
+				else
+					cs->writeisac(cs, ICC_ADF1, 0x0);
+			}
+			break;
+		case (HW_DEACTIVATE | RESPONSE):
+			discard_queue(&cs->rq);
+			discard_queue(&cs->sq);
+			if (cs->tx_skb) {
+				dev_kfree_skb(cs->tx_skb);
+				cs->tx_skb = NULL;
+			}
+			if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+				del_timer(&cs->dbusytimer);
+			if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+				icc_sched_event(cs, D_CLEARBUSY);
+			break;
+		default:
+			if (cs->debug & L1_DEB_WARN)
+				debugl1(cs, "icc_l1hw unknown %04x", pr);
+			break;
+	}
+}
+
+void
+setstack_icc(struct PStack *st, struct IsdnCardState *cs)
+{
+	st->l1.l1hw = ICC_l1hw;
+}
+
+void 
+DC_Close_icc(struct IsdnCardState *cs) {
+	if (cs->dc.icc.mon_rx) {
+		kfree(cs->dc.icc.mon_rx);
+		cs->dc.icc.mon_rx = NULL;
+	}
+	if (cs->dc.icc.mon_tx) {
+		kfree(cs->dc.icc.mon_tx);
+		cs->dc.icc.mon_tx = NULL;
+	}
+}
+
+static void
+dbusy_timer_handler(struct IsdnCardState *cs)
+{
+	struct PStack *stptr;
+	int	rbch, star;
+
+	if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
+		rbch = cs->readisac(cs, ICC_RBCH);
+		star = cs->readisac(cs, ICC_STAR);
+		if (cs->debug) 
+			debugl1(cs, "D-Channel Busy RBCH %02x STAR %02x",
+				rbch, star);
+		if (rbch & ICC_RBCH_XAC) { /* D-Channel Busy */
+			test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
+			stptr = cs->stlist;
+			while (stptr != NULL) {
+				stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
+				stptr = stptr->next;
+			}
+		} else {
+			/* discard frame; reset transceiver */
+			test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
+			if (cs->tx_skb) {
+				dev_kfree_skb(cs->tx_skb);
+				cs->tx_cnt = 0;
+				cs->tx_skb = NULL;
+			} else {
+				printk(KERN_WARNING "HiSax: ICC D-Channel Busy no skb\n");
+				debugl1(cs, "D-Channel Busy no skb");
+			}
+			cs->writeisac(cs, ICC_CMDR, 0x01); /* Transmitter reset */
+			cs->irq_func(cs->irq, cs, NULL);
+		}
+	}
+}
+
+void __init
+initicc(struct IsdnCardState *cs)
+{
+	cs->tqueue.routine = (void *) (void *) icc_bh;
+	cs->setstack_d = setstack_icc;
+	cs->DC_Close = DC_Close_icc;
+	cs->dc.icc.mon_tx = NULL;
+	cs->dc.icc.mon_rx = NULL;
+	cs->dbusytimer.function = (void *) dbusy_timer_handler;
+	cs->dbusytimer.data = (long) cs;
+	init_timer(&cs->dbusytimer);
+  	cs->writeisac(cs, ICC_MASK, 0xff);
+  	cs->dc.icc.mocr = 0xaa;
+	if (test_bit(HW_IOM1, &cs->HW_Flags)) {
+		/* IOM 1 Mode */
+		cs->writeisac(cs, ICC_ADF2, 0x0);
+		cs->writeisac(cs, ICC_SPCR, 0xa);
+		cs->writeisac(cs, ICC_ADF1, 0x2);
+		cs->writeisac(cs, ICC_STCR, 0x70);
+		cs->writeisac(cs, ICC_MODE, 0xc9);
+	} else {
+		/* IOM 2 Mode */
+		if (!cs->dc.icc.adf2)
+			cs->dc.icc.adf2 = 0x80;
+		cs->writeisac(cs, ICC_ADF2, cs->dc.icc.adf2);
+		cs->writeisac(cs, ICC_SQXR, 0xa0);
+		cs->writeisac(cs, ICC_SPCR, 0x20);
+		cs->writeisac(cs, ICC_STCR, 0x70);
+		cs->writeisac(cs, ICC_MODE, 0xca);
+		cs->writeisac(cs, ICC_TIMR, 0x00);
+		cs->writeisac(cs, ICC_ADF1, 0x20);
+	}
+	ph_command(cs, ICC_CMD_RES);
+	cs->writeisac(cs, ICC_MASK, 0x0);
+	ph_command(cs, ICC_CMD_DI);
+}
+
+void __init
+clear_pending_icc_ints(struct IsdnCardState *cs)
+{
+	int val, eval;
+
+	val = cs->readisac(cs, ICC_STAR);
+	debugl1(cs, "ICC STAR %x", val);
+	val = cs->readisac(cs, ICC_MODE);
+	debugl1(cs, "ICC MODE %x", val);
+	val = cs->readisac(cs, ICC_ADF2);
+	debugl1(cs, "ICC ADF2 %x", val);
+	val = cs->readisac(cs, ICC_ISTA);
+	debugl1(cs, "ICC ISTA %x", val);
+	if (val & 0x01) {
+		eval = cs->readisac(cs, ICC_EXIR);
+		debugl1(cs, "ICC EXIR %x", eval);
+	}
+	val = cs->readisac(cs, ICC_CIR0);
+	debugl1(cs, "ICC CIR0 %x", val);
+	cs->dc.icc.ph_state = (val >> 2) & 0xf;
+	icc_sched_event(cs, D_L1STATECHANGE);
+	/* Disable all IRQ */
+	cs->writeisac(cs, ICC_MASK, 0xFF);
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/icc.h linux.19p18/drivers/isdn/hisax/icc.h
--- linux.vanilla/drivers/isdn/hisax/icc.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/hisax/icc.h	Wed Dec 13 22:08:04 2000
@@ -0,0 +1,73 @@
+// $Id: icc.h,v 1.2 2000/06/26 08:59:13 keil Exp $
+//-----------------------------------------------------------------------------
+//
+// ICC specific routines
+//
+// Author       Matt Henderson & Guy Ellis - Traverse Tecnologies Pty Ltd
+//              www.traverse.com.au
+//
+// 1999.7.14 Initial implementation of routines for Siemens ISDN 
+// Communication Controler PEB 2070 based on the ISAC routines 
+// written by Karsten Keil.
+//
+// This file is (c) under GNU PUBLIC LICENSE
+//
+//-----------------------------------------------------------------------------
+
+
+/* All Registers original Siemens Spec  */
+
+#define ICC_MASK 0x20
+#define ICC_ISTA 0x20
+#define ICC_STAR 0x21
+#define ICC_CMDR 0x21
+#define ICC_EXIR 0x24
+#define ICC_ADF2 0x39
+#define ICC_SPCR 0x30
+#define ICC_ADF1 0x38
+#define ICC_CIR0 0x31
+#define ICC_CIX0 0x31
+#define ICC_CIR1 0x33
+#define ICC_CIX1 0x33
+#define ICC_STCR 0x37
+#define ICC_MODE 0x22
+#define ICC_RSTA 0x27
+#define ICC_RBCL 0x25
+#define ICC_RBCH 0x2A
+#define ICC_TIMR 0x23
+#define ICC_SQXR 0x3b
+#define ICC_MOSR 0x3a
+#define ICC_MOCR 0x3a
+#define ICC_MOR0 0x32
+#define ICC_MOX0 0x32
+#define ICC_MOR1 0x34
+#define ICC_MOX1 0x34
+
+#define ICC_RBCH_XAC 0x80
+
+#define ICC_CMD_TIM    0x0
+#define ICC_CMD_RES    0x1
+#define ICC_CMD_DU     0x3
+#define ICC_CMD_EI1    0x4
+#define ICC_CMD_SSP    0x5
+#define ICC_CMD_DT     0x6
+#define ICC_CMD_AR     0x8
+#define ICC_CMD_ARL    0xA
+#define ICC_CMD_AI     0xC
+#define ICC_CMD_DI     0xF
+
+#define ICC_IND_DR     0x0
+#define ICC_IND_FJ     0x2
+#define ICC_IND_EI1    0x4
+#define ICC_IND_INT    0x6
+#define ICC_IND_PU     0x7
+#define ICC_IND_AR     0x8
+#define ICC_IND_ARL    0xA
+#define ICC_IND_AI     0xC
+#define ICC_IND_AIL    0xE
+#define ICC_IND_DC     0xF
+
+extern void ICCVersion(struct IsdnCardState *cs, char *s);
+extern void initicc(struct IsdnCardState *cs);
+extern void icc_interrupt(struct IsdnCardState *cs, u_char val);
+extern void clear_pending_icc_ints(struct IsdnCardState *cs);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/ipac.h linux.19p18/drivers/isdn/hisax/ipac.h
--- linux.vanilla/drivers/isdn/hisax/ipac.h	Fri Apr 21 12:46:10 2000
+++ linux.19p18/drivers/isdn/hisax/ipac.h	Wed Dec 13 22:08:04 2000
@@ -1,24 +1,10 @@
-/* $Id: ipac.h,v 1.4 1999/12/23 15:09:32 keil Exp $
-
+/* $Id: ipac.h,v 1.5 2000/06/26 08:59:13 keil Exp $
+ *
  * ipac.h   IPAC specific defines
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *
- *
- * $Log: ipac.h,v $
- * Revision 1.4  1999/12/23 15:09:32  keil
- * change email
- *
- * Revision 1.3  1998/04/15 16:48:09  keil
- * IPAC_ATX added
- *
- * Revision 1.2  1997/10/29 18:51:21  keil
- * New files
- *
- * Revision 1.1.2.1  1997/10/17 22:10:48  keil
- * new files on 2.0
- *
- *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/isac.c linux.19p18/drivers/isdn/hisax/isac.c
--- linux.vanilla/drivers/isdn/hisax/isac.c	Fri Apr 21 12:46:10 2000
+++ linux.19p18/drivers/isdn/hisax/isac.c	Mon Feb 12 15:09:50 2001
@@ -1,5 +1,5 @@
-/* $Id: isac.c,v 1.24 1999/10/14 20:25:28 keil Exp $
-
+/* $Id: isac.c,v 1.28 2000/11/24 17:05:37 kai Exp $
+ *
  * isac.c   ISAC specific routines
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
@@ -7,82 +7,6 @@
  *		This file is (c) under GNU PUBLIC LICENSE
  *		For changes and modifications please read
  *		../../../Documentation/isdn/HiSax.cert
- *
- * $Log: isac.c,v $
- * Revision 1.24  1999/10/14 20:25:28  keil
- * add a statistic for error monitoring
- *
- * Revision 1.23  1999/08/25 16:50:52  keil
- * Fix bugs which cause 2.3.14 hangs (waitqueue init)
- *
- * Revision 1.22  1999/08/09 19:04:40  keil
- * Fix race condition - Thanks to Christer Weinigel
- *
- * Revision 1.21  1999/07/12 21:05:17  keil
- * fix race in IRQ handling
- * added watchdog for lost IRQs
- *
- * Revision 1.20  1999/07/09 08:23:06  keil
- * Fix ISAC lost TX IRQ handling
- *
- * Revision 1.19  1999/07/01 08:11:43  keil
- * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
- *
- * Revision 1.18  1998/11/15 23:54:51  keil
- * changes from 2.0
- *
- * Revision 1.17  1998/08/13 23:36:37  keil
- * HiSax 3.1 - don't work stable with current LinkLevel
- *
- * Revision 1.16  1998/05/25 12:58:01  keil
- * HiSax golden code from certification, Don't use !!!
- * No leased lines, no X75, but many changes.
- *
- * Revision 1.15  1998/04/15 16:45:32  keil
- * new init code
- *
- * Revision 1.14  1998/04/10 10:35:26  paul
- * fixed (silly?) warnings from egcs on Alpha.
- *
- * Revision 1.13  1998/03/07 22:57:01  tsbogend
- * made HiSax working on Linux/Alpha
- *
- * Revision 1.12  1998/02/12 23:07:40  keil
- * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
- *
- * Revision 1.11  1998/02/09 10:54:49  keil
- * fixes for leased mode
- *
- * Revision 1.10  1998/02/02 13:37:37  keil
- * new init
- *
- * Revision 1.9  1997/11/06 17:09:07  keil
- * New 2.1 init code
- *
- * Revision 1.8  1997/10/29 19:00:03  keil
- * new layer1,changes for 2.1
- *
- * Revision 1.7  1997/10/01 09:21:37  fritz
- * Removed old compatibility stuff for 2.0.X kernels.
- * From now on, this code is for 2.1.X ONLY!
- * Old stuff is still in the separate branch.
- *
- * Revision 1.6  1997/08/15 17:47:08  keil
- * avoid oops because a uninitialised timer
- *
- * Revision 1.5  1997/08/07 17:48:49  keil
- * fix wrong parenthesis
- *
- * Revision 1.4  1997/07/30 17:11:59  keil
- * fixed Timer3
- *
- * Revision 1.3  1997/07/27 21:37:40  keil
- * T3 implemented; supervisor l1timer; B-channel TEST_LOOP
- *
- * Revision 1.2  1997/06/26 11:16:15  keil
- * first version
- *
- *
  */
 
 #define __NO_VERSION__
@@ -91,11 +15,12 @@
 #include "arcofi.h"
 #include "isdnl1.h"
 #include <linux/interrupt.h>
+#include <linux/init.h>
 
 #define DBUSY_TIMER_VALUE 80
 #define ARCOFI_USE 1
 
-static char *ISACVer[] HISAX_INITDATA =
+static char *ISACVer[]  =
 {"2086/2186 V1.1", "2085 B1", "2085 B2",
  "2085 V2.3"};
 
@@ -696,8 +621,8 @@
 	}
 }
 
-HISAX_INITFUNC(void
-initisac(struct IsdnCardState *cs))
+void 
+initisac(struct IsdnCardState *cs)
 {
 	cs->tqueue.routine = (void *) (void *) isac_bh;
 	cs->setstack_d = setstack_isac;
@@ -732,8 +657,8 @@
 	cs->writeisac(cs, ISAC_MASK, 0x0);
 }
 
-HISAX_INITFUNC(void
-clear_pending_isac_ints(struct IsdnCardState *cs))
+void 
+clear_pending_isac_ints(struct IsdnCardState *cs)
 {
 	int val, eval;
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/isac.h linux.19p18/drivers/isdn/hisax/isac.h
--- linux.vanilla/drivers/isdn/hisax/isac.h	Fri Apr 21 12:46:10 2000
+++ linux.19p18/drivers/isdn/hisax/isac.h	Wed Dec 13 22:08:04 2000
@@ -1,27 +1,10 @@
-/* $Id: isac.h,v 1.6 1999/12/23 15:09:32 keil Exp $
-
+/* $Id: isac.h,v 1.7 2000/06/26 08:59:13 keil Exp $
+ *
  * isac.h   ISAC specific defines
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *
- *
- * $Log: isac.h,v $
- * Revision 1.6  1999/12/23 15:09:32  keil
- * change email
- *
- * Revision 1.5  1998/05/25 12:58:03  keil
- * HiSax golden code from certification, Don't use !!!
- * No leased lines, no X75, but many changes.
- *
- * Revision 1.4  1997/10/29 19:09:34  keil
- * new L1
- *
- * Revision 1.3  1997/07/27 21:37:41  keil
- * T3 implemented; supervisor l1timer; B-channel TEST_LOOP
- *
- * Revision 1.2  1997/06/26 11:16:16  keil
- * first version
- *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/isar.c linux.19p18/drivers/isdn/hisax/isar.c
--- linux.vanilla/drivers/isdn/hisax/isar.c	Fri Apr 21 12:46:10 2000
+++ linux.19p18/drivers/isdn/hisax/isar.c	Mon Feb 12 15:09:50 2001
@@ -1,43 +1,15 @@
-/* $Id: isar.c,v 1.9 2000/01/20 19:47:45 keil Exp $
-
+/* $Id: isar.c,v 1.17 2000/11/24 17:05:37 kai Exp $
+ *
  * isar.c   ISAR (Siemens PSB 7110) specific routines
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *
- *
- * $Log: isar.c,v $
- * Revision 1.9  2000/01/20 19:47:45  keil
- * Add Fax Class 1 support
- *
- * Revision 1.8  1999/12/19 13:00:56  keil
- * Fix races in setting a new mode
- *
- * Revision 1.7  1999/10/14 20:25:29  keil
- * add a statistic for error monitoring
- *
- * Revision 1.6  1999/08/31 11:20:20  paul
- * various spelling corrections (new checksums may be needed, Karsten!)
- *
- * Revision 1.5  1999/08/25 16:59:55  keil
- * Make ISAR V32bis modem running
- * Make LL->HL interface open for additional commands
- *
- * Revision 1.4  1999/08/05 20:43:18  keil
- * ISAR analog modem support
- *
- * Revision 1.3  1999/07/01 08:11:45  keil
- * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
- *
- * Revision 1.2  1998/11/15 23:54:53  keil
- * changes from 2.0
- *
- * Revision 1.1  1998/08/13 23:33:47  keil
- * First version, only init
- *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isar.h"
 #include "isdnl1.h"
@@ -272,6 +244,14 @@
 			printk(KERN_ERR"isar_load_firmware copy_from_user ret %d\n", ret);
 			goto reterror;
 		}
+#ifdef __BIG_ENDIAN
+		sadr = (blk_head.sadr & 0xff)*256 + blk_head.sadr/256;
+		blk_head.sadr = sadr;
+		sadr = (blk_head.len & 0xff)*256 + blk_head.len/256;
+		blk_head.len = sadr;
+		sadr = (blk_head.d_key & 0xff)*256 + blk_head.d_key/256;
+		blk_head.d_key = sadr;
+#endif /* __BIG_ENDIAN */
 		cnt += BLK_HEAD_SIZE;
 		p += BLK_HEAD_SIZE;
 		printk(KERN_DEBUG"isar firmware block (%#x,%5d,%#x)\n",
@@ -313,8 +293,13 @@
 #endif
 			sadr += noc;
 			while(noc) {
+#ifdef __BIG_ENDIAN
+				*mp++ = *sp % 256;
+				*mp++ = *sp / 256;
+#else
 				*mp++ = *sp / 256;
 				*mp++ = *sp % 256;
+#endif /* __BIG_ENDIAN */
 				sp++;
 				noc--;
 			}
@@ -557,8 +542,9 @@
 			rcv_mbox(cs, ireg, ptr);
 			if (ireg->cmsb & HDLC_FED) {
 				if (bcs->hw.isar.rcvidx < 3) { /* last 2 bytes are the FCS */
-					printk(KERN_WARNING "ISAR: HDLC frame too short(%d)\n",
-						bcs->hw.isar.rcvidx);
+					if (cs->debug & L1_DEB_WARN)
+						debugl1(cs, "isar frame to short %d",
+							bcs->hw.isar.rcvidx);
 				} else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx-2))) {
 					printk(KERN_WARNING "ISAR: receive out of memory\n");
 				} else {
@@ -567,6 +553,7 @@
 					skb_queue_tail(&bcs->rqueue, skb);
 					isar_sched_event(bcs, B_RCVBUFREADY);
 				}
+				bcs->hw.isar.rcvidx = 0;
 			}
 		}
 		break;
@@ -635,13 +622,16 @@
 			bcs->hw.isar.rcvidx += ireg->clsb;
 			rcv_mbox(cs, ireg, ptr);
 			if (ireg->cmsb & HDLC_FED) {
+				int len = bcs->hw.isar.rcvidx +
+					dle_count(bcs->hw.isar.rcvbuf, bcs->hw.isar.rcvidx);
 				if (bcs->hw.isar.rcvidx < 3) { /* last 2 bytes are the FCS */
-					printk(KERN_WARNING "ISAR: HDLC frame too short(%d)\n",
-						bcs->hw.isar.rcvidx);
+					if (cs->debug & L1_DEB_WARN)
+						debugl1(cs, "isar frame to short %d",
+							bcs->hw.isar.rcvidx);
 				} else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx))) {
 					printk(KERN_WARNING "ISAR: receive out of memory\n");
 				} else {
-					memcpy(skb_put(skb, bcs->hw.isar.rcvidx),
+					insert_dle((u_char *)skb_put(skb, len),
 						bcs->hw.isar.rcvbuf,
 						bcs->hw.isar.rcvidx);
 					skb_queue_tail(&bcs->rqueue, skb);
@@ -649,8 +639,20 @@
 					send_DLE_ETX(bcs);
 					isar_sched_event(bcs, B_LL_OK);
 				}
+				bcs->hw.isar.rcvidx = 0;
 			}
 		}
+		if (ireg->cmsb & SART_NMD) { /* ABORT */
+			if (cs->debug & L1_DEB_WARN)
+				debugl1(cs, "isar_rcv_frame: no more data");
+			cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0);
+			bcs->hw.isar.rcvidx = 0;
+			send_DLE_ETX(bcs);
+			sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) |
+				ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL);
+			bcs->hw.isar.state = STFAX_ESCAPE;
+			isar_sched_event(bcs, B_LL_NOCARRIER);
+		}
 		break;
 	default:
 		printk(KERN_ERR"isar_rcv_frame mode (%x)error\n", bcs->mode);
@@ -1073,6 +1075,9 @@
 				debugl1(cs, "pump stev RSP_DISC");
 			if (bcs->hw.isar.state == STFAX_ESCAPE) {
 				switch(bcs->hw.isar.newcmd) {
+					case 0:
+						bcs->hw.isar.state = STFAX_READY;
+						break;
 					case PCTRL_CMD_FTH:
 					case PCTRL_CMD_FTM:
 						p1 = 10;
@@ -1082,13 +1087,14 @@
 						break;
 					case PCTRL_CMD_FRH:
 					case PCTRL_CMD_FRM:
-						p1 = bcs->hw.isar.newmod;
+						p1 = bcs->hw.isar.mod = bcs->hw.isar.newmod;
 						bcs->hw.isar.newmod = 0;
 						bcs->hw.isar.cmd = bcs->hw.isar.newcmd;
 						bcs->hw.isar.newcmd = 0;
 						sendmsg(cs, dps | ISAR_HIS_PUMPCTRL,
 							bcs->hw.isar.cmd, 1, &p1);
 						bcs->hw.isar.state = STFAX_LINE;
+						bcs->hw.isar.try_mod = 3;
 						break;
 					default:
 						if (cs->debug & L1_DEB_HSCX)
@@ -1114,13 +1120,14 @@
 			if (cs->debug & L1_DEB_HSCX)
 				debugl1(cs, "pump stev RSP_SILDET");
 			if (bcs->hw.isar.state == STFAX_SILDET) {
-				p1 = bcs->hw.isar.newmod;
+				p1 = bcs->hw.isar.mod = bcs->hw.isar.newmod;
 				bcs->hw.isar.newmod = 0;
 				bcs->hw.isar.cmd = bcs->hw.isar.newcmd;
 				bcs->hw.isar.newcmd = 0;
 				sendmsg(cs, dps | ISAR_HIS_PUMPCTRL,
 					bcs->hw.isar.cmd, 1, &p1);
 				bcs->hw.isar.state = STFAX_LINE;
+				bcs->hw.isar.try_mod = 3;
 			}
 			break;
 		case PSEV_RSP_SILOFF:
@@ -1128,6 +1135,17 @@
 				debugl1(cs, "pump stev RSP_SILOFF");
 			break;
 		case PSEV_RSP_FCERR:
+			if (bcs->hw.isar.state == STFAX_LINE) {
+				if (cs->debug & L1_DEB_HSCX)
+					debugl1(cs, "pump stev RSP_FCERR try %d",
+						bcs->hw.isar.try_mod);
+				if (bcs->hw.isar.try_mod--) {
+					sendmsg(cs, dps | ISAR_HIS_PUMPCTRL,
+						bcs->hw.isar.cmd, 1,
+						&bcs->hw.isar.mod);
+					break;
+				}
+			}
 			if (cs->debug & L1_DEB_HSCX)
 				debugl1(cs, "pump stev RSP_FCERR");
 			bcs->hw.isar.state = STFAX_ESCAPE;
@@ -1438,6 +1456,7 @@
 				bcs->hw.isar.mod = para;
 				bcs->hw.isar.newmod = 0;
 				bcs->hw.isar.newcmd = 0;
+				bcs->hw.isar.try_mod = 3; 
 			} else if ((bcs->hw.isar.state == STFAX_ACTIV) &&
 				(bcs->hw.isar.cmd == PCTRL_CMD_FTM) &&
 				(bcs->hw.isar.mod == para)) {
@@ -1460,6 +1479,7 @@
 				bcs->hw.isar.mod = para;
 				bcs->hw.isar.newmod = 0;
 				bcs->hw.isar.newcmd = 0;
+				bcs->hw.isar.try_mod = 3; 
 			} else if ((bcs->hw.isar.state == STFAX_ACTIV) &&
 				(bcs->hw.isar.cmd == PCTRL_CMD_FTH) &&
 				(bcs->hw.isar.mod == para)) {
@@ -1482,6 +1502,7 @@
 				bcs->hw.isar.mod = para;
 				bcs->hw.isar.newmod = 0;
 				bcs->hw.isar.newcmd = 0;
+				bcs->hw.isar.try_mod = 3; 
 			} else if ((bcs->hw.isar.state == STFAX_ACTIV) &&
 				(bcs->hw.isar.cmd == PCTRL_CMD_FRM) &&
 				(bcs->hw.isar.mod == para)) {
@@ -1504,6 +1525,7 @@
 				bcs->hw.isar.mod = para;
 				bcs->hw.isar.newmod = 0;
 				bcs->hw.isar.newcmd = 0;
+				bcs->hw.isar.try_mod = 3; 
 			} else if ((bcs->hw.isar.state == STFAX_ACTIV) &&
 				(bcs->hw.isar.cmd == PCTRL_CMD_FRH) &&
 				(bcs->hw.isar.mod == para)) {
@@ -1761,8 +1783,8 @@
 	return(0);
 }
 
-HISAX_INITFUNC(void 
-initisar(struct IsdnCardState *cs))
+void 
+initisar(struct IsdnCardState *cs)
 {
 	cs->bcs[0].BC_SetStack = setstack_isar;
 	cs->bcs[1].BC_SetStack = setstack_isar;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/isar.h linux.19p18/drivers/isdn/hisax/isar.h
--- linux.vanilla/drivers/isdn/hisax/isar.h	Fri Apr 21 12:46:10 2000
+++ linux.19p18/drivers/isdn/hisax/isar.h	Wed Dec 13 22:08:04 2000
@@ -1,32 +1,10 @@
-/* $Id: isar.h,v 1.7 2000/01/20 19:47:45 keil Exp $
+/* $Id: isar.h,v 1.9 2000/06/26 08:59:13 keil Exp $
+ *
  * isar.h   ISAR (Siemens PSB 7110) specific defines
  *
  * Author Karsten Keil (keil@isdn4linux.de)
  *
- *
- * $Log: isar.h,v $
- * Revision 1.7  2000/01/20 19:47:45  keil
- * Add Fax Class 1 support
- *
- * Revision 1.6  1999/10/14 20:25:29  keil
- * add a statistic for error monitoring
- *
- * Revision 1.5  1999/08/25 16:59:59  keil
- * Make ISAR V32bis modem running
- * Make LL->HL interface open for additional commands
- *
- * Revision 1.4  1999/08/05 20:43:20  keil
- * ISAR analog modem support
- *
- * Revision 1.3  1999/07/01 08:11:46  keil
- * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
- *
- * Revision 1.2  1998/11/15 23:54:54  keil
- * changes from 2.0
- *
- * Revision 1.1  1998/08/13 23:33:48  keil
- * First version, only init
- *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
  
@@ -208,7 +186,7 @@
 #define HDLC_ERROR	0x1c
 #define HDLC_ERR_FAD	0x10
 #define HDLC_ERR_RER	0x08
-#define HDLC_ERR_CER	0x01
+#define HDLC_ERR_CER	0x04
 #define SART_NMD	0x01
 
 #define BSTAT_RDM0	0x1
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/isdnl1.c linux.19p18/drivers/isdn/hisax/isdnl1.c
--- linux.vanilla/drivers/isdn/hisax/isdnl1.c	Fri Apr 21 12:46:10 2000
+++ linux.19p18/drivers/isdn/hisax/isdnl1.c	Mon Feb 12 15:09:50 2001
@@ -1,5 +1,5 @@
-/* $Id: isdnl1.c,v 2.37 2000/01/20 19:51:46 keil Exp $
-
+/* $Id: isdnl1.c,v 2.41.6.1 2000/12/10 22:01:04 kai Exp $
+ *
  * isdnl1.c     common low level stuff for Siemens Chipsetbased isdn cards
  *              based on the teles driver from Jan den Ouden
  *
@@ -13,150 +13,19 @@
  *              Fritz Elfert
  *              Beat Doebeli
  *
- *
- * $Log: isdnl1.c,v $
- * Revision 2.37  2000/01/20 19:51:46  keil
- * Fix AddTimer message
- * Change CONFIG defines
- *
- * Revision 2.36  1999/08/25 16:50:57  keil
- * Fix bugs which cause 2.3.14 hangs (waitqueue init)
- *
- * Revision 2.35  1999/08/22 20:27:07  calle
- * backported changes from kernel 2.3.14:
- * - several #include "config.h" gone, others come.
- * - "struct device" changed to "struct net_device" in 2.3.14, added a
- *   define in isdn_compat.h for older kernel versions.
- *
- * Revision 2.34  1999/07/09 13:50:15  keil
- * remove unused variable
- *
- * Revision 2.33  1999/07/09 13:34:33  keil
- * remove debug code
- *
- * Revision 2.32  1999/07/01 08:11:47  keil
- * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
- *
- * Revision 2.31  1998/11/15 23:54:56  keil
- * changes from 2.0
- *
- * Revision 2.30  1998/09/30 22:27:00  keil
- * Add init of l1.Flags
- *
- * Revision 2.29  1998/09/27 23:54:43  keil
- * cosmetics
- *
- * Revision 2.28  1998/09/27 12:52:23  keil
- * Fix against segfault, if the driver cannot allocate an IRQ channel
- *
- * Revision 2.27  1998/08/13 23:36:39  keil
- * HiSax 3.1 - don't work stable with current LinkLevel
- *
- * Revision 2.26  1998/07/15 15:01:31  calle
- * Support for AVM passive PCMCIA cards:
- *    A1 PCMCIA, FRITZ!Card PCMCIA and FRITZ!Card PCMCIA 2.0
- *
- * Revision 2.25  1998/05/25 14:10:09  keil
- * HiSax 3.0
- * X.75 and leased are working again.
- *
- * Revision 2.24  1998/05/25 12:58:04  keil
- * HiSax golden code from certification, Don't use !!!
- * No leased lines, no X75, but many changes.
- *
- * Revision 2.22  1998/04/15 16:40:13  keil
- * Add S0Box and Teles PCI support
- * Fix cardnr overwrite bug
- *
- * Revision 2.21  1998/04/10 10:35:28  paul
- * fixed (silly?) warnings from egcs on Alpha.
- *
- * Revision 2.20  1998/03/09 23:19:27  keil
- * Changes for PCMCIA
- *
- * Revision 2.18  1998/02/12 23:07:42  keil
- * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
- *
- * Revision 2.17  1998/02/11 17:28:07  keil
- * Niccy PnP/PCI support
- *
- * Revision 2.16  1998/02/09 18:46:08  keil
- * Support for Sedlbauer PCMCIA (Marcus Niemann)
- *
- * Revision 2.15  1998/02/09 10:54:51  keil
- * fixes for leased mode
- *
- * Revision 2.14  1998/02/03 23:31:31  keil
- * add AMD7930 support
- *
- * Revision 2.13  1998/02/02 13:33:02  keil
- * New card support
- *
- * Revision 2.12  1998/01/31 21:41:48  keil
- * changes for newer 2.1 kernels
- *
- * Revision 2.11  1997/11/12 15:01:23  keil
- * COMPAQ_ISA changes
- *
- * Revision 2.10  1997/11/08 21:35:48  keil
- * new l1 init
- *
- * Revision 2.9  1997/11/06 17:09:18  keil
- * New 2.1 init code
- *
- * Revision 2.8  1997/10/29 19:00:05  keil
- * new layer1,changes for 2.1
- *
- * Revision 2.7  1997/10/10 20:56:50  fritz
- * New HL interface.
- *
- * Revision 2.6  1997/09/12 10:05:16  keil
- * ISDN_CTRL_DEBUG define
- *
- * Revision 2.5  1997/09/11 17:24:45  keil
- * Add new cards
- *
- * Revision 2.4  1997/08/15 17:47:09  keil
- * avoid oops because a uninitialised timer
- *
- * Revision 2.3  1997/08/01 11:16:40  keil
- * cosmetics
- *
- * Revision 2.2  1997/07/30 17:11:08  keil
- * L1deactivated exported
- *
- * Revision 2.1  1997/07/27 21:35:38  keil
- * new layer1 interface
- *
- * Revision 2.0  1997/06/26 11:02:53  keil
- * New Layer and card interface
- *
- * Revision 1.15  1997/05/27 15:17:55  fritz
- * Added changes for recent 2.1.x kernels:
- *   changed return type of isdn_close
- *   queue_task_* -> queue_task
- *   clear/set_bit -> test_and_... where apropriate.
- *   changed type of hard_header_cache parameter.
- *
- * old changes removed KKe
- *
  */
 
-const char *l1_revision = "$Revision: 2.37 $";
+const char *l1_revision = "$Revision: 2.41.6.1 $";
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isdnl1.h"
 
 #define TIMER3_VALUE 7000
 
-static
-struct Fsm l1fsm_b =
-{NULL, 0, 0, NULL, NULL};
-
-static
-struct Fsm l1fsm_d =
-{NULL, 0, 0, NULL, NULL};
+static struct Fsm l1fsm_b;
+static struct Fsm l1fsm_s;
 
 enum {
 	ST_L1_F2,
@@ -168,9 +37,9 @@
 	ST_L1_F8,
 };
 
-#define L1D_STATE_COUNT (ST_L1_F8+1)
+#define L1S_STATE_COUNT (ST_L1_F8+1)
 
-static char *strL1DState[] =
+static char *strL1SState[] =
 {
 	"ST_L1_F2",
 	"ST_L1_F3",
@@ -181,6 +50,29 @@
 	"ST_L1_F8",
 };
 
+#ifdef HISAX_UINTERFACE
+static
+struct Fsm l1fsm_u =
+{NULL, 0, 0, NULL, NULL};
+
+enum {
+	ST_L1_RESET,
+	ST_L1_DEACT,
+	ST_L1_SYNC2,
+	ST_L1_TRANS,
+};
+
+#define L1U_STATE_COUNT (ST_L1_TRANS+1)
+
+static char *strL1UState[] =
+{
+	"ST_L1_RESET",
+	"ST_L1_DEACT",
+	"ST_L1_SYNC2",
+	"ST_L1_TRANS",
+};
+#endif
+
 enum {
 	ST_L1_NULL,
 	ST_L1_WAIT_ACT,
@@ -451,7 +343,6 @@
 
 	bcs->cs = cs;
 	bcs->channel = bc;
-	bcs->tqueue.next = 0;
 	bcs->tqueue.sync = 0;
 	bcs->tqueue.routine = (void *) (void *) BChannel_bh;
 	bcs->tqueue.data = bcs;
@@ -559,7 +450,7 @@
 }
 
 static void
-l1_deact_req(struct FsmInst *fi, int event, void *arg)
+l1_deact_req_s(struct FsmInst *fi, int event, void *arg)
 {
 	struct PStack *st = fi->userdata;
 
@@ -569,7 +460,7 @@
 }
 
 static void
-l1_power_up(struct FsmInst *fi, int event, void *arg)
+l1_power_up_s(struct FsmInst *fi, int event, void *arg)
 {
 	struct PStack *st = fi->userdata;
 
@@ -599,7 +490,12 @@
 {
 	struct PStack *st = fi->userdata;
 
-	FsmChangeState(fi, ST_L1_F6);
+#ifdef HISAX_UINTERFACE
+	if (test_bit(FLG_L1_UINT, &st->l1.Flags))
+		FsmChangeState(fi, ST_L1_SYNC2);
+	else
+#endif
+		FsmChangeState(fi, ST_L1_F6);
 	st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL);
 }
 
@@ -608,7 +504,12 @@
 {
 	struct PStack *st = fi->userdata;
 
-	FsmChangeState(fi, ST_L1_F7);
+#ifdef HISAX_UINTERFACE
+	if (test_bit(FLG_L1_UINT, &st->l1.Flags))
+		FsmChangeState(fi, ST_L1_TRANS);
+	else
+#endif
+		FsmChangeState(fi, ST_L1_F7);
 	st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL);
 	if (test_and_clear_bit(FLG_L1_DEACTTIMER, &st->l1.Flags))
 		FsmDelTimer(&st->l1.timer, 4);
@@ -628,6 +529,10 @@
 	test_and_clear_bit(FLG_L1_T3RUN, &st->l1.Flags);	
 	if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags))
 		L1deactivated(st->l1.hardware);
+
+#ifdef HISAX_UINTERFACE
+	if (!test_bit(FLG_L1_UINT, &st->l1.Flags))
+#endif
 	if (st->l1.l1m.state != ST_L1_F6) {
 		FsmChangeState(fi, ST_L1_F3);
 		st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL);
@@ -656,7 +561,7 @@
 }
 
 static void
-l1_activate(struct FsmInst *fi, int event, void *arg)
+l1_activate_s(struct FsmInst *fi, int event, void *arg)
 {
 	struct PStack *st = fi->userdata;
                 
@@ -674,9 +579,9 @@
 	}
 }
 
-static struct FsmNode L1DFnList[] HISAX_INITDATA =
+static struct FsmNode L1SFnList[] __initdata =
 {
-	{ST_L1_F3, EV_PH_ACTIVATE, l1_activate},
+	{ST_L1_F3, EV_PH_ACTIVATE, l1_activate_s},
 	{ST_L1_F6, EV_PH_ACTIVATE, l1_activate_no},
 	{ST_L1_F8, EV_PH_ACTIVATE, l1_activate_no},
 	{ST_L1_F3, EV_RESET_IND, l1_reset},
@@ -691,10 +596,10 @@
 	{ST_L1_F6, EV_DEACT_CNF, l1_deact_cnf},
 	{ST_L1_F7, EV_DEACT_CNF, l1_deact_cnf},
 	{ST_L1_F8, EV_DEACT_CNF, l1_deact_cnf},
-	{ST_L1_F6, EV_DEACT_IND, l1_deact_req},
-	{ST_L1_F7, EV_DEACT_IND, l1_deact_req},
-	{ST_L1_F8, EV_DEACT_IND, l1_deact_req},
-	{ST_L1_F3, EV_POWER_UP, l1_power_up},
+	{ST_L1_F6, EV_DEACT_IND, l1_deact_req_s},
+	{ST_L1_F7, EV_DEACT_IND, l1_deact_req_s},
+	{ST_L1_F8, EV_DEACT_IND, l1_deact_req_s},
+	{ST_L1_F3, EV_POWER_UP, l1_power_up_s},
 	{ST_L1_F4, EV_RSYNC_IND, l1_go_F5},
 	{ST_L1_F6, EV_RSYNC_IND, l1_go_F8},
 	{ST_L1_F7, EV_RSYNC_IND, l1_go_F8},
@@ -722,7 +627,68 @@
 	{ST_L1_F8, EV_TIMER_DEACT, l1_timer_deact},
 };
 
-#define L1D_FN_COUNT (sizeof(L1DFnList)/sizeof(struct FsmNode))
+#define L1S_FN_COUNT (sizeof(L1SFnList)/sizeof(struct FsmNode))
+
+#ifdef HISAX_UINTERFACE
+static void
+l1_deact_req_u(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack *st = fi->userdata;
+
+	FsmChangeState(fi, ST_L1_RESET);
+	FsmRestartTimer(&st->l1.timer, 550, EV_TIMER_DEACT, NULL, 2);
+	test_and_set_bit(FLG_L1_DEACTTIMER, &st->l1.Flags);
+	st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL);
+}
+
+static void
+l1_power_up_u(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack *st = fi->userdata;
+
+	FsmRestartTimer(&st->l1.timer, TIMER3_VALUE, EV_TIMER3, NULL, 2);
+	test_and_set_bit(FLG_L1_T3RUN, &st->l1.Flags);
+}
+
+static void
+l1_info0_ind(struct FsmInst *fi, int event, void *arg)
+{
+	FsmChangeState(fi, ST_L1_DEACT);
+}
+
+static void
+l1_activate_u(struct FsmInst *fi, int event, void *arg)
+{
+	struct PStack *st = fi->userdata;
+                
+	st->l1.l1hw(st, HW_INFO1 | REQUEST, NULL);
+}
+
+static struct FsmNode L1UFnList[] __initdata =
+{
+	{ST_L1_RESET, EV_DEACT_IND, l1_deact_req_u},
+	{ST_L1_DEACT, EV_DEACT_IND, l1_deact_req_u},
+	{ST_L1_SYNC2, EV_DEACT_IND, l1_deact_req_u},
+	{ST_L1_TRANS, EV_DEACT_IND, l1_deact_req_u},
+	{ST_L1_DEACT, EV_PH_ACTIVATE, l1_activate_u},
+	{ST_L1_DEACT, EV_POWER_UP, l1_power_up_u},
+	{ST_L1_DEACT, EV_INFO2_IND, l1_info2_ind},
+	{ST_L1_TRANS, EV_INFO2_IND, l1_info2_ind},
+	{ST_L1_RESET, EV_DEACT_CNF, l1_info0_ind},
+	{ST_L1_DEACT, EV_INFO4_IND, l1_info4_ind},
+	{ST_L1_SYNC2, EV_INFO4_IND, l1_info4_ind},
+	{ST_L1_RESET, EV_INFO4_IND, l1_info4_ind},
+	{ST_L1_DEACT, EV_TIMER3, l1_timer3},
+	{ST_L1_SYNC2, EV_TIMER3, l1_timer3},
+	{ST_L1_TRANS, EV_TIMER_ACT, l1_timer_act},
+	{ST_L1_DEACT, EV_TIMER_DEACT, l1_timer_deact},
+	{ST_L1_SYNC2, EV_TIMER_DEACT, l1_timer_deact},
+	{ST_L1_RESET, EV_TIMER_DEACT, l1_timer_deact},
+};
+
+#define L1U_FN_COUNT (sizeof(L1UFnList)/sizeof(struct FsmNode))
+
+#endif
 
 static void
 l1b_activate(struct FsmInst *fi, int event, void *arg)
@@ -760,7 +726,7 @@
 	st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL);
 }
 
-static struct FsmNode L1BFnList[] HISAX_INITDATA =
+static struct FsmNode L1BFnList[] __initdata =
 {
 	{ST_L1_NULL, EV_PH_ACTIVATE, l1b_activate},
 	{ST_L1_WAIT_ACT, EV_TIMER_ACT, l1b_timer_act},
@@ -770,13 +736,21 @@
 
 #define L1B_FN_COUNT (sizeof(L1BFnList)/sizeof(struct FsmNode))
 
-HISAX_INITFUNC(void Isdnl1New(void))
+void __init 
+Isdnl1New(void)
 {
-	l1fsm_d.state_count = L1D_STATE_COUNT;
-	l1fsm_d.event_count = L1_EVENT_COUNT;
-	l1fsm_d.strEvent = strL1Event;
-	l1fsm_d.strState = strL1DState;
-	FsmNew(&l1fsm_d, L1DFnList, L1D_FN_COUNT);
+#ifdef HISAX_UINTERFACE
+	l1fsm_u.state_count = L1U_STATE_COUNT;
+	l1fsm_u.event_count = L1_EVENT_COUNT;
+	l1fsm_u.strEvent = strL1Event;
+	l1fsm_u.strState = strL1UState;
+	FsmNew(&l1fsm_u, L1UFnList, L1U_FN_COUNT);
+#endif
+	l1fsm_s.state_count = L1S_STATE_COUNT;
+	l1fsm_s.event_count = L1_EVENT_COUNT;
+	l1fsm_s.strEvent = strL1Event;
+	l1fsm_s.strState = strL1SState;
+	FsmNew(&l1fsm_s, L1SFnList, L1S_FN_COUNT);
 	l1fsm_b.state_count = L1B_STATE_COUNT;
 	l1fsm_b.event_count = L1_EVENT_COUNT;
 	l1fsm_b.strEvent = strL1Event;
@@ -786,7 +760,10 @@
 
 void Isdnl1Free(void)
 {
-	FsmFree(&l1fsm_d);
+#ifdef HISAX_UINTERFACE
+	FsmFree(&l1fsm_u);
+#endif
+	FsmFree(&l1fsm_s);
 	FsmFree(&l1fsm_b);
 }
 
@@ -804,7 +781,7 @@
 		case (PH_ACTIVATE | REQUEST):
 			if (cs->debug)
 				debugl1(cs, "PH_ACTIVATE_REQ %s",
-					strL1DState[st->l1.l1m.state]);
+					st->l1.l1m.fsm->strState[st->l1.l1m.state]);
 			if (test_bit(FLG_L1_ACTIVATED, &st->l1.Flags))
 				st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL);
 			else {
@@ -884,8 +861,16 @@
 {
 	st->l1.hardware = cs;
 	st->protocol = cs->protocol;
-	st->l1.l1m.fsm = &l1fsm_d;
+	st->l1.l1m.fsm = &l1fsm_s;
 	st->l1.l1m.state = ST_L1_F3;
+	st->l1.Flags = 0;
+#ifdef HISAX_UINTERFACE
+	if (test_bit(FLG_HW_L1_UINT, &cs->HW_Flags)) {
+		st->l1.l1m.fsm = &l1fsm_u;
+		st->l1.l1m.state = ST_L1_RESET;
+		st->l1.Flags = FLG_L1_UINT;
+	}
+#endif
 	st->l1.l1m.debug = cs->debug;
 	st->l1.l1m.userdata = st;
 	st->l1.l1m.userint = 0;
@@ -895,7 +880,6 @@
 	setstack_manager(st);
 	st->l1.stlistp = &(cs->stlist);
 	st->l2.l2l1  = dch_l2l1;
-	st->l1.Flags = 0;
 	cs->setstack_d(st, cs);
 }
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/isdnl1.h linux.19p18/drivers/isdn/hisax/isdnl1.h
--- linux.vanilla/drivers/isdn/hisax/isdnl1.h	Fri Apr 21 12:46:10 2000
+++ linux.19p18/drivers/isdn/hisax/isdnl1.h	Wed Dec 13 22:08:04 2000
@@ -1,34 +1,8 @@
-/* $Id: isdnl1.h,v 2.8 1998/11/15 23:54:59 keil Exp $
-
- * $Log: isdnl1.h,v $
- * Revision 2.8  1998/11/15 23:54:59  keil
- * changes from 2.0
+/* $Id: isdnl1.h,v 2.9 2000/06/26 08:59:13 keil Exp $
  *
- * Revision 2.7  1998/09/30 22:21:55  keil
- * cosmetics
- *
- * Revision 2.6  1998/05/25 12:58:06  keil
- * HiSax golden code from certification, Don't use !!!
- * No leased lines, no X75, but many changes.
- *
- * Revision 2.5  1998/02/02 13:36:58  keil
- * more debug
- *
- * Revision 2.4  1997/11/08 21:35:49  keil
- * new l1 init
- *
- * Revision 2.3  1997/10/29 19:07:53  keil
- * changes for 2.1
- *
- * Revision 2.2  1997/07/30 17:11:09  keil
- * L1deactivated exported
- *
- * Revision 2.1  1997/07/27 21:43:58  keil
- * new l1 interface
- *
- * Revision 2.0  1997/06/26 11:02:55  keil
- * New Layer and card interface
+ * Layer 1 defines
  *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/isdnl2.c linux.19p18/drivers/isdn/hisax/isdnl2.c
--- linux.vanilla/drivers/isdn/hisax/isdnl2.c	Fri Apr 21 12:46:10 2000
+++ linux.19p18/drivers/isdn/hisax/isdnl2.c	Mon Feb 12 15:09:50 2001
@@ -1,5 +1,5 @@
-/* $Id: isdnl2.c,v 2.20 1999/08/25 16:52:04 keil Exp $
-
+/* $Id: isdnl2.c,v 2.25 2000/11/24 17:05:38 kai Exp $
+ *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
  *
@@ -10,86 +10,17 @@
  * Thanks to    Jan den Ouden
  *              Fritz Elfert
  *
- * $Log: isdnl2.c,v $
- * Revision 2.20  1999/08/25 16:52:04  keil
- * Make gcc on AXP happy
- *
- * Revision 2.19  1999/08/05 20:40:26  keil
- * Fix interlayer communication
- *
- * Revision 2.18  1999/07/21 14:46:16  keil
- * changes from EICON certification
- *
- * Revision 2.17  1999/07/01 08:11:50  keil
- * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
- *
- * Revision 2.16  1998/11/15 23:55:01  keil
- * changes from 2.0
- *
- * Revision 2.15  1998/08/13 23:36:42  keil
- * HiSax 3.1 - don't work stable with current LinkLevel
- *
- * Revision 2.14  1998/06/19 15:19:18  keil
- * fix LAPB tx_cnt for none I-frames
- *
- * Revision 2.13  1998/06/18 23:17:20  keil
- * LAPB bugfix
- *
- * Revision 2.12  1998/05/25 14:10:12  keil
- * HiSax 3.0
- * X.75 and leased are working again.
- *
- * Revision 2.11  1998/05/25 12:58:08  keil
- * HiSax golden code from certification, Don't use !!!
- * No leased lines, no X75, but many changes.
- *
- * Revision 2.9  1998/04/10 10:35:30  paul
- * fixed (silly?) warnings from egcs on Alpha.
- *
- * Revision 2.8  1998/03/07 22:57:04  tsbogend
- * made HiSax working on Linux/Alpha
- *
- * Revision 2.7  1998/02/12 23:07:47  keil
- * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
- *
- * Revision 2.6  1998/02/02 13:36:15  keil
- * bugfix X.75 win calculation
- *
- * Revision 2.5  1997/11/06 17:09:22  keil
- * New 2.1 init code
- *
- * Revision 2.4  1997/10/29 19:02:01  keil
- * new LL interface
- *
- * Revision 2.3  1997/10/01 09:21:39  fritz
- * Removed old compatibility stuff for 2.0.X kernels.
- * From now on, this code is for 2.1.X ONLY!
- * Old stuff is still in the separate branch.
- *
- * Revision 2.2  1997/07/31 11:49:05  keil
- * Error handling for no TEI assign
- *
- * Revision 2.1  1997/07/27 21:34:38  keil
- * cosmetics
- *
- * Revision 2.0  1997/06/26 11:07:29  keil
- * New q.921 and X.75 Layer2
- *
- *
- *  Old log removed KKe
- *
  */
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isdnl2.h"
 
-const char *l2_revision = "$Revision: 2.20 $";
+const char *l2_revision = "$Revision: 2.25 $";
 
 static void l2m_debug(struct FsmInst *fi, char *fmt, ...);
 
-static
-struct Fsm l2fsm =
-{NULL, 0, 0, NULL, NULL};
+static struct Fsm l2fsm;
 
 enum {
 	ST_L2_1,
@@ -361,7 +292,7 @@
 int
 iframe_error(struct PStack *st, struct sk_buff *skb)
 {
-	int i = l2addrsize(&st->l2) + (test_bit(FLG_MOD128, &st->l2.flag) ? 1 : 0);
+	int i = l2addrsize(&st->l2) + (test_bit(FLG_MOD128, &st->l2.flag) ? 2 : 1);
 	int rsp = *skb->data & 0x2;
 
 	if (test_bit(FLG_ORIG, &st->l2.flag))
@@ -371,7 +302,7 @@
 		return 'L';
 
 
-	if (skb->len <= i)
+	if (skb->len < i)
 		return 'N';
 
 	if ((skb->len - i) > st->l2.maxlen)
@@ -1603,7 +1534,7 @@
 	test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
 }
 
-static struct FsmNode L2FnList[] HISAX_INITDATA =
+static struct FsmNode L2FnList[] __initdata =
 {
 	{ST_L2_1, EV_L2_DL_ESTABLISH_REQ, l2_mdl_assign},
 	{ST_L2_2, EV_L2_DL_ESTABLISH_REQ, l2_go_st3},
@@ -1900,8 +1831,8 @@
 {
 }
 
-HISAX_INITFUNC(void
-Isdnl2New(void))
+void __init
+Isdnl2New(void)
 {
 	l2fsm.state_count = L2_STATE_COUNT;
 	l2fsm.event_count = L2_EVENT_COUNT;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/isdnl2.h linux.19p18/drivers/isdn/hisax/isdnl2.h
--- linux.vanilla/drivers/isdn/hisax/isdnl2.h	Fri Apr 21 12:46:10 2000
+++ linux.19p18/drivers/isdn/hisax/isdnl2.h	Wed Dec 13 22:08:04 2000
@@ -1,4 +1,10 @@
-/* isdnl2.h */
+/* $Id: isdnl2.h,v 1.3 2000/06/26 08:59:13 keil Exp $
+ *
+ * Layer 2 defines
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
 
 #define RR     0x01
 #define RNR    0x05
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/isdnl3.c linux.19p18/drivers/isdn/hisax/isdnl3.c
--- linux.vanilla/drivers/isdn/hisax/isdnl3.c	Fri Apr 21 12:46:10 2000
+++ linux.19p18/drivers/isdn/hisax/isdnl3.c	Tue Feb 13 18:48:23 2001
@@ -1,5 +1,5 @@
-/* $Id: isdnl3.c,v 2.10 1999/07/21 14:46:19 keil Exp $
-
+/* $Id: isdnl3.c,v 2.17.6.1 2001/01/08 17:09:20 kai Exp $
+ *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
  *
@@ -10,69 +10,17 @@
  * Thanks to    Jan den Ouden
  *              Fritz Elfert
  *
- * $Log: isdnl3.c,v $
- * Revision 2.10  1999/07/21 14:46:19  keil
- * changes from EICON certification
- *
- * Revision 2.9  1999/07/01 08:11:53  keil
- * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
- *
- * Revision 2.8  1998/11/15 23:55:04  keil
- * changes from 2.0
- *
- * Revision 2.7  1998/05/25 14:10:15  keil
- * HiSax 3.0
- * X.75 and leased are working again.
- *
- * Revision 2.6  1998/05/25 12:58:11  keil
- * HiSax golden code from certification, Don't use !!!
- * No leased lines, no X75, but many changes.
- *
- * Revision 2.5  1998/02/12 23:07:52  keil
- * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
- *
- * Revision 2.4  1997/11/06 17:09:25  keil
- * New 2.1 init code
- *
- * Revision 2.3  1997/10/29 19:07:53  keil
- * changes for 2.1
- *
- * Revision 2.2  1997/10/01 09:21:41  fritz
- * Removed old compatibility stuff for 2.0.X kernels.
- * From now on, this code is for 2.1.X ONLY!
- * Old stuff is still in the separate branch.
- *
- * Revision 2.1  1997/08/03 14:36:32  keil
- * Implement RESTART procedure
- *
- * Revision 2.0  1997/07/27 21:15:42  keil
- * New Callref based layer3
- *
- * Revision 1.11  1997/06/26 11:11:44  keil
- * SET_SKBFREE now on creation of a SKB
- *
- * Revision 1.10  1997/04/06 22:54:16  keil
- * Using SKB's
- *
- * Revision 1.9  1997/03/25 23:11:25  keil
- * US NI-1 protocol
- *
- * Revision 1.8  1997/03/21 18:53:44  keil
- * Report no protocol error to syslog too
- *
- * Remove old logs /KKe
- *
  */
+
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isdnl3.h"
 #include <linux/config.h>
 
-const char *l3_revision = "$Revision: 2.10 $";
+const char *l3_revision = "$Revision: 2.17.6.1 $";
 
-static
-struct Fsm l3fsm =
-{NULL, 0, 0, NULL, NULL};
+static struct Fsm l3fsm;
 
 enum {
 	ST_L3_LC_REL,
@@ -234,7 +182,7 @@
 L3AddTimer(struct L3Timer *t,
 	   int millisec, int event)
 {
-	if (t->tl.next || t->tl.prev) {
+	if (timer_pending(&t->tl)) {
 		printk(KERN_WARNING "L3AddTimer: timer already active!\n");
 		return -1;
 	}
@@ -286,7 +234,7 @@
 extern void setstack_dss1(struct PStack *st);
 #endif
 
-#ifdef        CONFIG_HISAX_NI1
+#ifdef  CONFIG_HISAX_NI1
 extern void setstack_ni1(struct PStack *st);
 #endif
 
@@ -355,7 +303,10 @@
 				if (!skb_queue_len(&p->st->l3.squeue)) {
 					if (p->debug)
 						l3_debug(p->st, "release_l3_process: release link");
-					FsmEvent(&p->st->l3.l3m, EV_RELEASE_REQ, NULL);
+					if (p->st->protocol != ISDN_PTYPE_NI1)
+						FsmEvent(&p->st->l3.l3m, EV_RELEASE_REQ, NULL);
+					else
+						FsmEvent(&p->st->l3.l3m, EV_RELEASE_IND, NULL);
 				} else {
 					if (p->debug)
 						l3_debug(p->st, "release_l3_process: not release link");
@@ -375,10 +326,13 @@
 l3ml3p(struct PStack *st, int pr)
 {
 	struct l3_process *p = st->l3.proc;
+	struct l3_process *np;
 
 	while (p) {
+		/* p might be kfreed under us, so we need to save where we want to go on */
+		np = p->next;
 		st->l3.l3ml3(st, pr, p);
-		p = p->next;
+		p = np;
 	}
 }
 
@@ -405,7 +359,7 @@
 		setstack_dss1(st);
 	} else
 #endif
-#ifdef        CONFIG_HISAX_NI1
+#ifdef  CONFIG_HISAX_NI1
 	if (st->protocol == ISDN_PTYPE_NI1) {
 		setstack_ni1(st);
 	} else
@@ -532,6 +486,18 @@
 }
 
 static void
+lc_start_delay_check(struct FsmInst *fi, int event, void *arg)
+/* 20/09/00 - GE timer not user for NI-1 as layer 2 should stay up */
+{
+       struct PStack *st = fi->userdata;
+
+       FsmChangeState(fi, ST_L3_LC_REL_DELAY);
+       /* 19/09/00 - GE timer not user for NI-1 */
+       if (st->protocol != ISDN_PTYPE_NI1) 
+       		FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 50);
+}
+
+static void
 lc_release_req(struct FsmInst *fi, int event, void *arg)
 {
 	struct PStack *st = fi->userdata;
@@ -570,7 +536,7 @@
 
 
 /* *INDENT-OFF* */
-static struct FsmNode L3FnList[] HISAX_INITDATA =
+static struct FsmNode L3FnList[] __initdata =
 {
 	{ST_L3_LC_REL,		EV_ESTABLISH_REQ,	lc_activate},
 	{ST_L3_LC_REL,		EV_ESTABLISH_IND,	lc_connect},
@@ -579,7 +545,7 @@
 	{ST_L3_LC_ESTAB_WAIT,	EV_RELEASE_REQ,		lc_start_delay},
 	{ST_L3_LC_ESTAB_WAIT,	EV_RELEASE_IND,		lc_release_ind},
 	{ST_L3_LC_ESTAB,	EV_RELEASE_IND,		lc_release_ind},
-	{ST_L3_LC_ESTAB,	EV_RELEASE_REQ,		lc_start_delay},
+	{ST_L3_LC_ESTAB,	EV_RELEASE_REQ,		lc_start_delay_check},
         {ST_L3_LC_REL_DELAY,    EV_RELEASE_IND,         lc_release_ind},
         {ST_L3_LC_REL_DELAY,    EV_ESTABLISH_REQ,       lc_connected},
         {ST_L3_LC_REL_DELAY,    EV_TIMEOUT,             lc_release_req},
@@ -593,7 +559,6 @@
 void
 l3_msg(struct PStack *st, int pr, void *arg)
 {
-	
 	switch (pr) {
 		case (DL_DATA | REQUEST):
 			if (st->l3.l3m.state == ST_L3_LC_ESTAB) {
@@ -601,7 +566,7 @@
 			} else {
 				struct sk_buff *skb = arg;
 
-				skb_queue_head(&st->l3.squeue, skb);
+				skb_queue_tail(&st->l3.squeue, skb);
 				FsmEvent(&st->l3.l3m, EV_ESTABLISH_REQ, NULL); 
 			}
 			break;
@@ -626,8 +591,8 @@
 	}
 }
 
-HISAX_INITFUNC(void
-Isdnl3New(void))
+void __init
+Isdnl3New(void)
 {
 	l3fsm.state_count = L3_STATE_COUNT;
 	l3fsm.event_count = L3_EVENT_COUNT;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/isdnl3.h linux.19p18/drivers/isdn/hisax/isdnl3.h
--- linux.vanilla/drivers/isdn/hisax/isdnl3.h	Fri Apr 21 12:46:10 2000
+++ linux.19p18/drivers/isdn/hisax/isdnl3.h	Wed Dec 13 22:08:13 2000
@@ -1,38 +1,6 @@
-/* $Id: isdnl3.h,v 2.5 1999/07/25 16:18:32 keil Exp $
-
- * $Log: isdnl3.h,v $
- * Revision 2.5  1999/07/25 16:18:32  keil
- * Fix Suspend/Resume
- *
- * Revision 2.4  1999/07/01 08:11:54  keil
- * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
- *
- * Revision 2.3  1998/11/15 23:55:06  keil
- * changes from 2.0
- *
- * Revision 2.2  1998/05/25 14:10:17  keil
- * HiSax 3.0
- * X.75 and leased are working again.
- *
- * Revision 2.1  1998/05/25 12:58:13  keil
- * HiSax golden code from certification, Don't use !!!
- * No leased lines, no X75, but many changes.
- *
- * Revision 2.0  1997/07/27 21:15:42  keil
- * New Callref based layer3
- *
- * Revision 1.4  1997/06/26 11:20:57  keil
- * ?
- *
- * Revision 1.3  1997/04/06 22:54:17  keil
- * Using SKB's
- *
- * Revision 1.2  1997/01/21 22:31:28  keil
- * new statemachine; L3 timers
- *
- * Revision 1.1  1996/10/13 20:03:47  keil
- * Initial revision
+/* $Id: isdnl3.h,v 2.6 2000/06/26 08:59:13 keil Exp $
  *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/isurf.c linux.19p18/drivers/isdn/hisax/isurf.c
--- linux.vanilla/drivers/isdn/hisax/isurf.c	Fri Apr 21 12:46:10 2000
+++ linux.19p18/drivers/isdn/hisax/isurf.c	Mon Feb 12 15:09:50 2001
@@ -1,42 +1,15 @@
-/* $Id: isurf.c,v 1.8 1999/12/19 13:09:42 keil Exp $
-
+/* $Id: isurf.c,v 1.10 2000/11/24 17:05:38 kai Exp $
+ *
  * isurf.c  low level stuff for Siemens I-Surf/I-Talk cards
  *
  * Author     Karsten Keil (keil@isdn4linux.de)
  *
- * $Log: isurf.c,v $
- * Revision 1.8  1999/12/19 13:09:42  keil
- * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
- * signal proof delays
- *
- * Revision 1.7  1999/11/14 23:37:03  keil
- * new ISA memory mapped IO
- *
- * Revision 1.6  1999/09/04 06:20:06  keil
- * Changes from kernel set_current_state()
- *
- * Revision 1.5  1999/08/25 17:00:02  keil
- * Make ISAR V32bis modem running
- * Make LL->HL interface open for additional commands
- *
- * Revision 1.4  1999/08/22 20:27:09  calle
- * backported changes from kernel 2.3.14:
- * - several #include "config.h" gone, others come.
- * - "struct device" changed to "struct net_device" in 2.3.14, added a
- *   define in isdn_compat.h for older kernel versions.
- *
- * Revision 1.3  1999/07/12 21:05:18  keil
- * fix race in IRQ handling
- * added watchdog for lost IRQs
- *
- * Revision 1.2  1999/07/01 08:07:56  keil
- * Initial version
- *
- *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "isar.h"
@@ -44,7 +17,7 @@
 
 extern const char *CardType[];
 
-static const char *ISurf_revision = "$Revision: 1.8 $";
+static const char *ISurf_revision = "$Revision: 1.10 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -164,10 +137,10 @@
 	byteout(cs->hw.isurf.reset, chips); /* Reset On */
 	save_flags(flags);
 	sti();
-	current->state = TASK_UNINTERRUPTIBLE;
+	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout((10*HZ)/1000);
 	byteout(cs->hw.isurf.reset, ISURF_ISAR_EA); /* Reset Off */
-	current->state = TASK_UNINTERRUPTIBLE;
+	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout((10*HZ)/1000);
 	restore_flags(flags);
 }
@@ -216,8 +189,8 @@
 	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;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/ix1_micro.c linux.19p18/drivers/isdn/hisax/ix1_micro.c
--- linux.vanilla/drivers/isdn/hisax/ix1_micro.c	Fri Apr 21 12:46:10 2000
+++ linux.19p18/drivers/isdn/hisax/ix1_micro.c	Mon Feb 12 15:09:50 2001
@@ -1,5 +1,5 @@
-/* $Id: ix1_micro.c,v 2.8 1999/07/12 21:05:19 keil Exp $
-
+/* $Id: ix1_micro.c,v 2.10 2000/11/24 17:05:38 kai Exp $
+ *
  * ix1_micro.c  low level stuff for ITK ix1-micro Rev.2 isdn cards
  *              derived from the original file teles3.c from Karsten Keil
  *
@@ -10,45 +10,6 @@
  *              Fritz Elfert
  *              Beat Doebeli
  *
- * $Log: ix1_micro.c,v $
- * Revision 2.8  1999/07/12 21:05:19  keil
- * fix race in IRQ handling
- * added watchdog for lost IRQs
- *
- * Revision 2.7  1998/04/15 16:44:31  keil
- * new init code
- *
- * Revision 2.6  1998/02/11 17:28:09  keil
- * Niccy PnP/PCI support
- *
- * Revision 2.5  1998/02/02 13:29:42  keil
- * fast io
- *
- * Revision 2.4  1997/11/08 21:35:50  keil
- * new l1 init
- *
- * Revision 2.3  1997/11/06 17:09:35  keil
- * New 2.1 init code
- *
- * Revision 2.2  1997/10/29 18:55:51  keil
- * changes for 2.1.60 (irq2dev_map)
- *
- * Revision 2.1  1997/07/27 21:47:09  keil
- * new interface structures
- *
- * Revision 2.0  1997/06/26 11:02:50  keil
- * New Layer and card interface
- *
- * Revision 1.3  1997/04/13 19:54:02  keil
- * Change in IRQ check delay for SMP
- *
- * Revision 1.2  1997/04/06 22:54:21  keil
- * Using SKB's
- *
- * Revision 1.1  1997/01/27 15:43:10  keil
- * first version
- *
- *
  */
 
 /*
@@ -82,13 +43,14 @@
 
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
 #include "isdnl1.h"
 
 extern const char *CardType[];
-const char *ix1_revision = "$Revision: 2.8 $";
+const char *ix1_revision = "$Revision: 2.10 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -282,8 +244,8 @@
 }
 
 
-__initfunc(int
-setup_ix1micro(struct IsdnCard *card))
+int __init
+setup_ix1micro(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/jade.c linux.19p18/drivers/isdn/hisax/jade.c
--- linux.vanilla/drivers/isdn/hisax/jade.c	Fri Apr 21 12:46:10 2000
+++ linux.19p18/drivers/isdn/hisax/jade.c	Mon Feb 12 15:09:50 2001
@@ -1,18 +1,16 @@
-/* $Id: jade.c,v 1.2 1999/07/01 08:07:57 keil Exp $
+/* $Id: jade.c,v 1.6 2000/11/24 17:05:38 kai Exp $
  *
  * jade.c   JADE stuff (derived from original hscx.c)
  *
  * Author   Roland Klabunde (R.Klabunde@Berkom.de)
  *
- * $Log: jade.c,v $
- * Revision 1.2  1999/07/01 08:07:57  keil
- * Initial version
- *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "hscx.h"
 #include "jade.h"
@@ -20,8 +18,8 @@
 #include <linux/interrupt.h>
 
 
-HISAX_INITFUNC(int
-JadeVersion(struct IsdnCardState *cs, char *s))
+int __init
+JadeVersion(struct IsdnCardState *cs, char *s)
 {
     int ver,i;
     int to = 50;
@@ -265,8 +263,8 @@
 	return (0);
 }
 
-HISAX_INITFUNC(void
-clear_pending_jade_ints(struct IsdnCardState *cs))
+void __init
+clear_pending_jade_ints(struct IsdnCardState *cs)
 {
 	int val;
 	char tmp[64];
@@ -291,8 +289,8 @@
 	cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0xF8);
 }
 
-HISAX_INITFUNC(void
-initjade(struct IsdnCardState *cs))
+void __init
+initjade(struct IsdnCardState *cs)
 {
 	cs->bcs[0].BC_SetStack = setstack_jade;
 	cs->bcs[1].BC_SetStack = setstack_jade;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/jade.h linux.19p18/drivers/isdn/hisax/jade.h
--- linux.vanilla/drivers/isdn/hisax/jade.h	Fri Apr 21 12:46:10 2000
+++ linux.19p18/drivers/isdn/hisax/jade.h	Wed Dec 13 22:08:13 2000
@@ -1,13 +1,9 @@
-/* $Id: jade.h,v 1.2 1999/07/01 08:07:58 keil Exp $
+/* $Id: jade.h,v 1.3 2000/06/26 08:59:14 keil Exp $
  * jade.h   JADE specific defines
  *
  * Author   Roland Klabunde (R.Klabunde@Berkom.de)
  *
- *
- * $Log: jade.h,v $
- * Revision 1.2  1999/07/01 08:07:58  keil
- * Initial version
- *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/jade_irq.c linux.19p18/drivers/isdn/hisax/jade_irq.c
--- linux.vanilla/drivers/isdn/hisax/jade_irq.c	Fri Apr 21 12:46:10 2000
+++ linux.19p18/drivers/isdn/hisax/jade_irq.c	Sat Dec 30 19:33:52 2000
@@ -1,13 +1,10 @@
-/* $Id: jade_irq.c,v 1.2 1999/07/01 08:07:59 keil Exp $
+/* $Id: jade_irq.c,v 1.5 2000/11/19 17:02:48 kai Exp $
  *
  * jade_irq.c   Low level JADE IRQ stuff (derived from original hscx_irq.c)
  *
  * Author   Roland Klabunde (R.Klabunde@Berkom.de)
  *
- * $Log: jade_irq.c,v $
- * Revision 1.2  1999/07/01 08:07:59  keil
- * Initial version
- *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/l3_1tr6.c linux.19p18/drivers/isdn/hisax/l3_1tr6.c
--- linux.vanilla/drivers/isdn/hisax/l3_1tr6.c	Fri Apr 21 12:46:11 2000
+++ linux.19p18/drivers/isdn/hisax/l3_1tr6.c	Sat Dec 30 19:33:52 2000
@@ -1,5 +1,5 @@
-/* $Id: l3_1tr6.c,v 2.10 2000/01/20 19:42:01 keil Exp $
-
+/* $Id: l3_1tr6.c,v 2.13 2000/11/19 17:02:48 kai Exp $
+ *
  *  German 1TR6 D-channel protocol
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
@@ -8,51 +8,6 @@
  *		For changes and modifications please read
  *		../../../Documentation/isdn/HiSax.cert
  *
- *
- * $Log: l3_1tr6.c,v $
- * Revision 2.10  2000/01/20 19:42:01  keil
- * Fixed uninitialiesed location
- *
- * Revision 2.9  1999/07/01 08:11:55  keil
- * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
- *
- * Revision 2.8  1998/11/15 23:55:08  keil
- * changes from 2.0
- *
- * Revision 2.7  1998/08/13 23:36:45  keil
- * HiSax 3.1 - don't work stable with current LinkLevel
- *
- * Revision 2.6  1998/05/25 14:10:18  keil
- * HiSax 3.0
- * X.75 and leased are working again.
- *
- * Revision 2.5  1998/05/25 12:58:14  keil
- * HiSax golden code from certification, Don't use !!!
- * No leased lines, no X75, but many changes.
- *
- * Revision 2.4  1998/02/12 23:07:57  keil
- * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
- *
- * Revision 2.3  1997/11/06 17:12:24  keil
- * KERN_NOTICE --> KERN_INFO
- *
- * Revision 2.2  1997/10/29 19:03:00  keil
- * changes for 2.1
- *
- * Revision 2.1  1997/08/03 15:28:09  keil
- * release L3 empty processes
- *
- * Revision 2.0  1997/07/27 21:15:45  keil
- * New Callref based layer3
- *
- * Revision 1.12  1997/06/26 11:11:45  keil
- * SET_SKBFREE now on creation of a SKB
- *
- * Revision 1.11  1997/04/06 22:54:18  keil
- * Using SKB's
- *
- * Old Log removed /KKe
- *
  */
 
 #define __NO_VERSION__
@@ -62,7 +17,7 @@
 #include <linux/ctype.h>
 
 extern char *HiSax_getrev(const char *revision);
-const char *l3_1tr6_revision = "$Revision: 2.10 $";
+const char *l3_1tr6_revision = "$Revision: 2.13 $";
 
 #define MsgHead(ptr, cref, mty, dis) \
 	*ptr++ = dis; \
@@ -928,7 +883,7 @@
 		} else {
 			proc->chan = chan;
 			chan->proc = proc;
-			proc->para.setup = chan->setup;
+			memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm));
 			proc->callref = cr;
 		}
 	} else {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/l3_1tr6.h linux.19p18/drivers/isdn/hisax/l3_1tr6.h
--- linux.vanilla/drivers/isdn/hisax/l3_1tr6.h	Fri Apr 21 12:46:11 2000
+++ linux.19p18/drivers/isdn/hisax/l3_1tr6.h	Wed Dec 13 22:08:13 2000
@@ -1,16 +1,8 @@
-/* $Id: l3_1tr6.h,v 2.1 1998/08/13 23:36:48 keil Exp $
+/* $Id: l3_1tr6.h,v 2.2 2000/06/26 08:59:14 keil Exp $
  *
  *  German 1TR6 D-channel protocol defines
  *
- * $Log: l3_1tr6.h,v $
- * Revision 2.1  1998/08/13 23:36:48  keil
- * HiSax 3.1 - don't work stable with current LinkLevel
- *
- * Revision 2.0  1997/07/27 21:15:47  keil
- * New Callref based layer3
- *
- * Revision 1.1  1996/10/13 20:03:48  keil
- * Initial revision
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 #ifndef l3_1tr6
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/l3dss1.c linux.19p18/drivers/isdn/hisax/l3dss1.c
--- linux.vanilla/drivers/isdn/hisax/l3dss1.c	Fri Apr 21 12:46:11 2000
+++ linux.19p18/drivers/isdn/hisax/l3dss1.c	Sat Dec 30 19:33:52 2000
@@ -1,5 +1,5 @@
-/* $Id: l3dss1.c,v 2.23 2000/02/26 01:38:14 keil Exp $
-
+/* $Id: l3dss1.c,v 2.30 2000/11/19 17:02:48 kai Exp $
+ *
  * EURO/DSS1 D-channel protocol
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
@@ -12,91 +12,6 @@
  * Thanks to    Jan den Ouden
  *              Fritz Elfert
  *
- * $Log: l3dss1.c,v $
- * Revision 2.23  2000/02/26 01:38:14  keil
- * Fixes for V.110 encoding LLC from Jens Jakobsen
- *
- * Revision 2.22  2000/01/20 19:44:20  keil
- * Fixed uninitialiesed location
- * Fixed redirecting number IE in Setup
- * Changes from certification
- * option for disabling use of KEYPAD protocol
- *
- * Revision 2.21  1999/12/19 20:25:17  keil
- * fixed LLC for outgoing analog calls
- * IE Signal is valid on older local switches
- *
- * Revision 2.20  1999/10/11 22:16:27  keil
- * Suspend/Resume is possible without explicit ID too
- *
- * Revision 2.19  1999/08/25 16:55:23  keil
- * Fix for test case TC10011
- *
- * Revision 2.18  1999/08/11 20:54:39  keil
- * High layer compatibility is valid in SETUP
- *
- * Revision 2.17  1999/07/25 16:18:25  keil
- * Fix Suspend/Resume
- *
- * Revision 2.16  1999/07/21 14:46:23  keil
- * changes from EICON certification
- *
- * Revision 2.14  1999/07/09 08:30:08  keil
- * cosmetics
- *
- * Revision 2.13  1999/07/01 08:11:58  keil
- * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
- *
- * Revision 2.12  1998/11/15 23:55:10  keil
- * changes from 2.0
- *
- * Revision 2.11  1998/08/13 23:36:51  keil
- * HiSax 3.1 - don't work stable with current LinkLevel
- *
- * Revision 2.10  1998/05/25 14:10:20  keil
- * HiSax 3.0
- * X.75 and leased are working again.
- *
- * Revision 2.9  1998/05/25 12:58:17  keil
- * HiSax golden code from certification, Don't use !!!
- * No leased lines, no X75, but many changes.
- *
- * Revision 2.8  1998/03/19 13:18:47  keil
- * Start of a CAPI like interface for supplementary Service
- * first service: SUSPEND
- *
- * Revision 2.7  1998/02/12 23:08:01  keil
- * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
- *
- * Revision 2.6  1998/02/03 23:26:35  keil
- * V110 extensions from Thomas Pfeiffer
- *
- * Revision 2.5  1998/02/02 13:34:28  keil
- * Support australian Microlink net and german AOCD
- *
- * Revision 2.4  1997/11/06 17:12:25  keil
- * KERN_NOTICE --> KERN_INFO
- *
- * Revision 2.3  1997/10/29 19:03:01  keil
- * changes for 2.1
- *
- * Revision 2.2  1997/08/07 17:44:36  keil
- * Fix RESTART
- *
- * Revision 2.1  1997/08/03 14:36:33  keil
- * Implement RESTART procedure
- *
- * Revision 2.0  1997/07/27 21:15:43  keil
- * New Callref based layer3
- *
- * Revision 1.17  1997/06/26 11:11:46  keil
- * SET_SKBFREE now on creation of a SKB
- *
- * Revision 1.15  1997/04/17 11:50:48  keil
- * pa->loc was undefined, if it was not send by the exchange
- *
- * Old log removed /KKe
- *
  */
 
 #define __NO_VERSION__
@@ -107,7 +22,7 @@
 #include <linux/config.h>
 
 extern char *HiSax_getrev(const char *revision);
-const char *dss1_revision = "$Revision: 2.23 $";
+const char *dss1_revision = "$Revision: 2.30 $";
 
 #define EXT_BEARER_CAPS 1
 
@@ -806,6 +721,9 @@
 	u_char *p, ie;
 	int l, newpos, oldpos;
 	int err_seq = 0, err_len = 0, err_compr = 0, err_ureg = 0;
+	u_char codeset = 0;
+	u_char old_codeset = 0;
+	u_char codelock = 1;
 	
 	p = skb->data;
 	/* skip cr */
@@ -814,20 +732,34 @@
 	p += l;
 	mt = *p++;
 	oldpos = 0;
-/* shift codeset procedure not implemented in the moment */
 	while ((p - skb->data) < skb->len) {
-		if ((newpos = ie_in_set(pc, *p, cl))) {
-			if (newpos > 0) {
-				if (newpos < oldpos)
-					err_seq++;
+		if ((*p & 0xf0) == 0x90) { /* shift codeset */
+			old_codeset = codeset;
+			codeset = *p & 7;
+			if (*p & 0x08)
+				codelock = 0;
+			else
+				codelock = 1;
+			if (pc->debug & L3_DEB_CHECK)
+				l3_debug(pc->st, "check IE shift%scodeset %d->%d",
+					codelock ? " locking ": " ", old_codeset, codeset);
+			p++;
+			continue;
+		}
+		if (!codeset) { /* only codeset 0 */
+			if ((newpos = ie_in_set(pc, *p, cl))) {
+				if (newpos > 0) {
+					if (newpos < oldpos)
+						err_seq++;
+					else
+						oldpos = newpos;
+				}
+			} else {
+				if (ie_in_set(pc, *p, comp_required))
+					err_compr++;
 				else
-					oldpos = newpos;
+					err_ureg++;
 			}
-		} else {
-			if (ie_in_set(pc, *p, comp_required))
-				err_compr++;
-			else
-				err_ureg++;
 		}
 		ie = *p++;
 		if (ie & 0x80) {
@@ -837,12 +769,19 @@
 			p += l;
 			l += 2;
 		}
-		if (l > getmax_ie_len(ie))
+		if (!codeset && (l > getmax_ie_len(ie)))
 			err_len++;
+		if (!codelock) {
+			if (pc->debug & L3_DEB_CHECK)
+				l3_debug(pc->st, "check IE shift back codeset %d->%d",
+					codeset, old_codeset);
+			codeset = old_codeset;
+			codelock = 1;
+		}
 	}
 	if (err_compr | err_ureg | err_len | err_seq) {
 		if (pc->debug & L3_DEB_CHECK)
-			l3_debug(pc->st, "check_infoelements mt %x %d/%d/%d/%d",
+			l3_debug(pc->st, "check IE MT(%x) %d/%d/%d/%d",
 				mt, err_compr, err_ureg, err_len, err_seq);
 		if (err_compr)
 			return(ERR_IE_COMPREHENSION);
@@ -1044,7 +983,7 @@
 
 #if EXT_BEARER_CAPS
 
-u_char *
+static u_char *
 EncodeASyncParams(u_char * p, u_char si2)
 {				// 7c 06 88  90 21 42 00 bb
 
@@ -1109,7 +1048,7 @@
 	return p + 3;
 }
 
-u_char
+static  u_char
 EncodeSyncParams(u_char si2, u_char ai)
 {
 
@@ -1313,39 +1252,31 @@
 	/*
 	 * Set Bearer Capability, Map info from 1TR6-convention to EDSS1
 	 */
-        if (!send_keypad)
-	  switch (pc->para.setup.si1) {
-		case 1:	/* Telephony                               */
-			*p++ = 0x4;	/* BC-IE-code                              */
-			*p++ = 0x3;	/* Length                                  */
-			*p++ = 0x90;	/* Coding Std. CCITT, 3.1 kHz audio     */
-			*p++ = 0x90;	/* Circuit-Mode 64kbps                     */
-			*p++ = 0xa3;	/* A-Law Audio                             */
-			break;
-		case 5:	/* Datatransmission 64k, BTX               */
-		case 7:	/* Datatransmission 64k                    */
-		default:
-			*p++ = 0x4;	/* BC-IE-code                              */
-			*p++ = 0x2;	/* Length                                  */
-			*p++ = 0x88;	/* Coding Std. CCITT, unrestr. dig. Inform. */
-			*p++ = 0x90;	/* Circuit-Mode 64kbps                      */
-			break;
-	  }
-	else {  *p++ = 0x4; /* assumptions for bearer services with keypad  */
-		*p++ = 0x3;
-		*p++ = 0x80;
-                *p++ = 0x90;
-                *p++ = 0xa3;
-		*p++ = 0x18; /* no specific channel */
-                *p++ = 0x01;
-                *p++ = 0x83;
-		*p++ = 0x2C; /* IE keypad */
+	switch (pc->para.setup.si1) {
+	case 1:	                  /* Telephony                                */
+		*p++ = IE_BEARER;
+		*p++ = 0x3;	  /* Length                                   */
+		*p++ = 0x90;	  /* Coding Std. CCITT, 3.1 kHz audio         */
+		*p++ = 0x90;	  /* Circuit-Mode 64kbps                      */
+		*p++ = 0xa3;	  /* A-Law Audio                              */
+		break;
+	case 5:	                  /* Datatransmission 64k, BTX                */
+	case 7:	                  /* Datatransmission 64k                     */
+	default:
+		*p++ = IE_BEARER;
+		*p++ = 0x2;	  /* Length                                   */
+		*p++ = 0x88;	  /* Coding Std. CCITT, unrestr. dig. Inform. */
+		*p++ = 0x90;	  /* Circuit-Mode 64kbps                      */
+		break;
+	}
+
+	if (send_keypad) {
+		*p++ = IE_KEYPAD;
 		*p++ = strlen(teln);
 		while (*teln)
-		  *p++ = (*teln++) & 0x7F;
-	  }
+			*p++ = (*teln++) & 0x7F;
+	}
 	  
-       
 	/*
 	 * What about info2? Mapping to High-Layer-Compatibility?
 	 */
@@ -1394,7 +1325,7 @@
 			sp++;
 	}
 	if (*msn) {
-		*p++ = 0x6c;
+		*p++ = IE_CALLING_PN;
 		*p++ = strlen(msn) + (screen ? 2 : 1);
 		/* Classify as AnyPref. */
 		if (screen) {
@@ -1407,7 +1338,7 @@
 	}
 	if (sub) {
 		*sub++ = '.';
-		*p++ = 0x6d;	/* Calling party subaddress */
+		*p++ = IE_CALLING_SUB;
 		*p++ = strlen(sub) + 2;
 		*p++ = 0x80;	/* NSAP coded */
 		*p++ = 0x50;	/* local IDI format */
@@ -1425,33 +1356,27 @@
 	}
 	
         if (!send_keypad) {      
-	  *p++ = 0x70;
-	  *p++ = strlen(teln) + 1;
-	  /* Classify as AnyPref. */
-	  *p++ = 0x81;		/* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
-	  while (*teln)
-		  *p++ = *teln++ & 0x7f;
-
-	  if (sub) {
-		  *sub++ = '.';
-		  *p++ = 0x71;	/* Called party subaddress */
-		  *p++ = strlen(sub) + 2;
-		  *p++ = 0x80;	/* NSAP coded */
-		  *p++ = 0x50;	/* local IDI format */
-		  while (*sub)
-			  *p++ = *sub++ & 0x7f;
-	  }
+		*p++ = IE_CALLED_PN;
+		*p++ = strlen(teln) + 1;
+		/* Classify as AnyPref. */
+		*p++ = 0x81;		/* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
+		while (*teln)
+			*p++ = *teln++ & 0x7f;
+		
+		if (sub) {
+			*sub++ = '.';
+			*p++ = IE_CALLED_SUB;
+			*p++ = strlen(sub) + 2;
+			*p++ = 0x80;	/* NSAP coded */
+			*p++ = 0x50;	/* local IDI format */
+			while (*sub)
+				*p++ = *sub++ & 0x7f;
+		}
         }
 #if EXT_BEARER_CAPS
-        if (send_keypad) { /* special handling independant of si2 */
-                *p++ = 0x7c;
-                *p++ = 0x03;
-                *p++ = 0x80;
-                *p++ = 0x90;
-                *p++ = 0xa3;
-	} else if ((pc->para.setup.si2 >= 160) && (pc->para.setup.si2 <= 175)) {	// sync. Bitratenadaption, V.110/X.30
+	if ((pc->para.setup.si2 >= 160) && (pc->para.setup.si2 <= 175)) {	// sync. Bitratenadaption, V.110/X.30
 
-		*p++ = 0x7c;
+		*p++ = IE_LLC;
 		*p++ = 0x04;
 		*p++ = 0x88;
 		*p++ = 0x90;
@@ -1459,7 +1384,7 @@
 		*p++ = EncodeSyncParams(pc->para.setup.si2 - 160, 0x80);
 	} else if ((pc->para.setup.si2 >= 176) && (pc->para.setup.si2 <= 191)) {	// sync. Bitratenadaption, V.120
 
-		*p++ = 0x7c;
+		*p++ = IE_LLC;
 		*p++ = 0x05;
 		*p++ = 0x88;
 		*p++ = 0x90;
@@ -1468,7 +1393,7 @@
 		*p++ = 0x82;
 	} else if (pc->para.setup.si2 >= 192) {		// async. Bitratenadaption, V.110/X.30
 
-		*p++ = 0x7c;
+		*p++ = IE_LLC;
 		*p++ = 0x06;
 		*p++ = 0x88;
 		*p++ = 0x90;
@@ -1477,18 +1402,18 @@
 #ifndef CONFIG_HISAX_NO_LLC
 	} else {
 	  switch (pc->para.setup.si1) {
-		case 1:	/* Telephony                               */
-			*p++ = 0x7c;	/* BC-IE-code                              */
-			*p++ = 0x3;	/* Length                                  */
-			*p++ = 0x90;	/* Coding Std. CCITT, 3.1 kHz audio     */
-			*p++ = 0x90;	/* Circuit-Mode 64kbps                     */
-			*p++ = 0xa3;	/* A-Law Audio                             */
+		case 1:	                /* Telephony                                */
+			*p++ = IE_LLC;
+			*p++ = 0x3;	/* Length                                   */
+			*p++ = 0x90;	/* Coding Std. CCITT, 3.1 kHz audio         */
+			*p++ = 0x90;	/* Circuit-Mode 64kbps                      */
+			*p++ = 0xa3;	/* A-Law Audio                              */
 			break;
-		case 5:	/* Datatransmission 64k, BTX               */
-		case 7:	/* Datatransmission 64k                    */
+		case 5:	                /* Datatransmission 64k, BTX                */
+		case 7:	                /* Datatransmission 64k                     */
 		default:
-			*p++ = 0x7c;	/* BC-IE-code                              */
-			*p++ = 0x2;	/* Length                                  */
+			*p++ = IE_LLC;
+			*p++ = 0x2;	/* Length                                   */
 			*p++ = 0x88;	/* Coding Std. CCITT, unrestr. dig. Inform. */
 			*p++ = 0x90;	/* Circuit-Mode 64kbps                      */
 			break;
@@ -1988,6 +1913,16 @@
 	pc->st->l3.l3l4(pc->st, CC_PROCEED_SEND | INDICATION, pc); 
 }
 
+static void
+l3dss1_setup_ack_req(struct l3_process *pc, u_char pr,
+		   void *arg)
+{
+	newl3state(pc, 25);
+	L3DelTimer(&pc->timer);
+	L3AddTimer(&pc->timer, T302, CC_T302);
+	l3dss1_message(pc, MT_SETUP_ACKNOWLEDGE);
+}
+
 /********************************************/
 /* deliver a incoming display message to HL */
 /********************************************/
@@ -2025,7 +1960,7 @@
 		if (p[1] != 2) {
 			err = 1;
 			pc->para.cause = 100;
-		} else if (p[2] & 0x60) {
+		} else if (!(p[2] & 0x70)) {
 			switch (p[2]) {
 				case 0x80:
 				case 0x81:
@@ -2129,9 +2064,22 @@
 {
 	int ret;
 	struct sk_buff *skb = arg;
+	u_char *p;
+	char tmp[32];
 
 	ret = check_infoelements(pc, skb, ie_INFORMATION);
-	l3dss1_std_ie_err(pc, ret);
+	if (ret)
+		l3dss1_std_ie_err(pc, ret);
+	if (pc->state == 25) { /* overlap receiving */
+		L3DelTimer(&pc->timer);
+		p = skb->data;
+		if ((p = findie(p, skb->len, 0x70, 0))) {
+			iecpy(tmp, p, 1);
+			strcat(pc->para.setup.eazmsn, tmp);
+			pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
+		}
+		L3AddTimer(&pc->timer, T302, CC_T302);
+	}
 }
 
 /******************************/
@@ -2357,6 +2305,16 @@
 }
 
 static void
+l3dss1_t302(struct l3_process *pc, u_char pr, void *arg)
+{
+	L3DelTimer(&pc->timer);
+	pc->para.loc = 0;
+	pc->para.cause = 28; /* invalid number */
+	l3dss1_disconnect_req(pc, pr, NULL);
+	pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
+}
+
+static void
 l3dss1_t303(struct l3_process *pc, u_char pr, void *arg)
 {
 	if (pc->N303 > 0) {
@@ -2375,6 +2333,7 @@
 l3dss1_t304(struct l3_process *pc, u_char pr, void *arg)
 {
 	L3DelTimer(&pc->timer);
+	pc->para.loc = 0;
 	pc->para.cause = 102;
 	l3dss1_disconnect_req(pc, pr, NULL);
 	pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
@@ -2414,6 +2373,7 @@
 l3dss1_t310(struct l3_process *pc, u_char pr, void *arg)
 {
 	L3DelTimer(&pc->timer);
+	pc->para.loc = 0;
 	pc->para.cause = 102;
 	l3dss1_disconnect_req(pc, pr, NULL);
 	pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
@@ -2423,6 +2383,7 @@
 l3dss1_t313(struct l3_process *pc, u_char pr, void *arg)
 {
 	L3DelTimer(&pc->timer);
+	pc->para.loc = 0;
 	pc->para.cause = 102;
 	l3dss1_disconnect_req(pc, pr, NULL);
 	pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc);
@@ -2812,32 +2773,36 @@
 	 CC_SETUP | REQUEST, l3dss1_setup_req},
 	{SBIT(0),
 	 CC_RESUME | REQUEST, l3dss1_resume_req},
-	{SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10),
+	{SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(25),
 	 CC_DISCONNECT | REQUEST, l3dss1_disconnect_req},
 	{SBIT(12),
 	 CC_RELEASE | REQUEST, l3dss1_release_req},
 	{ALL_STATES,
 	 CC_RESTART | REQUEST, l3dss1_restart},
-	{SBIT(6),
+	{SBIT(6) | SBIT(25),
 	 CC_IGNORE | REQUEST, l3dss1_reset},
-	{SBIT(6),
+	{SBIT(6) | SBIT(25),
 	 CC_REJECT | REQUEST, l3dss1_reject_req},
-	{SBIT(6),
+	{SBIT(6) | SBIT(25),
 	 CC_PROCEED_SEND | REQUEST, l3dss1_proceed_req},
-	{SBIT(6) | SBIT(9),
+	{SBIT(6),
+	 CC_MORE_INFO | REQUEST, l3dss1_setup_ack_req},
+	{SBIT(25),
+	 CC_MORE_INFO | REQUEST, l3dss1_dummy},
+	{SBIT(6) | SBIT(9) | SBIT(25),
 	 CC_ALERTING | REQUEST, l3dss1_alert_req},
-	{SBIT(6) | SBIT(7) | SBIT(9),
+	{SBIT(6) | SBIT(7) | SBIT(9) | SBIT(25),
 	 CC_SETUP | RESPONSE, l3dss1_setup_rsp},
 	{SBIT(10),
 	 CC_SUSPEND | REQUEST, l3dss1_suspend_req},
-        {SBIT(6),
-         CC_PROCEED_SEND | REQUEST, l3dss1_proceed_req},
-        {SBIT(7) | SBIT(9),
+        {SBIT(7) | SBIT(9) | SBIT(25),
          CC_REDIR | REQUEST, l3dss1_redir_req},
         {SBIT(6),
          CC_REDIR | REQUEST, l3dss1_redir_req_early},
         {SBIT(9) | SBIT(25),
          CC_DISCONNECT | REQUEST, l3dss1_disconnect_req},
+	{SBIT(25),
+	 CC_T302, l3dss1_t302},
 	{SBIT(1),
 	 CC_T303, l3dss1_t303},
 	{SBIT(2),
@@ -3180,7 +3145,7 @@
 		if ((proc = dss1_new_l3_process(st, cr))) {
 			proc->chan = chan;
 			chan->proc = proc;
-			proc->para.setup = chan->setup;
+			memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm));
 			proc->callref = cr;
 		}
 	} else {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/l3dss1.h linux.19p18/drivers/isdn/hisax/l3dss1.h
--- linux.vanilla/drivers/isdn/hisax/l3dss1.h	Fri Apr 21 12:46:11 2000
+++ linux.19p18/drivers/isdn/hisax/l3dss1.h	Wed Dec 13 22:08:13 2000
@@ -1,39 +1,14 @@
-/* $Id: l3dss1.h,v 1.8 2000/01/20 19:46:15 keil Exp $
+/* $Id: l3dss1.h,v 1.10 2000/06/26 08:59:14 keil Exp $
  *
  *  DSS1 (Euro) D-channel protocol defines
  *
- * $Log: l3dss1.h,v $
- * Revision 1.8  2000/01/20 19:46:15  keil
- * Changes from certification
- *
- * Revision 1.7  1999/07/01 08:12:02  keil
- * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
- *
- * Revision 1.6  1998/03/19 13:18:50  keil
- * Start of a CAPI like interface for supplementary Service
- * first service: SUSPEND
- *
- * Revision 1.5  1998/02/02 13:34:30  keil
- * Support australian Microlink net and german AOCD
- *
- * Revision 1.4  1997/10/29 19:07:54  keil
- * changes for 2.1
- *
- * Revision 1.3  1997/08/07 17:44:37  keil
- * Fix RESTART
- *
- * Revision 1.2  1997/08/03 14:36:34  keil
- * Implement RESTART procedure
- *
- * Revision 1.1  1997/07/27 21:08:38  keil
- * new
- *
- *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 
 #ifndef l3dss1_process
 
+#define T302	15000
 #define T303	4000
 #define T304	30000
 #define T305	30000
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/l3ni1.c linux.19p18/drivers/isdn/hisax/l3ni1.c
--- linux.vanilla/drivers/isdn/hisax/l3ni1.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/hisax/l3ni1.c	Tue Feb 13 18:48:23 2001
@@ -0,0 +1,3199 @@
+// $Id: l3ni1.c,v 2.5.6.1 2000/12/06 16:59:19 kai Exp $
+//
+//-----------------------------------------------------------------------------
+//
+// NI1 D-channel protocol
+//
+// Authors:
+// Matt Henderson & Guy Ellis - Traverse Tecnologies Pty Ltd
+// www.traverse.com.au
+//
+// 2000.6.6 Initial implementation of routines for US NI1 
+// Layer 3 protocol based on the EURO/DSS1 D-channel protocol 
+// driver written by Karsten Keil et al.  
+// NI-1 Hall of Fame - Thanks to.... 
+// Ragnar Paulson - for some handy code fragments
+// Will Scales - beta tester extraordinaire
+// Brett Whittacre - beta tester and remote devel system in Vegas
+//
+// This file is (c) under GNU PUBLIC LICENSE
+//
+//-----------------------------------------------------------------------------
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isdnl3.h"
+#include "l3ni1.h"
+#include <linux/ctype.h>
+
+extern char *HiSax_getrev(const char *revision);
+const char *ni1_revision = "$Revision: 2.5.6.1 $";
+
+#define EXT_BEARER_CAPS 1
+
+#define	MsgHead(ptr, cref, mty) \
+	*ptr++ = 0x8; \
+	if (cref == -1) { \
+		*ptr++ = 0x0; \
+	} else { \
+		*ptr++ = 0x1; \
+		*ptr++ = cref^0x80; \
+	} \
+	*ptr++ = mty
+
+
+/**********************************************/
+/* get a new invoke id for remote operations. */
+/* Only a return value != 0 is valid          */
+/**********************************************/
+static unsigned char new_invoke_id(struct PStack *p)
+{
+	unsigned char retval;
+	int flags,i;
+  
+	i = 32; /* maximum search depth */
+
+	save_flags(flags);
+	cli();
+
+	retval = p->prot.ni1.last_invoke_id + 1; /* try new id */
+	while ((i) && (p->prot.ni1.invoke_used[retval >> 3] == 0xFF)) {
+		p->prot.ni1.last_invoke_id = (retval & 0xF8) + 8;
+		i--;
+	}  
+	if (i) {
+		while (p->prot.ni1.invoke_used[retval >> 3] & (1 << (retval & 7)))
+		retval++; 
+	} else
+		retval = 0;
+	p->prot.ni1.last_invoke_id = retval;
+	p->prot.ni1.invoke_used[retval >> 3] |= (1 << (retval & 7));
+	restore_flags(flags);
+
+	return(retval);  
+} /* new_invoke_id */
+
+/*************************/
+/* free a used invoke id */
+/*************************/
+static void free_invoke_id(struct PStack *p, unsigned char id)
+{ int flags;
+
+  if (!id) return; /* 0 = invalid value */
+
+  save_flags(flags);
+  cli();
+  p->prot.ni1.invoke_used[id >> 3] &= ~(1 << (id & 7));
+  restore_flags(flags);
+} /* free_invoke_id */  
+
+
+/**********************************************************/
+/* create a new l3 process and fill in ni1 specific data */
+/**********************************************************/
+static struct l3_process
+*ni1_new_l3_process(struct PStack *st, int cr)
+{  struct l3_process *proc;
+
+   if (!(proc = new_l3_process(st, cr))) 
+     return(NULL);
+
+   proc->prot.ni1.invoke_id = 0;
+   proc->prot.ni1.remote_operation = 0;
+   proc->prot.ni1.uus1_data[0] = '\0';
+   
+   return(proc);
+} /* ni1_new_l3_process */
+
+/************************************************/
+/* free a l3 process and all ni1 specific data */
+/************************************************/ 
+static void
+ni1_release_l3_process(struct l3_process *p)
+{
+   free_invoke_id(p->st,p->prot.ni1.invoke_id);
+   release_l3_process(p);
+} /* ni1_release_l3_process */
+ 
+/********************************************************/
+/* search a process with invoke id id and dummy callref */
+/********************************************************/
+static struct l3_process *
+l3ni1_search_dummy_proc(struct PStack *st, int id)
+{ struct l3_process *pc = st->l3.proc; /* start of processes */
+
+  if (!id) return(NULL);
+
+  while (pc)
+   { if ((pc->callref == -1) && (pc->prot.ni1.invoke_id == id))
+       return(pc);
+     pc = pc->next;
+   } 
+  return(NULL);
+} /* l3ni1_search_dummy_proc */
+
+/*******************************************************************/
+/* called when a facility message with a dummy callref is received */
+/* and a return result is delivered. id specifies the invoke id.   */
+/*******************************************************************/ 
+static void 
+l3ni1_dummy_return_result(struct PStack *st, int id, u_char *p, u_char nlen)
+{ isdn_ctrl ic;
+  struct IsdnCardState *cs;
+  struct l3_process *pc = NULL; 
+
+  if ((pc = l3ni1_search_dummy_proc(st, id)))
+   { L3DelTimer(&pc->timer); /* remove timer */
+
+     cs = pc->st->l1.hardware;
+     ic.driver = cs->myid;
+     ic.command = ISDN_STAT_PROT;
+     ic.arg = NI1_STAT_INVOKE_RES;
+     ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id;
+     ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id;
+     ic.parm.ni1_io.proc = pc->prot.ni1.proc;
+     ic.parm.ni1_io.timeout= 0;
+     ic.parm.ni1_io.datalen = nlen;
+     ic.parm.ni1_io.data = p;
+     free_invoke_id(pc->st, pc->prot.ni1.invoke_id);
+     pc->prot.ni1.invoke_id = 0; /* reset id */
+
+     cs->iif.statcallb(&ic);
+     ni1_release_l3_process(pc); 
+   }
+  else
+   l3_debug(st, "dummy return result id=0x%x result len=%d",id,nlen);
+} /* l3ni1_dummy_return_result */
+
+/*******************************************************************/
+/* called when a facility message with a dummy callref is received */
+/* and a return error is delivered. id specifies the invoke id.    */
+/*******************************************************************/ 
+static void 
+l3ni1_dummy_error_return(struct PStack *st, int id, ulong error)
+{ isdn_ctrl ic;
+  struct IsdnCardState *cs;
+  struct l3_process *pc = NULL; 
+
+  if ((pc = l3ni1_search_dummy_proc(st, id)))
+   { L3DelTimer(&pc->timer); /* remove timer */
+
+     cs = pc->st->l1.hardware;
+     ic.driver = cs->myid;
+     ic.command = ISDN_STAT_PROT;
+     ic.arg = NI1_STAT_INVOKE_ERR;
+     ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id;
+     ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id;
+     ic.parm.ni1_io.proc = pc->prot.ni1.proc;
+     ic.parm.ni1_io.timeout= error;
+     ic.parm.ni1_io.datalen = 0;
+     ic.parm.ni1_io.data = NULL;
+     free_invoke_id(pc->st, pc->prot.ni1.invoke_id);
+     pc->prot.ni1.invoke_id = 0; /* reset id */
+
+     cs->iif.statcallb(&ic);
+     ni1_release_l3_process(pc); 
+   }
+  else
+   l3_debug(st, "dummy return error id=0x%x error=0x%lx",id,error);
+} /* l3ni1_error_return */
+
+/*******************************************************************/
+/* called when a facility message with a dummy callref is received */
+/* and a invoke is delivered. id specifies the invoke id.          */
+/*******************************************************************/ 
+static void 
+l3ni1_dummy_invoke(struct PStack *st, int cr, int id, 
+                    int ident, u_char *p, u_char nlen)
+{ isdn_ctrl ic;
+  struct IsdnCardState *cs;
+
+  l3_debug(st, "dummy invoke %s id=0x%x ident=0x%x datalen=%d",
+               (cr == -1) ? "local" : "broadcast",id,ident,nlen);
+  if (cr >= -1) return; /* ignore local data */
+
+  cs = st->l1.hardware;
+  ic.driver = cs->myid;
+  ic.command = ISDN_STAT_PROT;
+  ic.arg = NI1_STAT_INVOKE_BRD;
+  ic.parm.ni1_io.hl_id = id;
+  ic.parm.ni1_io.ll_id = 0;
+  ic.parm.ni1_io.proc = ident;
+  ic.parm.ni1_io.timeout= 0;
+  ic.parm.ni1_io.datalen = nlen;
+  ic.parm.ni1_io.data = p;
+
+  cs->iif.statcallb(&ic);
+} /* l3ni1_dummy_invoke */
+
+static void
+l3ni1_parse_facility(struct PStack *st, struct l3_process *pc,
+                      int cr, u_char * p)
+{
+	int qd_len = 0;
+	unsigned char nlen = 0, ilen, cp_tag;
+	int ident, id;
+	ulong err_ret;
+
+	if (pc) 
+		st = pc->st; /* valid Stack */
+	else
+		if ((!st) || (cr >= 0)) return; /* neither pc nor st specified */
+
+	p++;
+	qd_len = *p++;
+	if (qd_len == 0) {
+		l3_debug(st, "qd_len == 0");
+		return;
+	}
+	if ((*p & 0x1F) != 0x11) {	/* Service discriminator, supplementary service */
+		l3_debug(st, "supplementary service != 0x11");
+		return;
+	}
+	while (qd_len > 0 && !(*p & 0x80)) {	/* extension ? */
+		p++;
+		qd_len--;
+	}
+	if (qd_len < 2) {
+		l3_debug(st, "qd_len < 2");
+		return;
+	}
+	p++;
+	qd_len--;
+	if ((*p & 0xE0) != 0xA0) {	/* class and form */
+		l3_debug(st, "class and form != 0xA0");
+		return;
+	}
+       
+        cp_tag = *p & 0x1F; /* remember tag value */
+
+        p++;
+	qd_len--;
+	if (qd_len < 1) 
+          { l3_debug(st, "qd_len < 1");
+	    return;
+	  }
+	if (*p & 0x80) 
+          { /* length format indefinite or limited */
+	    nlen = *p++ & 0x7F; /* number of len bytes or indefinite */
+            if ((qd_len-- < ((!nlen) ? 3 : (1 + nlen))) ||
+                (nlen > 1))   
+	     { l3_debug(st, "length format error or not implemented");
+	       return;
+             }
+            if (nlen == 1)
+	     { nlen = *p++; /* complete length */
+               qd_len--;
+             } 
+            else
+	     { qd_len -= 2; /* trailing null bytes */
+               if ((*(p+qd_len)) || (*(p+qd_len+1)))
+		{ l3_debug(st,"length format indefinite error");
+                  return;
+                }
+               nlen = qd_len;
+             }
+	  }
+        else
+	  { nlen = *p++;
+	    qd_len--;
+          } 
+	if (qd_len < nlen) 
+          { l3_debug(st, "qd_len < nlen");
+	    return;
+	  }
+	qd_len -= nlen;
+
+	if (nlen < 2) 
+          { l3_debug(st, "nlen < 2");
+	    return;
+	  }
+        if (*p != 0x02) 
+          {  /* invoke identifier tag */
+	     l3_debug(st, "invoke identifier tag !=0x02");
+	     return;
+	  }
+	p++;
+	nlen--;
+	if (*p & 0x80) 
+          { /* length format */
+	    l3_debug(st, "invoke id length format 2");
+	    return;
+	  }
+	ilen = *p++;
+	nlen--;
+	if (ilen > nlen || ilen == 0) 
+          { l3_debug(st, "ilen > nlen || ilen == 0");
+	    return;
+	  }
+	nlen -= ilen;
+	id = 0;
+	while (ilen > 0) 
+          { id = (id << 8) | (*p++ & 0xFF);	/* invoke identifier */
+	    ilen--;
+	  }
+
+	switch (cp_tag) {	/* component tag */
+		case 1:	/* invoke */
+				if (nlen < 2) {
+					l3_debug(st, "nlen < 2 22");
+					return;
+				}
+				if (*p != 0x02) {	/* operation value */
+					l3_debug(st, "operation value !=0x02");
+					return;
+				}
+				p++;
+				nlen--;
+				ilen = *p++;
+				nlen--;
+				if (ilen > nlen || ilen == 0) {
+					l3_debug(st, "ilen > nlen || ilen == 0 22");
+					return;
+				}
+				nlen -= ilen;
+				ident = 0;
+				while (ilen > 0) {
+					ident = (ident << 8) | (*p++ & 0xFF);
+					ilen--;
+				}
+
+				if (!pc) 
+				{
+					l3ni1_dummy_invoke(st, cr, id, ident, p, nlen);
+					return;
+				} 
+				l3_debug(st, "invoke break");
+				break;
+		case 2:	/* return result */
+			 /* if no process available handle separately */ 
+                        if (!pc)
+			 { if (cr == -1) 
+                             l3ni1_dummy_return_result(st, id, p, nlen);
+                           return; 
+                         }   
+                        if ((pc->prot.ni1.invoke_id) && (pc->prot.ni1.invoke_id == id))
+                          { /* Diversion successfull */
+                            free_invoke_id(st,pc->prot.ni1.invoke_id);
+                            pc->prot.ni1.remote_result = 0; /* success */     
+                            pc->prot.ni1.invoke_id = 0;
+                            pc->redir_result = pc->prot.ni1.remote_result; 
+                            st->l3.l3l4(st, CC_REDIR | INDICATION, pc);                                  } /* Diversion successfull */
+                        else
+                          l3_debug(st,"return error unknown identifier");
+			break;
+		case 3:	/* return error */
+                            err_ret = 0;
+	                    if (nlen < 2) 
+                              { l3_debug(st, "return error nlen < 2");
+	                        return;
+	                      }
+                            if (*p != 0x02) 
+                              { /* result tag */
+	                        l3_debug(st, "invoke error tag !=0x02");
+	                        return;
+	                      }
+	                    p++;
+	                    nlen--;
+	                    if (*p > 4) 
+                              { /* length format */
+	                        l3_debug(st, "invoke return errlen > 4 ");
+	                        return;
+	                      }
+	                    ilen = *p++;
+	                    nlen--;
+	                    if (ilen > nlen || ilen == 0) 
+                              { l3_debug(st, "error return ilen > nlen || ilen == 0");
+	                        return;
+	                       }
+	                    nlen -= ilen;
+	                    while (ilen > 0) 
+                             { err_ret = (err_ret << 8) | (*p++ & 0xFF);	/* error value */
+	                       ilen--;
+	                     }
+			 /* if no process available handle separately */ 
+                        if (!pc)
+			 { if (cr == -1)
+                             l3ni1_dummy_error_return(st, id, err_ret);
+                           return; 
+                         }   
+                        if ((pc->prot.ni1.invoke_id) && (pc->prot.ni1.invoke_id == id))
+                          { /* Deflection error */
+                            free_invoke_id(st,pc->prot.ni1.invoke_id);
+                            pc->prot.ni1.remote_result = err_ret; /* result */
+                            pc->prot.ni1.invoke_id = 0; 
+                            pc->redir_result = pc->prot.ni1.remote_result; 
+                            st->l3.l3l4(st, CC_REDIR | INDICATION, pc);  
+                          } /* Deflection error */
+                        else
+                          l3_debug(st,"return result unknown identifier");
+			break;
+		default:
+			l3_debug(st, "facility default break tag=0x%02x",cp_tag);
+			break;
+	}
+}
+
+static void
+l3ni1_message(struct l3_process *pc, u_char mt)
+{
+	struct sk_buff *skb;
+	u_char *p;
+
+	if (!(skb = l3_alloc_skb(4)))
+		return;
+	p = skb_put(skb, 4);
+	MsgHead(p, pc->callref, mt);
+	l3_msg(pc->st, DL_DATA | REQUEST, skb);
+}
+
+static void
+l3ni1_message_plus_chid(struct l3_process *pc, u_char mt)
+/* sends an l3 messages plus channel id -  added GE 05/09/00 */
+{
+	struct sk_buff *skb;
+	u_char tmp[16];
+	u_char *p = tmp;
+	u_char chid;
+
+	chid = (u_char)(pc->para.bchannel & 0x03) | 0x88;
+	MsgHead(p, pc->callref, mt);
+	*p++ = IE_CHANNEL_ID;
+	*p++ = 0x01;
+	*p++ = chid;
+
+	if (!(skb = l3_alloc_skb(7)))
+		return;
+	memcpy(skb_put(skb, 7), tmp, 7);
+	l3_msg(pc->st, DL_DATA | REQUEST, skb);
+}
+
+static void
+l3ni1_message_cause(struct l3_process *pc, u_char mt, u_char cause)
+{
+	struct sk_buff *skb;
+	u_char tmp[16];
+	u_char *p = tmp;
+	int l;
+
+	MsgHead(p, pc->callref, mt);
+	*p++ = IE_CAUSE;
+	*p++ = 0x2;
+	*p++ = 0x80;
+	*p++ = cause | 0x80;
+
+	l = p - tmp;
+	if (!(skb = l3_alloc_skb(l)))
+		return;
+	memcpy(skb_put(skb, l), tmp, l);
+	l3_msg(pc->st, DL_DATA | REQUEST, skb);
+}
+
+static void
+l3ni1_status_send(struct l3_process *pc, u_char pr, void *arg)
+{
+	u_char tmp[16];
+	u_char *p = tmp;
+	int l;
+	struct sk_buff *skb;
+
+	MsgHead(p, pc->callref, MT_STATUS);
+
+	*p++ = IE_CAUSE;
+	*p++ = 0x2;
+	*p++ = 0x80;
+	*p++ = pc->para.cause | 0x80;
+
+	*p++ = IE_CALL_STATE;
+	*p++ = 0x1;
+	*p++ = pc->state & 0x3f;
+
+	l = p - tmp;
+	if (!(skb = l3_alloc_skb(l)))
+		return;
+	memcpy(skb_put(skb, l), tmp, l);
+	l3_msg(pc->st, DL_DATA | REQUEST, skb);
+}
+
+static void
+l3ni1_msg_without_setup(struct l3_process *pc, u_char pr, void *arg)
+{
+	/* This routine is called if here was no SETUP made (checks in ni1up and in
+	 * l3ni1_setup) and a RELEASE_COMPLETE have to be sent with an error code
+	 * MT_STATUS_ENQUIRE in the NULL state is handled too
+	 */
+	u_char tmp[16];
+	u_char *p = tmp;
+	int l;
+	struct sk_buff *skb;
+
+	switch (pc->para.cause) {
+		case 81:	/* invalid callreference */
+		case 88:	/* incomp destination */
+		case 96:	/* mandory IE missing */
+		case 100:       /* invalid IE contents */
+		case 101:	/* incompatible Callstate */
+			MsgHead(p, pc->callref, MT_RELEASE_COMPLETE);
+			*p++ = IE_CAUSE;
+			*p++ = 0x2;
+			*p++ = 0x80;
+			*p++ = pc->para.cause | 0x80;
+			break;
+		default:
+			printk(KERN_ERR "HiSax l3ni1_msg_without_setup wrong cause %d\n",
+				pc->para.cause);
+			return;
+	}
+	l = p - tmp;
+	if (!(skb = l3_alloc_skb(l)))
+		return;
+	memcpy(skb_put(skb, l), tmp, l);
+	l3_msg(pc->st, DL_DATA | REQUEST, skb);
+	ni1_release_l3_process(pc);
+}
+
+static int ie_ALERTING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1,
+		IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_HLC,
+		IE_USER_USER, -1};
+static int ie_CALL_PROCEEDING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1,
+		IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_HLC, -1};
+static int ie_CONNECT[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, 
+		IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_DATE, IE_SIGNAL,
+		IE_CONNECT_PN, IE_CONNECT_SUB, IE_LLC, IE_HLC, IE_USER_USER, -1};
+static int ie_CONNECT_ACKNOWLEDGE[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_SIGNAL, -1};
+static int ie_DISCONNECT[] = {IE_CAUSE | IE_MANDATORY, IE_FACILITY,
+		IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1};
+static int ie_INFORMATION[] = {IE_COMPLETE, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL,
+		IE_CALLED_PN, -1};
+static int ie_NOTIFY[] = {IE_BEARER, IE_NOTIFY | IE_MANDATORY, IE_DISPLAY, -1};
+static int ie_PROGRESS[] = {IE_BEARER, IE_CAUSE, IE_FACILITY, IE_PROGRESS |
+		IE_MANDATORY, IE_DISPLAY, IE_HLC, IE_USER_USER, -1};
+static int ie_RELEASE[] = {IE_CAUSE | IE_MANDATORY_1, IE_FACILITY, IE_DISPLAY,
+		IE_SIGNAL, IE_USER_USER, -1};
+/* a RELEASE_COMPLETE with errors don't require special actions 
+static int ie_RELEASE_COMPLETE[] = {IE_CAUSE | IE_MANDATORY_1, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1};
+*/
+static int ie_RESUME_ACKNOWLEDGE[] = {IE_CHANNEL_ID| IE_MANDATORY, IE_FACILITY,
+		IE_DISPLAY, -1};
+static int ie_RESUME_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1};
+static int ie_SETUP[] = {IE_COMPLETE, IE_BEARER  | IE_MANDATORY,
+		IE_CHANNEL_ID| IE_MANDATORY, IE_FACILITY, IE_PROGRESS,
+		IE_NET_FAC, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL, IE_CALLING_PN,
+		IE_CALLING_SUB, IE_CALLED_PN, IE_CALLED_SUB, IE_REDIR_NR,
+		IE_LLC, IE_HLC, IE_USER_USER, -1};
+static int ie_SETUP_ACKNOWLEDGE[] = {IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY,
+		IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, -1};
+static int ie_STATUS[] = {IE_CAUSE | IE_MANDATORY, IE_CALL_STATE |
+		IE_MANDATORY, IE_DISPLAY, -1};
+static int ie_STATUS_ENQUIRY[] = {IE_DISPLAY, -1};
+static int ie_SUSPEND_ACKNOWLEDGE[] = {IE_DISPLAY, IE_FACILITY, -1};
+static int ie_SUSPEND_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1};
+/* not used 
+ * static int ie_CONGESTION_CONTROL[] = {IE_CONGESTION | IE_MANDATORY,
+ *		IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1};
+ * static int ie_USER_INFORMATION[] = {IE_MORE_DATA, IE_USER_USER | IE_MANDATORY, -1};
+ * static int ie_RESTART[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_RESTART_IND |
+ *		IE_MANDATORY, -1};
+ */
+static int ie_FACILITY[] = {IE_FACILITY | IE_MANDATORY, IE_DISPLAY, -1};
+static int comp_required[] = {1,2,3,5,6,7,9,10,11,14,15,-1};
+static int l3_valid_states[] = {0,1,2,3,4,6,7,8,9,10,11,12,15,17,19,25,-1};
+
+struct ie_len {
+	int ie;
+	int len;
+};
+
+static
+struct ie_len max_ie_len[] = {
+	{IE_SEGMENT, 4},
+	{IE_BEARER, 12},
+	{IE_CAUSE, 32},
+	{IE_CALL_ID, 10},
+	{IE_CALL_STATE, 3},
+	{IE_CHANNEL_ID,	34},
+	{IE_FACILITY, 255},
+	{IE_PROGRESS, 4},
+	{IE_NET_FAC, 255},
+	{IE_NOTIFY, 3},
+	{IE_DISPLAY, 82},
+	{IE_DATE, 8},
+	{IE_KEYPAD, 34},
+	{IE_SIGNAL, 3},
+	{IE_INFORATE, 6},
+	{IE_E2E_TDELAY, 11},
+	{IE_TDELAY_SEL, 5},
+	{IE_PACK_BINPARA, 3},
+	{IE_PACK_WINSIZE, 4},
+	{IE_PACK_SIZE, 4},
+	{IE_CUG, 7},
+	{IE_REV_CHARGE, 3},
+	{IE_CALLING_PN, 24},
+	{IE_CALLING_SUB, 23},
+	{IE_CALLED_PN, 24},
+	{IE_CALLED_SUB, 23},
+	{IE_REDIR_NR, 255},
+	{IE_TRANS_SEL, 255},
+	{IE_RESTART_IND, 3},
+	{IE_LLC, 18},
+	{IE_HLC, 5},
+	{IE_USER_USER, 131},
+	{-1,0},
+};
+
+static int
+getmax_ie_len(u_char ie) {
+	int i = 0;
+	while (max_ie_len[i].ie != -1) {
+		if (max_ie_len[i].ie == ie)
+			return(max_ie_len[i].len);
+		i++;
+	}
+	return(255);
+}
+
+static int
+ie_in_set(struct l3_process *pc, u_char ie, int *checklist) {
+	int ret = 1;
+
+	while (*checklist != -1) {
+		if ((*checklist & 0xff) == ie) {
+			if (ie & 0x80)
+				return(-ret);
+			else
+				return(ret);
+		}
+		ret++;
+		checklist++;
+	}
+	return(0);
+}
+
+static int
+check_infoelements(struct l3_process *pc, struct sk_buff *skb, int *checklist)
+{
+	int *cl = checklist;
+	u_char mt;
+	u_char *p, ie;
+	int l, newpos, oldpos;
+	int err_seq = 0, err_len = 0, err_compr = 0, err_ureg = 0;
+	u_char codeset = 0;
+	u_char old_codeset = 0;
+	u_char codelock = 1;
+	
+	p = skb->data;
+	/* skip cr */
+	p++;
+	l = (*p++) & 0xf;
+	p += l;
+	mt = *p++;
+	oldpos = 0;
+	while ((p - skb->data) < skb->len) {
+		if ((*p & 0xf0) == 0x90) { /* shift codeset */
+			old_codeset = codeset;
+			codeset = *p & 7;
+			if (*p & 0x08)
+				codelock = 0;
+			else
+				codelock = 1;
+			if (pc->debug & L3_DEB_CHECK)
+				l3_debug(pc->st, "check IE shift%scodeset %d->%d",
+					codelock ? " locking ": " ", old_codeset, codeset);
+			p++;
+			continue;
+		}
+		if (!codeset) { /* only codeset 0 */
+			if ((newpos = ie_in_set(pc, *p, cl))) {
+				if (newpos > 0) {
+					if (newpos < oldpos)
+						err_seq++;
+					else
+						oldpos = newpos;
+				}
+			} else {
+				if (ie_in_set(pc, *p, comp_required))
+					err_compr++;
+				else
+					err_ureg++;
+			}
+		}
+		ie = *p++;
+		if (ie & 0x80) {
+			l = 1;
+		} else {
+			l = *p++;
+			p += l;
+			l += 2;
+		}
+		if (!codeset && (l > getmax_ie_len(ie)))
+			err_len++;
+		if (!codelock) {
+			if (pc->debug & L3_DEB_CHECK)
+				l3_debug(pc->st, "check IE shift back codeset %d->%d",
+					codeset, old_codeset);
+			codeset = old_codeset;
+			codelock = 1;
+		}
+	}
+	if (err_compr | err_ureg | err_len | err_seq) {
+		if (pc->debug & L3_DEB_CHECK)
+			l3_debug(pc->st, "check IE MT(%x) %d/%d/%d/%d",
+				mt, err_compr, err_ureg, err_len, err_seq);
+		if (err_compr)
+			return(ERR_IE_COMPREHENSION);
+		if (err_ureg)
+			return(ERR_IE_UNRECOGNIZED);
+		if (err_len)
+			return(ERR_IE_LENGTH);
+		if (err_seq)
+			return(ERR_IE_SEQUENCE);
+	} 
+	return(0);
+}
+
+/* verify if a message type exists and contain no IE error */
+static int
+l3ni1_check_messagetype_validity(struct l3_process *pc, int mt, void *arg)
+{
+	switch (mt) {
+		case MT_ALERTING:
+		case MT_CALL_PROCEEDING:
+		case MT_CONNECT:
+		case MT_CONNECT_ACKNOWLEDGE:
+		case MT_DISCONNECT:
+		case MT_INFORMATION:
+		case MT_FACILITY:
+		case MT_NOTIFY:
+		case MT_PROGRESS:
+		case MT_RELEASE:
+		case MT_RELEASE_COMPLETE:
+		case MT_SETUP:
+		case MT_SETUP_ACKNOWLEDGE:
+		case MT_RESUME_ACKNOWLEDGE:
+		case MT_RESUME_REJECT:
+		case MT_SUSPEND_ACKNOWLEDGE:
+		case MT_SUSPEND_REJECT:
+		case MT_USER_INFORMATION:
+		case MT_RESTART:
+		case MT_RESTART_ACKNOWLEDGE:
+		case MT_CONGESTION_CONTROL:
+		case MT_STATUS:
+		case MT_STATUS_ENQUIRY:
+			if (pc->debug & L3_DEB_CHECK)
+				l3_debug(pc->st, "l3ni1_check_messagetype_validity mt(%x) OK", mt);
+			break;
+		case MT_RESUME: /* RESUME only in user->net */
+		case MT_SUSPEND: /* SUSPEND only in user->net */
+		default:
+			if (pc->debug & (L3_DEB_CHECK | L3_DEB_WARN))
+				l3_debug(pc->st, "l3ni1_check_messagetype_validity mt(%x) fail", mt);
+			pc->para.cause = 97;
+			l3ni1_status_send(pc, 0, NULL);
+			return(1);
+	}
+	return(0);
+}
+
+static void
+l3ni1_std_ie_err(struct l3_process *pc, int ret) {
+
+	if (pc->debug & L3_DEB_CHECK)
+		l3_debug(pc->st, "check_infoelements ret %d", ret);
+	switch(ret) {
+		case 0: 
+			break;
+		case ERR_IE_COMPREHENSION:
+			pc->para.cause = 96;
+			l3ni1_status_send(pc, 0, NULL);
+			break;
+		case ERR_IE_UNRECOGNIZED:
+			pc->para.cause = 99;
+			l3ni1_status_send(pc, 0, NULL);
+			break;
+		case ERR_IE_LENGTH:
+			pc->para.cause = 100;
+			l3ni1_status_send(pc, 0, NULL);
+			break;
+		case ERR_IE_SEQUENCE:
+		default:
+			break;
+	}
+}
+
+static int
+l3ni1_get_channel_id(struct l3_process *pc, struct sk_buff *skb) {
+	u_char *p;
+
+	p = skb->data;
+	if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) {
+		p++;
+		if (*p != 1) { /* len for BRI = 1 */
+			if (pc->debug & L3_DEB_WARN)
+				l3_debug(pc->st, "wrong chid len %d", *p);
+			return (-2);
+		}
+		p++;
+		if (*p & 0x60) { /* only base rate interface */
+			if (pc->debug & L3_DEB_WARN)
+				l3_debug(pc->st, "wrong chid %x", *p);
+			return (-3);
+		}
+		return(*p & 0x3);
+	} else
+		return(-1);
+}
+
+static int
+l3ni1_get_cause(struct l3_process *pc, struct sk_buff *skb) {
+	u_char l, i=0;
+	u_char *p;
+
+	p = skb->data;
+	pc->para.cause = 31;
+	pc->para.loc = 0;
+	if ((p = findie(p, skb->len, IE_CAUSE, 0))) {
+		p++;
+		l = *p++;
+		if (l>30)
+			return(1);
+		if (l) {
+			pc->para.loc = *p++;
+			l--;
+		} else {
+			return(2);
+		}
+		if (l && !(pc->para.loc & 0x80)) {
+			l--;
+			p++; /* skip recommendation */
+		}
+		if (l) {
+			pc->para.cause = *p++;
+			l--;
+			if (!(pc->para.cause & 0x80))
+				return(3);
+		} else
+			return(4);
+		while (l && (i<6)) {
+			pc->para.diag[i++] = *p++;
+			l--;
+		}
+	} else
+		return(-1);
+	return(0);
+}
+
+static void
+l3ni1_msg_with_uus(struct l3_process *pc, u_char cmd)
+{
+	struct sk_buff *skb;
+	u_char tmp[16+40];
+	u_char *p = tmp;
+	int l;
+
+	MsgHead(p, pc->callref, cmd);
+
+        if (pc->prot.ni1.uus1_data[0])
+	 { *p++ = IE_USER_USER; /* UUS info element */
+           *p++ = strlen(pc->prot.ni1.uus1_data) + 1;
+           *p++ = 0x04; /* IA5 chars */
+           strcpy(p,pc->prot.ni1.uus1_data);
+           p += strlen(pc->prot.ni1.uus1_data);
+           pc->prot.ni1.uus1_data[0] = '\0';   
+         } 
+
+	l = p - tmp;
+	if (!(skb = l3_alloc_skb(l)))
+		return;
+	memcpy(skb_put(skb, l), tmp, l);
+	l3_msg(pc->st, DL_DATA | REQUEST, skb);
+} /* l3ni1_msg_with_uus */
+
+static void
+l3ni1_release_req(struct l3_process *pc, u_char pr, void *arg)
+{
+	StopAllL3Timer(pc);
+	newl3state(pc, 19);
+	if (!pc->prot.ni1.uus1_data[0]) 
+		l3ni1_message(pc, MT_RELEASE);
+	else
+		l3ni1_msg_with_uus(pc, MT_RELEASE);
+	L3AddTimer(&pc->timer, T308, CC_T308_1);
+}
+
+static void
+l3ni1_release_cmpl(struct l3_process *pc, u_char pr, void *arg)
+{
+	struct sk_buff *skb = arg;
+	int ret;
+
+	if ((ret = l3ni1_get_cause(pc, skb))>0) {
+		if (pc->debug & L3_DEB_WARN)
+			l3_debug(pc->st, "RELCMPL get_cause ret(%d)",ret);
+	} else if (ret < 0)
+		pc->para.cause = NO_CAUSE;
+	StopAllL3Timer(pc);
+	newl3state(pc, 0);
+	pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc);
+	ni1_release_l3_process(pc);
+}
+
+#if EXT_BEARER_CAPS
+
+static u_char *
+EncodeASyncParams(u_char * p, u_char si2)
+{				// 7c 06 88  90 21 42 00 bb
+
+	p[0] = 0;
+	p[1] = 0x40;		// Intermediate rate: 16 kbit/s jj 2000.02.19
+	p[2] = 0x80;
+	if (si2 & 32)		// 7 data bits
+
+		p[2] += 16;
+	else			// 8 data bits
+
+		p[2] += 24;
+
+	if (si2 & 16)		// 2 stop bits
+
+		p[2] += 96;
+	else			// 1 stop bit
+
+		p[2] += 32;
+
+	if (si2 & 8)		// even parity
+
+		p[2] += 2;
+	else			// no parity
+
+		p[2] += 3;
+
+	switch (si2 & 0x07) {
+		case 0:
+			p[0] = 66;	// 1200 bit/s
+
+			break;
+		case 1:
+			p[0] = 88;	// 1200/75 bit/s
+
+			break;
+		case 2:
+			p[0] = 87;	// 75/1200 bit/s
+
+			break;
+		case 3:
+			p[0] = 67;	// 2400 bit/s
+
+			break;
+		case 4:
+			p[0] = 69;	// 4800 bit/s
+
+			break;
+		case 5:
+			p[0] = 72;	// 9600 bit/s
+
+			break;
+		case 6:
+			p[0] = 73;	// 14400 bit/s
+
+			break;
+		case 7:
+			p[0] = 75;	// 19200 bit/s
+
+			break;
+	}
+	return p + 3;
+}
+
+static u_char
+EncodeSyncParams(u_char si2, u_char ai)
+{
+
+	switch (si2) {
+		case 0:
+			return ai + 2;	// 1200 bit/s
+
+		case 1:
+			return ai + 24;		// 1200/75 bit/s
+
+		case 2:
+			return ai + 23;		// 75/1200 bit/s
+
+		case 3:
+			return ai + 3;	// 2400 bit/s
+
+		case 4:
+			return ai + 5;	// 4800 bit/s
+
+		case 5:
+			return ai + 8;	// 9600 bit/s
+
+		case 6:
+			return ai + 9;	// 14400 bit/s
+
+		case 7:
+			return ai + 11;		// 19200 bit/s
+
+		case 8:
+			return ai + 14;		// 48000 bit/s
+
+		case 9:
+			return ai + 15;		// 56000 bit/s
+
+		case 15:
+			return ai + 40;		// negotiate bit/s
+
+		default:
+			break;
+	}
+	return ai;
+}
+
+
+static u_char
+DecodeASyncParams(u_char si2, u_char * p)
+{
+	u_char info;
+
+	switch (p[5]) {
+		case 66:	// 1200 bit/s
+
+			break;	// si2 don't change
+
+		case 88:	// 1200/75 bit/s
+
+			si2 += 1;
+			break;
+		case 87:	// 75/1200 bit/s
+
+			si2 += 2;
+			break;
+		case 67:	// 2400 bit/s
+
+			si2 += 3;
+			break;
+		case 69:	// 4800 bit/s
+
+			si2 += 4;
+			break;
+		case 72:	// 9600 bit/s
+
+			si2 += 5;
+			break;
+		case 73:	// 14400 bit/s
+
+			si2 += 6;
+			break;
+		case 75:	// 19200 bit/s
+
+			si2 += 7;
+			break;
+	}
+
+	info = p[7] & 0x7f;
+	if ((info & 16) && (!(info & 8)))	// 7 data bits
+
+		si2 += 32;	// else 8 data bits
+
+	if ((info & 96) == 96)	// 2 stop bits
+
+		si2 += 16;	// else 1 stop bit
+
+	if ((info & 2) && (!(info & 1)))	// even parity
+
+		si2 += 8;	// else no parity
+
+	return si2;
+}
+
+
+static u_char
+DecodeSyncParams(u_char si2, u_char info)
+{
+	info &= 0x7f;
+	switch (info) {
+		case 40:	// bit/s negotiation failed  ai := 165 not 175!
+
+			return si2 + 15;
+		case 15:	// 56000 bit/s failed, ai := 0 not 169 !
+
+			return si2 + 9;
+		case 14:	// 48000 bit/s
+
+			return si2 + 8;
+		case 11:	// 19200 bit/s
+
+			return si2 + 7;
+		case 9:	// 14400 bit/s
+
+			return si2 + 6;
+		case 8:	// 9600  bit/s
+
+			return si2 + 5;
+		case 5:	// 4800  bit/s
+
+			return si2 + 4;
+		case 3:	// 2400  bit/s
+
+			return si2 + 3;
+		case 23:	// 75/1200 bit/s
+
+			return si2 + 2;
+		case 24:	// 1200/75 bit/s
+
+			return si2 + 1;
+		default:	// 1200 bit/s
+
+			return si2;
+	}
+}
+
+static u_char
+DecodeSI2(struct sk_buff *skb)
+{
+	u_char *p;		//, *pend=skb->data + skb->len;
+
+	if ((p = findie(skb->data, skb->len, 0x7c, 0))) {
+		switch (p[4] & 0x0f) {
+			case 0x01:
+				if (p[1] == 0x04)	// sync. Bitratenadaption
+
+					return DecodeSyncParams(160, p[5]);	// V.110/X.30
+
+				else if (p[1] == 0x06)	// async. Bitratenadaption
+
+					return DecodeASyncParams(192, p);	// V.110/X.30
+
+				break;
+			case 0x08:	// if (p[5] == 0x02) // sync. Bitratenadaption
+				if (p[1] > 3) 
+					return DecodeSyncParams(176, p[5]);	// V.120
+				break;
+		}
+	}
+	return 0;
+}
+
+#endif
+
+
+static void
+l3ni1_setup_req(struct l3_process *pc, u_char pr,
+		 void *arg)
+{
+	struct sk_buff *skb;
+	u_char tmp[128];
+	u_char *p = tmp;
+
+	u_char *teln;
+	u_char *sub;
+	u_char *sp;
+	int l;
+
+	MsgHead(p, pc->callref, MT_SETUP);
+
+	teln = pc->para.setup.phone;
+
+	*p++ = 0xa1;		/* complete indicator */
+	/*
+	 * Set Bearer Capability, Map info from 1TR6-convention to NI1
+	 */
+	switch (pc->para.setup.si1) {
+	case 1:	                  /* Telephony                                */
+		*p++ = IE_BEARER;
+		*p++ = 0x3;	  /* Length                                   */
+		*p++ = 0x90;	  /* 3.1khz Audio      			      */
+		*p++ = 0x90;	  /* Circuit-Mode 64kbps                      */
+		*p++ = 0xa2;	  /* u-Law Audio                              */
+		break;
+	case 5:	                  /* Datatransmission 64k, BTX                */
+	case 7:	                  /* Datatransmission 64k                     */
+	default:
+		*p++ = IE_BEARER;
+		*p++ = 0x2;	  /* Length                                   */
+		*p++ = 0x88;	  /* Coding Std. CCITT, unrestr. dig. Inform. */
+		*p++ = 0x90;	  /* Circuit-Mode 64kbps                      */
+		break;
+	}
+
+	sub = NULL;
+	sp = teln;
+	while (*sp) {
+		if ('.' == *sp) {
+			sub = sp;
+			*sp = 0;
+		} else
+			sp++;
+	}
+	
+	*p++ = IE_KEYPAD;
+	*p++ = strlen(teln);
+	while (*teln)
+		*p++ = (*teln++) & 0x7F;
+
+	if (sub)
+		*sub++ = '.';
+	
+#if EXT_BEARER_CAPS
+	if ((pc->para.setup.si2 >= 160) && (pc->para.setup.si2 <= 175)) {	// sync. Bitratenadaption, V.110/X.30
+
+		*p++ = IE_LLC;
+		*p++ = 0x04;
+		*p++ = 0x88;
+		*p++ = 0x90;
+		*p++ = 0x21;
+		*p++ = EncodeSyncParams(pc->para.setup.si2 - 160, 0x80);
+	} else if ((pc->para.setup.si2 >= 176) && (pc->para.setup.si2 <= 191)) {	// sync. Bitratenadaption, V.120
+
+		*p++ = IE_LLC;
+		*p++ = 0x05;
+		*p++ = 0x88;
+		*p++ = 0x90;
+		*p++ = 0x28;
+		*p++ = EncodeSyncParams(pc->para.setup.si2 - 176, 0);
+		*p++ = 0x82;
+	} else if (pc->para.setup.si2 >= 192) {		// async. Bitratenadaption, V.110/X.30
+
+		*p++ = IE_LLC;
+		*p++ = 0x06;
+		*p++ = 0x88;
+		*p++ = 0x90;
+		*p++ = 0x21;
+		p = EncodeASyncParams(p, pc->para.setup.si2 - 192);
+	} else {
+	  switch (pc->para.setup.si1) {
+		case 1:	                /* Telephony                                */
+			*p++ = IE_LLC;
+			*p++ = 0x3;	/* Length                                   */
+			*p++ = 0x90;	/* Coding Std. CCITT, 3.1 kHz audio         */
+			*p++ = 0x90;	/* Circuit-Mode 64kbps                      */
+			*p++ = 0xa2;	/* u-Law Audio                              */
+			break;
+		case 5:	                /* Datatransmission 64k, BTX                */
+		case 7:	                /* Datatransmission 64k                     */
+		default:
+			*p++ = IE_LLC;
+			*p++ = 0x2;	/* Length                                   */
+			*p++ = 0x88;	/* Coding Std. CCITT, unrestr. dig. Inform. */
+			*p++ = 0x90;	/* Circuit-Mode 64kbps                      */
+			break;
+	  }
+	}
+#endif
+	l = p - tmp;
+	if (!(skb = l3_alloc_skb(l)))
+{
+		return;
+}
+	memcpy(skb_put(skb, l), tmp, l);
+	L3DelTimer(&pc->timer);
+	L3AddTimer(&pc->timer, T303, CC_T303);
+	newl3state(pc, 1);
+	l3_msg(pc->st, DL_DATA | REQUEST, skb);
+}
+
+static void
+l3ni1_call_proc(struct l3_process *pc, u_char pr, void *arg)
+{
+	struct sk_buff *skb = arg;
+	int id, ret;
+
+	if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) {
+		if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) {
+			if (pc->debug & L3_DEB_WARN)
+				l3_debug(pc->st, "setup answer with wrong chid %x", id);
+			pc->para.cause = 100;
+			l3ni1_status_send(pc, pr, NULL);
+			return;
+		}
+		pc->para.bchannel = id;
+	} else if (1 == pc->state) {
+		if (pc->debug & L3_DEB_WARN)
+			l3_debug(pc->st, "setup answer wrong chid (ret %d)", id);
+		if (id == -1)
+			pc->para.cause = 96;
+		else
+			pc->para.cause = 100;
+		l3ni1_status_send(pc, pr, NULL);
+		return;
+	}
+	/* Now we are on none mandatory IEs */
+	ret = check_infoelements(pc, skb, ie_CALL_PROCEEDING);
+	if (ERR_IE_COMPREHENSION == ret) {
+		l3ni1_std_ie_err(pc, ret);
+		return;
+	}
+	L3DelTimer(&pc->timer);
+	newl3state(pc, 3);
+	L3AddTimer(&pc->timer, T310, CC_T310);
+	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
+		l3ni1_std_ie_err(pc, ret);
+	pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc);
+}
+
+static void
+l3ni1_setup_ack(struct l3_process *pc, u_char pr, void *arg)
+{
+	struct sk_buff *skb = arg;
+	int id, ret;
+
+	if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) {
+		if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) {
+			if (pc->debug & L3_DEB_WARN)
+				l3_debug(pc->st, "setup answer with wrong chid %x", id);
+			pc->para.cause = 100;
+			l3ni1_status_send(pc, pr, NULL);
+			return;
+		}
+		pc->para.bchannel = id;
+	} else {
+		if (pc->debug & L3_DEB_WARN)
+			l3_debug(pc->st, "setup answer wrong chid (ret %d)", id);
+		if (id == -1)
+			pc->para.cause = 96;
+		else
+			pc->para.cause = 100;
+		l3ni1_status_send(pc, pr, NULL);
+		return;
+	}
+	/* Now we are on none mandatory IEs */
+	ret = check_infoelements(pc, skb, ie_SETUP_ACKNOWLEDGE);
+	if (ERR_IE_COMPREHENSION == ret) {
+		l3ni1_std_ie_err(pc, ret);
+		return;
+	}
+	L3DelTimer(&pc->timer);
+	newl3state(pc, 2);
+	L3AddTimer(&pc->timer, T304, CC_T304);
+	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
+		l3ni1_std_ie_err(pc, ret);
+	pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
+}
+
+static void
+l3ni1_disconnect(struct l3_process *pc, u_char pr, void *arg)
+{
+	struct sk_buff *skb = arg;
+	u_char *p;
+	int ret;
+	u_char cause = 0;
+
+	StopAllL3Timer(pc);
+	if ((ret = l3ni1_get_cause(pc, skb))) {
+		if (pc->debug & L3_DEB_WARN)
+			l3_debug(pc->st, "DISC get_cause ret(%d)", ret);
+		if (ret < 0)
+			cause = 96;
+		else if (ret > 0)
+			cause = 100;
+	} 
+	if ((p = findie(skb->data, skb->len, IE_FACILITY, 0)))
+		l3ni1_parse_facility(pc->st, pc, pc->callref, p);
+	ret = check_infoelements(pc, skb, ie_DISCONNECT);
+	if (ERR_IE_COMPREHENSION == ret)
+		cause = 96;
+	else if ((!cause) && (ERR_IE_UNRECOGNIZED == ret))
+		cause = 99;
+	ret = pc->state;
+	newl3state(pc, 12);
+	if (cause)
+		newl3state(pc, 19);
+       	if (11 != ret)
+		pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc);
+       	else if (!cause)
+		   l3ni1_release_req(pc, pr, NULL);
+	if (cause) {
+		l3ni1_message_cause(pc, MT_RELEASE, cause);
+		L3AddTimer(&pc->timer, T308, CC_T308_1);
+	}
+}
+
+static void
+l3ni1_connect(struct l3_process *pc, u_char pr, void *arg)
+{
+	struct sk_buff *skb = arg;
+	int ret;
+
+	ret = check_infoelements(pc, skb, ie_CONNECT);
+	if (ERR_IE_COMPREHENSION == ret) {
+		l3ni1_std_ie_err(pc, ret);
+		return;
+	}
+	L3DelTimer(&pc->timer);	/* T310 */
+	newl3state(pc, 10);
+	pc->para.chargeinfo = 0;
+	/* here should inserted COLP handling KKe */
+	if (ret)
+		l3ni1_std_ie_err(pc, ret);
+	pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc);
+}
+
+static void
+l3ni1_alerting(struct l3_process *pc, u_char pr, void *arg)
+{
+	struct sk_buff *skb = arg;
+	int ret;
+
+	ret = check_infoelements(pc, skb, ie_ALERTING);
+	if (ERR_IE_COMPREHENSION == ret) {
+		l3ni1_std_ie_err(pc, ret);
+		return;
+	}
+	L3DelTimer(&pc->timer);	/* T304 */
+	newl3state(pc, 4);
+	if (ret)
+		l3ni1_std_ie_err(pc, ret);
+	pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc);
+}
+
+static void
+l3ni1_setup(struct l3_process *pc, u_char pr, void *arg)
+{
+	u_char *p;
+	int bcfound = 0;
+	char tmp[80];
+	struct sk_buff *skb = arg;
+	int id;
+	int err = 0;
+
+	/*
+	 * Bearer Capabilities
+	 */
+	p = skb->data;
+	/* only the first occurence 'll be detected ! */
+	if ((p = findie(p, skb->len, 0x04, 0))) {
+		if ((p[1] < 2) || (p[1] > 11))
+			err = 1;
+		else {
+			pc->para.setup.si2 = 0;
+			switch (p[2] & 0x7f) {
+				case 0x00: /* Speech */
+				case 0x10: /* 3.1 Khz audio */
+					pc->para.setup.si1 = 1;
+					break;
+				case 0x08: /* Unrestricted digital information */
+					pc->para.setup.si1 = 7;
+/* JIM, 05.11.97 I wanna set service indicator 2 */
+#if EXT_BEARER_CAPS
+					pc->para.setup.si2 = DecodeSI2(skb);
+#endif
+					break;
+				case 0x09: /* Restricted digital information */
+					pc->para.setup.si1 = 2;
+					break;
+				case 0x11:
+					/* Unrestr. digital information  with 
+					 * tones/announcements ( or 7 kHz audio
+					 */
+					pc->para.setup.si1 = 3;
+					break;
+				case 0x18: /* Video */
+					pc->para.setup.si1 = 4;
+					break;
+				default:
+					err = 2;
+					break;
+			}
+			switch (p[3] & 0x7f) {
+				case 0x40: /* packed mode */
+					pc->para.setup.si1 = 8;
+					break;
+				case 0x10: /* 64 kbit */
+				case 0x11: /* 2*64 kbit */
+				case 0x13: /* 384 kbit */
+				case 0x15: /* 1536 kbit */
+				case 0x17: /* 1920 kbit */
+					pc->para.moderate = p[3] & 0x7f;
+					break;
+				default:
+					err = 3;
+					break;
+			}
+		}
+		if (pc->debug & L3_DEB_SI)
+			l3_debug(pc->st, "SI=%d, AI=%d",
+				pc->para.setup.si1, pc->para.setup.si2);
+		if (err) {
+			if (pc->debug & L3_DEB_WARN)
+				l3_debug(pc->st, "setup with wrong bearer(l=%d:%x,%x)",
+					p[1], p[2], p[3]);
+			pc->para.cause = 100;
+			l3ni1_msg_without_setup(pc, pr, NULL);
+			return;
+		}
+	} else {
+		if (pc->debug & L3_DEB_WARN)
+			l3_debug(pc->st, "setup without bearer capabilities");
+		/* ETS 300-104 1.3.3 */
+		pc->para.cause = 96;
+		l3ni1_msg_without_setup(pc, pr, NULL);
+		return;
+	}
+	/*
+	 * Channel Identification
+	 */
+	if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) {
+		if ((pc->para.bchannel = id)) {
+			if ((3 == id) && (0x10 == pc->para.moderate)) {
+				if (pc->debug & L3_DEB_WARN)
+					l3_debug(pc->st, "setup with wrong chid %x",
+						id);
+				pc->para.cause = 100;
+				l3ni1_msg_without_setup(pc, pr, NULL);
+				return;
+			}
+			bcfound++;
+		} else 
+                   { if (pc->debug & L3_DEB_WARN)
+			 l3_debug(pc->st, "setup without bchannel, call waiting");
+                     bcfound++;
+                   } 
+	} else {
+		if (pc->debug & L3_DEB_WARN)
+			l3_debug(pc->st, "setup with wrong chid ret %d", id);
+		if (id == -1)
+			pc->para.cause = 96;
+		else
+			pc->para.cause = 100;
+		l3ni1_msg_without_setup(pc, pr, NULL);
+		return;
+	}
+	/* Now we are on none mandatory IEs */
+	err = check_infoelements(pc, skb, ie_SETUP);
+	if (ERR_IE_COMPREHENSION == err) {
+		pc->para.cause = 96;
+		l3ni1_msg_without_setup(pc, pr, NULL);
+		return;
+	}
+	p = skb->data;
+	if ((p = findie(p, skb->len, 0x70, 0)))
+		iecpy(pc->para.setup.eazmsn, p, 1);
+	else
+		pc->para.setup.eazmsn[0] = 0;
+
+	p = skb->data;
+	if ((p = findie(p, skb->len, 0x71, 0))) {
+		/* Called party subaddress */
+		if ((p[1] >= 2) && (p[2] == 0x80) && (p[3] == 0x50)) {
+			tmp[0] = '.';
+			iecpy(&tmp[1], p, 2);
+			strcat(pc->para.setup.eazmsn, tmp);
+		} else if (pc->debug & L3_DEB_WARN)
+			l3_debug(pc->st, "wrong called subaddress");
+	}
+	p = skb->data;
+	if ((p = findie(p, skb->len, 0x6c, 0))) {
+		pc->para.setup.plan = p[2];
+		if (p[2] & 0x80) {
+			iecpy(pc->para.setup.phone, p, 1);
+			pc->para.setup.screen = 0;
+		} else {
+			iecpy(pc->para.setup.phone, p, 2);
+			pc->para.setup.screen = p[3];
+		}
+	} else {
+		pc->para.setup.phone[0] = 0;
+		pc->para.setup.plan = 0;
+		pc->para.setup.screen = 0;
+	}
+	p = skb->data;
+	if ((p = findie(p, skb->len, 0x6d, 0))) {
+		/* Calling party subaddress */
+		if ((p[1] >= 2) && (p[2] == 0x80) && (p[3] == 0x50)) {
+			tmp[0] = '.';
+			iecpy(&tmp[1], p, 2);
+			strcat(pc->para.setup.phone, tmp);
+		} else if (pc->debug & L3_DEB_WARN)
+			l3_debug(pc->st, "wrong calling subaddress");
+	}
+	newl3state(pc, 6);
+	if (err) /* STATUS for none mandatory IE errors after actions are taken */
+		l3ni1_std_ie_err(pc, err);
+	pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc);
+}
+
+static void
+l3ni1_reset(struct l3_process *pc, u_char pr, void *arg)
+{
+	ni1_release_l3_process(pc);
+}
+
+static void
+l3ni1_disconnect_req(struct l3_process *pc, u_char pr, void *arg)
+{
+	struct sk_buff *skb;
+	u_char tmp[16+40];
+	u_char *p = tmp;
+	int l;
+	u_char cause = 16;
+
+	if (pc->para.cause != NO_CAUSE)
+		cause = pc->para.cause;
+
+	StopAllL3Timer(pc);
+
+	MsgHead(p, pc->callref, MT_DISCONNECT);
+
+	*p++ = IE_CAUSE;
+	*p++ = 0x2;
+	*p++ = 0x80;
+	*p++ = cause | 0x80;
+
+        if (pc->prot.ni1.uus1_data[0])
+	 { *p++ = IE_USER_USER; /* UUS info element */
+           *p++ = strlen(pc->prot.ni1.uus1_data) + 1;
+           *p++ = 0x04; /* IA5 chars */
+           strcpy(p,pc->prot.ni1.uus1_data);
+           p += strlen(pc->prot.ni1.uus1_data);
+           pc->prot.ni1.uus1_data[0] = '\0';   
+         } 
+
+	l = p - tmp;
+	if (!(skb = l3_alloc_skb(l)))
+		return;
+	memcpy(skb_put(skb, l), tmp, l);
+	newl3state(pc, 11);
+	l3_msg(pc->st, DL_DATA | REQUEST, skb);
+	L3AddTimer(&pc->timer, T305, CC_T305);
+}
+
+static void
+l3ni1_setup_rsp(struct l3_process *pc, u_char pr,
+		 void *arg)
+{
+        if (!pc->para.bchannel) 
+	 { if (pc->debug & L3_DEB_WARN)
+	       l3_debug(pc->st, "D-chan connect for waiting call");
+           l3ni1_disconnect_req(pc, pr, arg);
+           return;
+         }
+	newl3state(pc, 8);
+	if (pc->debug & L3_DEB_WARN)
+		l3_debug(pc->st, "D-chan connect for waiting call");
+	l3ni1_message_plus_chid(pc, MT_CONNECT); /* GE 05/09/00 */ 
+	L3DelTimer(&pc->timer);
+	L3AddTimer(&pc->timer, T313, CC_T313);
+}
+
+static void
+l3ni1_connect_ack(struct l3_process *pc, u_char pr, void *arg)
+{
+	struct sk_buff *skb = arg;
+	int ret;
+
+	ret = check_infoelements(pc, skb, ie_CONNECT_ACKNOWLEDGE);
+	if (ERR_IE_COMPREHENSION == ret) {
+		l3ni1_std_ie_err(pc, ret);
+		return;
+	}
+	newl3state(pc, 10);
+	L3DelTimer(&pc->timer);
+	if (ret)
+		l3ni1_std_ie_err(pc, ret);
+	pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc);
+}
+
+static void
+l3ni1_reject_req(struct l3_process *pc, u_char pr, void *arg)
+{
+	struct sk_buff *skb;
+	u_char tmp[16];
+	u_char *p = tmp;
+	int l;
+	u_char cause = 21;
+
+	if (pc->para.cause != NO_CAUSE)
+		cause = pc->para.cause;
+
+	MsgHead(p, pc->callref, MT_RELEASE_COMPLETE);
+
+	*p++ = IE_CAUSE;
+	*p++ = 0x2;
+	*p++ = 0x80;
+	*p++ = cause | 0x80;
+
+	l = p - tmp;
+	if (!(skb = l3_alloc_skb(l)))
+		return;
+	memcpy(skb_put(skb, l), tmp, l);
+	l3_msg(pc->st, DL_DATA | REQUEST, skb);
+	pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+	newl3state(pc, 0);
+	ni1_release_l3_process(pc);
+}
+
+static void
+l3ni1_release(struct l3_process *pc, u_char pr, void *arg)
+{
+	struct sk_buff *skb = arg;
+	u_char *p;
+	int ret, cause=0;
+
+	StopAllL3Timer(pc);
+	if ((ret = l3ni1_get_cause(pc, skb))>0) {
+		if (pc->debug & L3_DEB_WARN)
+			l3_debug(pc->st, "REL get_cause ret(%d)", ret);
+	} else if (ret<0)
+		pc->para.cause = NO_CAUSE;
+	if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) {
+		l3ni1_parse_facility(pc->st, pc, pc->callref, p);
+	}
+	if ((ret<0) && (pc->state != 11))
+		cause = 96;
+	else if (ret>0)
+		cause = 100;
+	ret = check_infoelements(pc, skb, ie_RELEASE);
+	if (ERR_IE_COMPREHENSION == ret)
+		cause = 96;
+	else if ((ERR_IE_UNRECOGNIZED == ret) && (!cause))
+		cause = 99;  
+	if (cause)
+		l3ni1_message_cause(pc, MT_RELEASE_COMPLETE, cause);
+	else
+		l3ni1_message(pc, MT_RELEASE_COMPLETE);
+	pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+	newl3state(pc, 0);
+	ni1_release_l3_process(pc);
+}
+
+static void
+l3ni1_alert_req(struct l3_process *pc, u_char pr,
+		 void *arg)
+{
+	newl3state(pc, 7);
+	if (!pc->prot.ni1.uus1_data[0]) 
+		l3ni1_message(pc, MT_ALERTING);
+	else
+		l3ni1_msg_with_uus(pc, MT_ALERTING); 
+}
+
+static void
+l3ni1_proceed_req(struct l3_process *pc, u_char pr,
+		   void *arg)
+{
+	newl3state(pc, 9);
+	l3ni1_message(pc, MT_CALL_PROCEEDING);
+	pc->st->l3.l3l4(pc->st, CC_PROCEED_SEND | INDICATION, pc); 
+}
+
+static void
+l3ni1_setup_ack_req(struct l3_process *pc, u_char pr,
+		   void *arg)
+{
+	newl3state(pc, 25);
+	L3DelTimer(&pc->timer);
+	L3AddTimer(&pc->timer, T302, CC_T302);
+	l3ni1_message(pc, MT_SETUP_ACKNOWLEDGE);
+}
+
+/********************************************/
+/* deliver a incoming display message to HL */
+/********************************************/
+static void
+l3ni1_deliver_display(struct l3_process *pc, int pr, u_char *infp)
+{       u_char len;
+        isdn_ctrl ic; 
+	struct IsdnCardState *cs;
+        char *p; 
+
+        if (*infp++ != IE_DISPLAY) return;
+        if ((len = *infp++) > 80) return; /* total length <= 82 */
+	if (!pc->chan) return;
+
+	p = ic.parm.display; 
+        while (len--)
+	  *p++ = *infp++;
+	*p = '\0';
+	ic.command = ISDN_STAT_DISPLAY;
+	cs = pc->st->l1.hardware;
+	ic.driver = cs->myid;
+	ic.arg = pc->chan->chan; 
+	cs->iif.statcallb(&ic);
+} /* l3ni1_deliver_display */
+
+
+static void
+l3ni1_progress(struct l3_process *pc, u_char pr, void *arg)
+{
+	struct sk_buff *skb = arg;
+	int err = 0;
+	u_char *p;
+
+	if ((p = findie(skb->data, skb->len, IE_PROGRESS, 0))) {
+		if (p[1] != 2) {
+			err = 1;
+			pc->para.cause = 100;
+		} else if (!(p[2] & 0x70)) {
+			switch (p[2]) {
+				case 0x80:
+				case 0x81:
+				case 0x82:
+				case 0x84:
+				case 0x85:
+				case 0x87:
+				case 0x8a:
+					switch (p[3]) {
+						case 0x81:
+						case 0x82:
+						case 0x83:
+						case 0x84:
+						case 0x88:
+							break;
+						default:
+							err = 2;
+							pc->para.cause = 100;
+							break;
+					}
+					break;
+				default:
+					err = 3;
+					pc->para.cause = 100;
+					break;
+			}
+		}
+	} else {
+		pc->para.cause = 96;
+		err = 4;
+	}
+	if (err) {	
+		if (pc->debug & L3_DEB_WARN)
+			l3_debug(pc->st, "progress error %d", err);
+		l3ni1_status_send(pc, pr, NULL);
+		return;
+	}
+	/* Now we are on none mandatory IEs */
+	err = check_infoelements(pc, skb, ie_PROGRESS);
+	if (err)
+		l3ni1_std_ie_err(pc, err);
+	if (ERR_IE_COMPREHENSION != err)
+		pc->st->l3.l3l4(pc->st, CC_PROGRESS | INDICATION, pc);
+}
+
+static void
+l3ni1_notify(struct l3_process *pc, u_char pr, void *arg)
+{
+	struct sk_buff *skb = arg;
+	int err = 0;
+	u_char *p;
+
+	if ((p = findie(skb->data, skb->len, IE_NOTIFY, 0))) {
+		if (p[1] != 1) {
+			err = 1;
+			pc->para.cause = 100;
+		} else {
+			switch (p[2]) {
+				case 0x80:
+				case 0x81:
+				case 0x82:
+					break;
+				default:
+					pc->para.cause = 100;
+					err = 2;
+					break;
+			}
+		}
+	} else {
+		pc->para.cause = 96;
+		err = 3;
+	}
+	if (err) {	
+		if (pc->debug & L3_DEB_WARN)
+			l3_debug(pc->st, "notify error %d", err);
+		l3ni1_status_send(pc, pr, NULL);
+		return;
+	}
+	/* Now we are on none mandatory IEs */
+	err = check_infoelements(pc, skb, ie_NOTIFY);
+	if (err)
+		l3ni1_std_ie_err(pc, err);
+	if (ERR_IE_COMPREHENSION != err)
+		pc->st->l3.l3l4(pc->st, CC_NOTIFY | INDICATION, pc);
+}
+
+static void
+l3ni1_status_enq(struct l3_process *pc, u_char pr, void *arg)
+{
+	int ret;
+	struct sk_buff *skb = arg;
+
+	ret = check_infoelements(pc, skb, ie_STATUS_ENQUIRY);
+	l3ni1_std_ie_err(pc, ret);
+	pc->para.cause = 30; /* response to STATUS_ENQUIRY */
+        l3ni1_status_send(pc, pr, NULL);
+}
+
+static void
+l3ni1_information(struct l3_process *pc, u_char pr, void *arg)
+{
+	int ret;
+	struct sk_buff *skb = arg;
+	u_char *p;
+	char tmp[32];
+
+	ret = check_infoelements(pc, skb, ie_INFORMATION);
+	if (ret)
+		l3ni1_std_ie_err(pc, ret);
+	if (pc->state == 25) { /* overlap receiving */
+		L3DelTimer(&pc->timer);
+		p = skb->data;
+		if ((p = findie(p, skb->len, 0x70, 0))) {
+			iecpy(tmp, p, 1);
+			strcat(pc->para.setup.eazmsn, tmp);
+			pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
+		}
+		L3AddTimer(&pc->timer, T302, CC_T302);
+	}
+}
+
+/******************************/
+/* handle deflection requests */
+/******************************/
+static void l3ni1_redir_req(struct l3_process *pc, u_char pr, void *arg)
+{
+	struct sk_buff *skb;
+	u_char tmp[128];
+	u_char *p = tmp;
+        u_char *subp;
+        u_char len_phone = 0;
+        u_char len_sub = 0;
+	int l; 
+
+
+        strcpy(pc->prot.ni1.uus1_data,pc->chan->setup.eazmsn); /* copy uus element if available */
+        if (!pc->chan->setup.phone[0])
+          { pc->para.cause = -1;
+            l3ni1_disconnect_req(pc,pr,arg); /* disconnect immediately */
+            return;
+          } /* only uus */
+ 
+        if (pc->prot.ni1.invoke_id) 
+          free_invoke_id(pc->st,pc->prot.ni1.invoke_id);
+ 
+        if (!(pc->prot.ni1.invoke_id = new_invoke_id(pc->st))) 
+          return;
+
+        MsgHead(p, pc->callref, MT_FACILITY);
+
+        for (subp = pc->chan->setup.phone; (*subp) && (*subp != '.'); subp++) len_phone++; /* len of phone number */
+        if (*subp++ == '.') len_sub = strlen(subp) + 2; /* length including info subadress element */ 
+
+	*p++ = 0x1c;   /* Facility info element */
+        *p++ = len_phone + len_sub + 2 + 2 + 8 + 3 + 3; /* length of element */
+        *p++ = 0x91;  /* remote operations protocol */
+        *p++ = 0xa1;  /* invoke component */
+	  
+        *p++ = len_phone + len_sub + 2 + 2 + 8 + 3; /* length of data */
+        *p++ = 0x02;  /* invoke id tag, integer */
+	*p++ = 0x01;  /* length */
+        *p++ = pc->prot.ni1.invoke_id;  /* invoke id */ 
+        *p++ = 0x02;  /* operation value tag, integer */
+	*p++ = 0x01;  /* length */
+        *p++ = 0x0D;  /* Call Deflect */
+	  
+        *p++ = 0x30;  /* sequence phone number */
+        *p++ = len_phone + 2 + 2 + 3 + len_sub; /* length */
+	  
+        *p++ = 0x30;  /* Deflected to UserNumber */
+        *p++ = len_phone+2+len_sub; /* length */
+        *p++ = 0x80; /* NumberDigits */
+	*p++ = len_phone; /* length */
+        for (l = 0; l < len_phone; l++)
+	 *p++ = pc->chan->setup.phone[l];
+
+        if (len_sub)
+	  { *p++ = 0x04; /* called party subadress */
+            *p++ = len_sub - 2;
+            while (*subp) *p++ = *subp++;
+          }
+
+        *p++ = 0x01; /* screening identifier */
+        *p++ = 0x01;
+        *p++ = pc->chan->setup.screen;
+
+	l = p - tmp;
+	if (!(skb = l3_alloc_skb(l))) return;
+	memcpy(skb_put(skb, l), tmp, l);
+
+        l3_msg(pc->st, DL_DATA | REQUEST, skb);
+} /* l3ni1_redir_req */
+
+/********************************************/
+/* handle deflection request in early state */
+/********************************************/
+static void l3ni1_redir_req_early(struct l3_process *pc, u_char pr, void *arg)
+{
+  l3ni1_proceed_req(pc,pr,arg);
+  l3ni1_redir_req(pc,pr,arg);
+} /* l3ni1_redir_req_early */
+
+/***********************************************/
+/* handle special commands for this protocol.  */
+/* Examples are call independant services like */
+/* remote operations with dummy  callref.      */
+/***********************************************/
+static int l3ni1_cmd_global(struct PStack *st, isdn_ctrl *ic)
+{ u_char id;
+  u_char temp[265];
+  u_char *p = temp;
+  int i, l, proc_len; 
+  struct sk_buff *skb;
+  struct l3_process *pc = NULL;
+
+  switch (ic->arg)
+   { case NI1_CMD_INVOKE:
+       if (ic->parm.ni1_io.datalen < 0) return(-2); /* invalid parameter */ 
+
+       for (proc_len = 1, i = ic->parm.ni1_io.proc >> 8; i; i++) 
+         i = i >> 8; /* add one byte */    
+       l = ic->parm.ni1_io.datalen + proc_len + 8; /* length excluding ie header */
+       if (l > 255) 
+         return(-2); /* too long */
+
+       if (!(id = new_invoke_id(st))) 
+         return(0); /* first get a invoke id -> return if no available */
+       
+       i = -1; 
+       MsgHead(p, i, MT_FACILITY); /* build message head */
+       *p++ = 0x1C; /* Facility IE */
+       *p++ = l; /* length of ie */
+       *p++ = 0x91; /* remote operations */
+       *p++ = 0xA1; /* invoke */
+       *p++ = l - 3; /* length of invoke */
+       *p++ = 0x02; /* invoke id tag */
+       *p++ = 0x01; /* length is 1 */
+       *p++ = id; /* invoke id */
+       *p++ = 0x02; /* operation */
+       *p++ = proc_len; /* length of operation */
+       
+       for (i = proc_len; i; i--)
+         *p++ = (ic->parm.ni1_io.proc >> (i-1)) & 0xFF;
+       memcpy(p, ic->parm.ni1_io.data, ic->parm.ni1_io.datalen); /* copy data */
+       l = (p - temp) + ic->parm.ni1_io.datalen; /* total length */         
+
+       if (ic->parm.ni1_io.timeout > 0)
+        if (!(pc = ni1_new_l3_process(st, -1)))
+          { free_invoke_id(st, id);
+            return(-2);
+          } 
+       pc->prot.ni1.ll_id = ic->parm.ni1_io.ll_id; /* remember id */ 
+       pc->prot.ni1.proc = ic->parm.ni1_io.proc; /* and procedure */
+
+       if (!(skb = l3_alloc_skb(l))) 
+         { free_invoke_id(st, id);
+           if (pc) ni1_release_l3_process(pc);
+           return(-2);
+         }
+       memcpy(skb_put(skb, l), temp, l);
+       
+       if (pc)
+        { pc->prot.ni1.invoke_id = id; /* remember id */
+          L3AddTimer(&pc->timer, ic->parm.ni1_io.timeout, CC_TNI1_IO | REQUEST);
+        }
+       
+       l3_msg(st, DL_DATA | REQUEST, skb);
+       ic->parm.ni1_io.hl_id = id; /* return id */
+       return(0);
+
+     case NI1_CMD_INVOKE_ABORT:
+       if ((pc = l3ni1_search_dummy_proc(st, ic->parm.ni1_io.hl_id)))
+	{ L3DelTimer(&pc->timer); /* remove timer */
+          ni1_release_l3_process(pc);
+          return(0); 
+        } 
+       else
+	{ l3_debug(st, "l3ni1_cmd_global abort unknown id");
+          return(-2);
+        } 
+       break;
+    
+     default: 
+       l3_debug(st, "l3ni1_cmd_global unknown cmd 0x%lx", ic->arg);
+       return(-1);  
+   } /* switch ic-> arg */
+  return(-1);
+} /* l3ni1_cmd_global */
+
+static void 
+l3ni1_io_timer(struct l3_process *pc)
+{ isdn_ctrl ic;
+  struct IsdnCardState *cs = pc->st->l1.hardware;
+
+  L3DelTimer(&pc->timer); /* remove timer */
+
+  ic.driver = cs->myid;
+  ic.command = ISDN_STAT_PROT;
+  ic.arg = NI1_STAT_INVOKE_ERR;
+  ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id;
+  ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id;
+  ic.parm.ni1_io.proc = pc->prot.ni1.proc;
+  ic.parm.ni1_io.timeout= -1;
+  ic.parm.ni1_io.datalen = 0;
+  ic.parm.ni1_io.data = NULL;
+  free_invoke_id(pc->st, pc->prot.ni1.invoke_id);
+  pc->prot.ni1.invoke_id = 0; /* reset id */
+
+  cs->iif.statcallb(&ic);
+
+  ni1_release_l3_process(pc); 
+} /* l3ni1_io_timer */
+
+static void
+l3ni1_release_ind(struct l3_process *pc, u_char pr, void *arg)
+{
+	u_char *p;
+	struct sk_buff *skb = arg;
+	int callState = 0;
+	p = skb->data;
+
+	if ((p = findie(p, skb->len, IE_CALL_STATE, 0))) {
+		p++;
+		if (1 == *p++)
+			callState = *p;
+	}
+	if (callState == 0) {
+		/* ETS 300-104 7.6.1, 8.6.1, 10.6.1... and 16.1
+		 * set down layer 3 without sending any message
+		 */
+		pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+		newl3state(pc, 0);
+		ni1_release_l3_process(pc);
+	} else {
+		pc->st->l3.l3l4(pc->st, CC_IGNORE | INDICATION, pc);
+	}
+}
+
+static void
+l3ni1_dummy(struct l3_process *pc, u_char pr, void *arg)
+{
+}
+
+static void
+l3ni1_t302(struct l3_process *pc, u_char pr, void *arg)
+{
+	L3DelTimer(&pc->timer);
+	pc->para.loc = 0;
+	pc->para.cause = 28; /* invalid number */
+	l3ni1_disconnect_req(pc, pr, NULL);
+	pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
+}
+
+static void
+l3ni1_t303(struct l3_process *pc, u_char pr, void *arg)
+{
+	if (pc->N303 > 0) {
+		pc->N303--;
+		L3DelTimer(&pc->timer);
+		l3ni1_setup_req(pc, pr, arg);
+	} else {
+		L3DelTimer(&pc->timer);
+		l3ni1_message_cause(pc, MT_RELEASE_COMPLETE, 102);
+		pc->st->l3.l3l4(pc->st, CC_NOSETUP_RSP, pc);
+		ni1_release_l3_process(pc);
+	}
+}
+
+static void
+l3ni1_t304(struct l3_process *pc, u_char pr, void *arg)
+{
+	L3DelTimer(&pc->timer);
+	pc->para.loc = 0;
+	pc->para.cause = 102;
+	l3ni1_disconnect_req(pc, pr, NULL);
+	pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
+
+}
+
+static void
+l3ni1_t305(struct l3_process *pc, u_char pr, void *arg)
+{
+	u_char tmp[16];
+	u_char *p = tmp;
+	int l;
+	struct sk_buff *skb;
+	u_char cause = 16;
+
+	L3DelTimer(&pc->timer);
+	if (pc->para.cause != NO_CAUSE)
+		cause = pc->para.cause;
+
+	MsgHead(p, pc->callref, MT_RELEASE);
+
+	*p++ = IE_CAUSE;
+	*p++ = 0x2;
+	*p++ = 0x80;
+	*p++ = cause | 0x80;
+
+	l = p - tmp;
+	if (!(skb = l3_alloc_skb(l)))
+		return;
+	memcpy(skb_put(skb, l), tmp, l);
+	newl3state(pc, 19);
+	l3_msg(pc->st, DL_DATA | REQUEST, skb);
+	L3AddTimer(&pc->timer, T308, CC_T308_1);
+}
+
+static void
+l3ni1_t310(struct l3_process *pc, u_char pr, void *arg)
+{
+	L3DelTimer(&pc->timer);
+	pc->para.loc = 0;
+	pc->para.cause = 102;
+	l3ni1_disconnect_req(pc, pr, NULL);
+	pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
+}
+
+static void
+l3ni1_t313(struct l3_process *pc, u_char pr, void *arg)
+{
+	L3DelTimer(&pc->timer);
+	pc->para.loc = 0;
+	pc->para.cause = 102;
+	l3ni1_disconnect_req(pc, pr, NULL);
+	pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc);
+}
+
+static void
+l3ni1_t308_1(struct l3_process *pc, u_char pr, void *arg)
+{
+	newl3state(pc, 19);
+	L3DelTimer(&pc->timer);
+	l3ni1_message(pc, MT_RELEASE);
+	L3AddTimer(&pc->timer, T308, CC_T308_2);
+}
+
+static void
+l3ni1_t308_2(struct l3_process *pc, u_char pr, void *arg)
+{
+	L3DelTimer(&pc->timer);
+	pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc);
+	ni1_release_l3_process(pc);
+}
+
+static void
+l3ni1_t318(struct l3_process *pc, u_char pr, void *arg)
+{
+	L3DelTimer(&pc->timer);
+	pc->para.cause = 102;	/* Timer expiry */
+	pc->para.loc = 0;	/* local */
+	pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc);
+	newl3state(pc, 19);
+	l3ni1_message(pc, MT_RELEASE);
+	L3AddTimer(&pc->timer, T308, CC_T308_1);
+}
+
+static void
+l3ni1_t319(struct l3_process *pc, u_char pr, void *arg)
+{
+	L3DelTimer(&pc->timer);
+	pc->para.cause = 102;	/* Timer expiry */
+	pc->para.loc = 0;	/* local */
+	pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc);
+	newl3state(pc, 10);
+}
+
+static void
+l3ni1_restart(struct l3_process *pc, u_char pr, void *arg)
+{
+	L3DelTimer(&pc->timer);
+	pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+	ni1_release_l3_process(pc);
+}
+
+static void
+l3ni1_status(struct l3_process *pc, u_char pr, void *arg)
+{
+	u_char *p;
+	struct sk_buff *skb = arg;
+	int ret; 
+	u_char cause = 0, callState = 0;
+	
+	if ((ret = l3ni1_get_cause(pc, skb))) {
+		if (pc->debug & L3_DEB_WARN)
+			l3_debug(pc->st, "STATUS get_cause ret(%d)",ret);
+		if (ret < 0)
+			cause = 96;
+		else if (ret > 0)
+			cause = 100;
+	}
+	if ((p = findie(skb->data, skb->len, IE_CALL_STATE, 0))) {
+		p++;
+		if (1 == *p++) {
+			callState = *p;
+			if (!ie_in_set(pc, *p, l3_valid_states))
+				cause = 100;
+		} else
+			cause = 100;
+	} else
+		cause = 96;
+	if (!cause) { /*  no error before */
+		ret = check_infoelements(pc, skb, ie_STATUS);
+		if (ERR_IE_COMPREHENSION == ret)
+			cause = 96;
+		else if (ERR_IE_UNRECOGNIZED == ret)
+			cause = 99;
+	}
+	if (cause) {
+		u_char tmp;
+		
+		if (pc->debug & L3_DEB_WARN)
+			l3_debug(pc->st, "STATUS error(%d/%d)",ret,cause);
+		tmp = pc->para.cause;
+		pc->para.cause = cause;
+		l3ni1_status_send(pc, 0, NULL);
+		if (cause == 99)
+			pc->para.cause = tmp;
+		else
+			return;
+	}
+	cause = pc->para.cause;
+	if (((cause & 0x7f) == 111) && (callState == 0)) {
+		/* ETS 300-104 7.6.1, 8.6.1, 10.6.1...
+		 * if received MT_STATUS with cause == 111 and call
+		 * state == 0, then we must set down layer 3
+		 */
+		pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+		newl3state(pc, 0);
+		ni1_release_l3_process(pc);
+	}
+}
+
+static void
+l3ni1_facility(struct l3_process *pc, u_char pr, void *arg)
+{
+	struct sk_buff *skb = arg;
+	int ret;
+	
+	ret = check_infoelements(pc, skb, ie_FACILITY);
+	l3ni1_std_ie_err(pc, ret);
+ 	  {
+		u_char *p;
+		if ((p = findie(skb->data, skb->len, IE_FACILITY, 0)))
+			l3ni1_parse_facility(pc->st, pc, pc->callref, p);
+	}
+}
+
+static void
+l3ni1_suspend_req(struct l3_process *pc, u_char pr, void *arg)
+{
+	struct sk_buff *skb;
+	u_char tmp[32];
+	u_char *p = tmp;
+	u_char i, l;
+	u_char *msg = pc->chan->setup.phone;
+
+	MsgHead(p, pc->callref, MT_SUSPEND);
+	l = *msg++;
+	if (l && (l <= 10)) {	/* Max length 10 octets */
+		*p++ = IE_CALL_ID;
+		*p++ = l;
+		for (i = 0; i < l; i++)
+			*p++ = *msg++;
+	} else if (l) {
+		l3_debug(pc->st, "SUS wrong CALL_ID len %d", l);
+		return;
+	}
+	l = p - tmp;
+	if (!(skb = l3_alloc_skb(l)))
+		return;
+	memcpy(skb_put(skb, l), tmp, l);
+	l3_msg(pc->st, DL_DATA | REQUEST, skb);
+	newl3state(pc, 15);
+	L3AddTimer(&pc->timer, T319, CC_T319);
+}
+
+static void
+l3ni1_suspend_ack(struct l3_process *pc, u_char pr, void *arg)
+{
+	struct sk_buff *skb = arg;
+	int ret;
+
+	L3DelTimer(&pc->timer);
+	newl3state(pc, 0);
+	pc->para.cause = NO_CAUSE;
+	pc->st->l3.l3l4(pc->st, CC_SUSPEND | CONFIRM, pc);
+	/* We don't handle suspend_ack for IE errors now */
+	if ((ret = check_infoelements(pc, skb, ie_SUSPEND_ACKNOWLEDGE)))
+		if (pc->debug & L3_DEB_WARN)
+			l3_debug(pc->st, "SUSPACK check ie(%d)",ret);
+	ni1_release_l3_process(pc);
+}
+
+static void
+l3ni1_suspend_rej(struct l3_process *pc, u_char pr, void *arg)
+{
+	struct sk_buff *skb = arg;
+	int ret;
+
+	if ((ret = l3ni1_get_cause(pc, skb))) {
+		if (pc->debug & L3_DEB_WARN)
+			l3_debug(pc->st, "SUSP_REJ get_cause ret(%d)",ret);
+		if (ret < 0) 
+			pc->para.cause = 96;
+		else
+			pc->para.cause = 100;
+		l3ni1_status_send(pc, pr, NULL);
+		return;
+	}
+	ret = check_infoelements(pc, skb, ie_SUSPEND_REJECT);
+	if (ERR_IE_COMPREHENSION == ret) {
+		l3ni1_std_ie_err(pc, ret);
+		return;
+	}
+	L3DelTimer(&pc->timer);
+	pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc);
+	newl3state(pc, 10);
+	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
+		l3ni1_std_ie_err(pc, ret);
+}
+
+static void
+l3ni1_resume_req(struct l3_process *pc, u_char pr, void *arg)
+{
+	struct sk_buff *skb;
+	u_char tmp[32];
+	u_char *p = tmp;
+	u_char i, l;
+	u_char *msg = pc->para.setup.phone;
+
+	MsgHead(p, pc->callref, MT_RESUME);
+
+	l = *msg++;
+	if (l && (l <= 10)) {	/* Max length 10 octets */
+		*p++ = IE_CALL_ID;
+		*p++ = l;
+		for (i = 0; i < l; i++)
+			*p++ = *msg++;
+	} else if (l) {
+		l3_debug(pc->st, "RES wrong CALL_ID len %d", l);
+		return;
+	}
+	l = p - tmp;
+	if (!(skb = l3_alloc_skb(l)))
+		return;
+	memcpy(skb_put(skb, l), tmp, l);
+	l3_msg(pc->st, DL_DATA | REQUEST, skb);
+	newl3state(pc, 17);
+	L3AddTimer(&pc->timer, T318, CC_T318);
+}
+
+static void
+l3ni1_resume_ack(struct l3_process *pc, u_char pr, void *arg)
+{
+	struct sk_buff *skb = arg;
+	int id, ret;
+
+	if ((id = l3ni1_get_channel_id(pc, skb)) > 0) {
+		if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) {
+			if (pc->debug & L3_DEB_WARN)
+				l3_debug(pc->st, "resume ack with wrong chid %x", id);
+			pc->para.cause = 100;
+			l3ni1_status_send(pc, pr, NULL);
+			return;
+		}
+		pc->para.bchannel = id;
+	} else if (1 == pc->state) {
+		if (pc->debug & L3_DEB_WARN)
+			l3_debug(pc->st, "resume ack without chid (ret %d)", id);
+		pc->para.cause = 96;
+		l3ni1_status_send(pc, pr, NULL);
+		return;
+	}
+	ret = check_infoelements(pc, skb, ie_RESUME_ACKNOWLEDGE);
+	if (ERR_IE_COMPREHENSION == ret) {
+		l3ni1_std_ie_err(pc, ret);
+		return;
+	}
+	L3DelTimer(&pc->timer);
+	pc->st->l3.l3l4(pc->st, CC_RESUME | CONFIRM, pc);
+	newl3state(pc, 10);
+	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
+		l3ni1_std_ie_err(pc, ret);
+}
+
+static void
+l3ni1_resume_rej(struct l3_process *pc, u_char pr, void *arg)
+{
+	struct sk_buff *skb = arg;
+	int ret;
+
+	if ((ret = l3ni1_get_cause(pc, skb))) {
+		if (pc->debug & L3_DEB_WARN)
+			l3_debug(pc->st, "RES_REJ get_cause ret(%d)",ret);
+		if (ret < 0) 
+			pc->para.cause = 96;
+		else
+			pc->para.cause = 100;
+		l3ni1_status_send(pc, pr, NULL);
+		return;
+	}
+	ret = check_infoelements(pc, skb, ie_RESUME_REJECT);
+	if (ERR_IE_COMPREHENSION == ret) {
+		l3ni1_std_ie_err(pc, ret);
+		return;
+	}
+	L3DelTimer(&pc->timer);
+	pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc);
+	newl3state(pc, 0);
+	if (ret) /* STATUS for none mandatory IE errors after actions are taken */
+		l3ni1_std_ie_err(pc, ret);
+	ni1_release_l3_process(pc);
+}
+
+static void
+l3ni1_global_restart(struct l3_process *pc, u_char pr, void *arg)
+{
+	u_char tmp[32];
+	u_char *p;
+	u_char ri, ch = 0, chan = 0;
+	int l;
+	struct sk_buff *skb = arg;
+	struct l3_process *up;
+
+	newl3state(pc, 2);
+	L3DelTimer(&pc->timer);
+	p = skb->data;
+	if ((p = findie(p, skb->len, IE_RESTART_IND, 0))) {
+		ri = p[2];
+		l3_debug(pc->st, "Restart %x", ri);
+	} else {
+		l3_debug(pc->st, "Restart without restart IE");
+		ri = 0x86;
+	}
+	p = skb->data;
+	if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) {
+		chan = p[2] & 3;
+		ch = p[2];
+		if (pc->st->l3.debug)
+			l3_debug(pc->st, "Restart for channel %d", chan);
+	}
+	newl3state(pc, 2);
+	up = pc->st->l3.proc;
+	while (up) {
+		if ((ri & 7) == 7)
+			up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up);
+		else if (up->para.bchannel == chan)
+			up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up);
+		
+		up = up->next;
+	}
+	p = tmp;
+	MsgHead(p, pc->callref, MT_RESTART_ACKNOWLEDGE);
+	if (chan) {
+		*p++ = IE_CHANNEL_ID;
+		*p++ = 1;
+		*p++ = ch | 0x80;
+	}
+	*p++ = 0x79;		/* RESTART Ind */
+	*p++ = 1;
+	*p++ = ri;
+	l = p - tmp;
+	if (!(skb = l3_alloc_skb(l)))
+		return;
+	memcpy(skb_put(skb, l), tmp, l);
+	newl3state(pc, 0);
+	l3_msg(pc->st, DL_DATA | REQUEST, skb);
+}
+
+static void
+l3ni1_dl_reset(struct l3_process *pc, u_char pr, void *arg)
+{
+        pc->para.cause = 0x29;          /* Temporary failure */
+        pc->para.loc = 0;
+        l3ni1_disconnect_req(pc, pr, NULL);
+        pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
+}
+
+static void
+l3ni1_dl_release(struct l3_process *pc, u_char pr, void *arg)
+{
+        newl3state(pc, 0);
+        pc->para.cause = 0x1b;          /* Destination out of order */
+        pc->para.loc = 0;
+        pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
+        release_l3_process(pc);
+}
+
+static void
+l3ni1_dl_reestablish(struct l3_process *pc, u_char pr, void *arg)
+{
+        L3DelTimer(&pc->timer);
+        L3AddTimer(&pc->timer, T309, CC_T309);
+        l3_msg(pc->st, DL_ESTABLISH | REQUEST, NULL);
+}
+ 
+static void
+l3ni1_dl_reest_status(struct l3_process *pc, u_char pr, void *arg)
+{
+	L3DelTimer(&pc->timer);
+ 
+ 	pc->para.cause = 0x1F; /* normal, unspecified */
+	l3ni1_status_send(pc, 0, NULL);
+}
+
+static void l3ni1_SendSpid( struct l3_process *pc, u_char pr, struct sk_buff *skb, int iNewState )
+{
+	u_char         * p;
+	char           * pSPID;
+	struct Channel * pChan = pc->st->lli.userdata;
+	int              l;
+
+	if ( skb )
+		dev_kfree_skb( skb);
+
+	if ( !( pSPID = strchr( pChan->setup.eazmsn, ':' ) ) )
+	{
+		printk( KERN_ERR "SPID not supplied in EAZMSN %s\n", pChan->setup.eazmsn );
+		newl3state( pc, 0 );
+		pc->st->l3.l3l2( pc->st, DL_RELEASE | REQUEST, NULL );
+		return;
+	}
+
+	l = strlen( ++pSPID );
+	if ( !( skb = l3_alloc_skb( 5+l ) ) )
+	{
+		printk( KERN_ERR "HiSax can't get memory to send SPID\n" );
+		return;
+	}
+
+	p = skb_put( skb, 5 );
+	*p++ = PROTO_DIS_EURO;
+	*p++ = 0;
+	*p++ = MT_INFORMATION;
+	*p++ = IE_SPID;
+	*p++ = l;
+
+	memcpy( skb_put( skb, l ), pSPID, l );
+
+	newl3state( pc, iNewState );
+
+	L3DelTimer( &pc->timer );
+	L3AddTimer( &pc->timer, TSPID, CC_TSPID );
+
+	pc->st->l3.l3l2( pc->st, DL_DATA | REQUEST, skb );
+}
+
+static void l3ni1_spid_send( struct l3_process *pc, u_char pr, void *arg )
+{
+	l3ni1_SendSpid( pc, pr, arg, 20 );
+}
+
+void l3ni1_spid_epid( struct l3_process *pc, u_char pr, void *arg )
+{
+	struct sk_buff *skb = arg;
+
+	if ( skb->data[ 1 ] == 0 )
+		if ( skb->data[ 3 ] == IE_ENDPOINT_ID )
+		{
+			L3DelTimer( &pc->timer );
+			newl3state( pc, 0 );
+			l3_msg( pc->st, DL_ESTABLISH | CONFIRM, NULL );
+		}
+	dev_kfree_skb( skb);
+}
+
+static void l3ni1_spid_tout( struct l3_process *pc, u_char pr, void *arg )
+{
+	if ( pc->state < 22 )
+		l3ni1_SendSpid( pc, pr, arg, pc->state+1 );
+	else
+	{
+		L3DelTimer( &pc->timer );
+		dev_kfree_skb( arg);
+
+		printk( KERN_ERR "SPID not accepted\n" );
+		newl3state( pc, 0 );
+		pc->st->l3.l3l2( pc->st, DL_RELEASE | REQUEST, NULL );
+	}
+}
+
+/* *INDENT-OFF* */
+static struct stateentry downstatelist[] =
+{
+	{SBIT(0),
+	 CC_SETUP | REQUEST, l3ni1_setup_req},
+	{SBIT(0),
+	 CC_RESUME | REQUEST, l3ni1_resume_req},
+	{SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(25),
+	 CC_DISCONNECT | REQUEST, l3ni1_disconnect_req},
+	{SBIT(12),
+	 CC_RELEASE | REQUEST, l3ni1_release_req},
+	{ALL_STATES,
+	 CC_RESTART | REQUEST, l3ni1_restart},
+	{SBIT(6) | SBIT(25),
+	 CC_IGNORE | REQUEST, l3ni1_reset},
+	{SBIT(6) | SBIT(25),
+	 CC_REJECT | REQUEST, l3ni1_reject_req},
+	{SBIT(6) | SBIT(25),
+	 CC_PROCEED_SEND | REQUEST, l3ni1_proceed_req},
+	{SBIT(6),
+	 CC_MORE_INFO | REQUEST, l3ni1_setup_ack_req},
+	{SBIT(25),
+	 CC_MORE_INFO | REQUEST, l3ni1_dummy},
+	{SBIT(6) | SBIT(9) | SBIT(25),
+	 CC_ALERTING | REQUEST, l3ni1_alert_req},
+	{SBIT(6) | SBIT(7) | SBIT(9) | SBIT(25),
+	 CC_SETUP | RESPONSE, l3ni1_setup_rsp},
+	{SBIT(10),
+	 CC_SUSPEND | REQUEST, l3ni1_suspend_req},
+        {SBIT(7) | SBIT(9) | SBIT(25),
+         CC_REDIR | REQUEST, l3ni1_redir_req},
+        {SBIT(6),
+         CC_REDIR | REQUEST, l3ni1_redir_req_early},
+        {SBIT(9) | SBIT(25),
+         CC_DISCONNECT | REQUEST, l3ni1_disconnect_req},
+	{SBIT(25),
+	 CC_T302, l3ni1_t302},
+	{SBIT(1),
+	 CC_T303, l3ni1_t303},
+	{SBIT(2),
+	 CC_T304, l3ni1_t304},
+	{SBIT(3),
+	 CC_T310, l3ni1_t310},
+	{SBIT(8),
+	 CC_T313, l3ni1_t313},
+	{SBIT(11),
+	 CC_T305, l3ni1_t305},
+	{SBIT(15),
+	 CC_T319, l3ni1_t319},
+	{SBIT(17),
+	 CC_T318, l3ni1_t318},
+	{SBIT(19),
+	 CC_T308_1, l3ni1_t308_1},
+	{SBIT(19),
+	 CC_T308_2, l3ni1_t308_2},
+	{SBIT(10),
+	 CC_T309, l3ni1_dl_release},
+	{ SBIT( 20 ) | SBIT( 21 ) | SBIT( 22 ),
+	 CC_TSPID, l3ni1_spid_tout },
+};
+
+#define DOWNSLLEN \
+	(sizeof(downstatelist) / sizeof(struct stateentry))
+
+static struct stateentry datastatelist[] =
+{
+	{ALL_STATES,
+	 MT_STATUS_ENQUIRY, l3ni1_status_enq},
+	{ALL_STATES,
+	 MT_FACILITY, l3ni1_facility},
+	{SBIT(19),
+	 MT_STATUS, l3ni1_release_ind},
+	{ALL_STATES,
+	 MT_STATUS, l3ni1_status},
+	{SBIT(0),
+	 MT_SETUP, l3ni1_setup},
+	{SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) |
+	 SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25),
+	 MT_SETUP, l3ni1_dummy},
+	{SBIT(1) | SBIT(2),
+	 MT_CALL_PROCEEDING, l3ni1_call_proc},
+	{SBIT(1),
+	 MT_SETUP_ACKNOWLEDGE, l3ni1_setup_ack},
+	{SBIT(2) | SBIT(3),
+	 MT_ALERTING, l3ni1_alerting},
+	{SBIT(2) | SBIT(3),
+	 MT_PROGRESS, l3ni1_progress},
+	{SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) |
+	 SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25),
+	 MT_INFORMATION, l3ni1_information},
+	{SBIT(10) | SBIT(11) | SBIT(15),
+	 MT_NOTIFY, l3ni1_notify},
+	{SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10) |
+	 SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25),
+	 MT_RELEASE_COMPLETE, l3ni1_release_cmpl},
+	{SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(25),
+	 MT_RELEASE, l3ni1_release},
+	{SBIT(19),  MT_RELEASE, l3ni1_release_ind},
+	{SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(15) | SBIT(17) | SBIT(25),
+	 MT_DISCONNECT, l3ni1_disconnect},
+	{SBIT(19),
+	 MT_DISCONNECT, l3ni1_dummy},
+	{SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4),
+	 MT_CONNECT, l3ni1_connect},
+	{SBIT(8),
+	 MT_CONNECT_ACKNOWLEDGE, l3ni1_connect_ack},
+	{SBIT(15),
+	 MT_SUSPEND_ACKNOWLEDGE, l3ni1_suspend_ack},
+	{SBIT(15),
+	 MT_SUSPEND_REJECT, l3ni1_suspend_rej},
+	{SBIT(17),
+	 MT_RESUME_ACKNOWLEDGE, l3ni1_resume_ack},
+	{SBIT(17),
+	 MT_RESUME_REJECT, l3ni1_resume_rej},
+};
+
+#define DATASLLEN \
+	(sizeof(datastatelist) / sizeof(struct stateentry))
+
+static struct stateentry globalmes_list[] =
+{
+	{ALL_STATES,
+	 MT_STATUS, l3ni1_status},
+	{SBIT(0),
+	 MT_RESTART, l3ni1_global_restart},
+/*	{SBIT(1),
+	 MT_RESTART_ACKNOWLEDGE, l3ni1_restart_ack},
+*/
+	{ SBIT( 0 ), MT_DL_ESTABLISHED, l3ni1_spid_send },
+	{ SBIT( 20 ) | SBIT( 21 ) | SBIT( 22 ), MT_INFORMATION, l3ni1_spid_epid },
+};
+#define GLOBALM_LEN \
+	(sizeof(globalmes_list) / sizeof(struct stateentry))
+
+static struct stateentry manstatelist[] =
+{
+        {SBIT(2),
+         DL_ESTABLISH | INDICATION, l3ni1_dl_reset},
+        {SBIT(10),
+         DL_ESTABLISH | CONFIRM, l3ni1_dl_reest_status},
+        {SBIT(10),
+         DL_RELEASE | INDICATION, l3ni1_dl_reestablish},
+        {ALL_STATES,
+         DL_RELEASE | INDICATION, l3ni1_dl_release},
+};
+
+#define MANSLLEN \
+        (sizeof(manstatelist) / sizeof(struct stateentry))
+/* *INDENT-ON* */
+
+
+static void
+global_handler(struct PStack *st, int mt, struct sk_buff *skb)
+{
+	u_char tmp[16];
+	u_char *p = tmp;
+	int l;
+	int i;
+	struct l3_process *proc = st->l3.global;
+
+	if ( skb )	
+		proc->callref = skb->data[2]; /* cr flag */
+	else
+		proc->callref = 0;
+	for (i = 0; i < GLOBALM_LEN; i++)
+		if ((mt == globalmes_list[i].primitive) &&
+		    ((1 << proc->state) & globalmes_list[i].state))
+			break;
+	if (i == GLOBALM_LEN) {
+		if (st->l3.debug & L3_DEB_STATE) {
+			l3_debug(st, "ni1 global state %d mt %x unhandled",
+				proc->state, mt);
+		}
+		MsgHead(p, proc->callref, MT_STATUS);
+		*p++ = IE_CAUSE;
+		*p++ = 0x2;
+		*p++ = 0x80;
+		*p++ = 81 |0x80;	/* invalid cr */
+		*p++ = 0x14;		/* CallState */
+		*p++ = 0x1;
+		*p++ = proc->state & 0x3f;
+		l = p - tmp;
+		if (!(skb = l3_alloc_skb(l)))
+			return;
+		memcpy(skb_put(skb, l), tmp, l);
+		l3_msg(proc->st, DL_DATA | REQUEST, skb);
+	} else {
+		if (st->l3.debug & L3_DEB_STATE) {
+			l3_debug(st, "ni1 global %d mt %x",
+				proc->state, mt);
+		}
+		globalmes_list[i].rout(proc, mt, skb);
+	}
+}
+
+static void
+ni1up(struct PStack *st, int pr, void *arg)
+{
+	int i, mt, cr, cause, callState;
+	char *ptr;
+	u_char *p;
+	struct sk_buff *skb = arg;
+	struct l3_process *proc;
+
+	switch (pr) {
+		case (DL_DATA | INDICATION):
+		case (DL_UNIT_DATA | INDICATION):
+			break;
+		case (DL_ESTABLISH | INDICATION):
+		case (DL_RELEASE | INDICATION):
+		case (DL_RELEASE | CONFIRM):
+			l3_msg(st, pr, arg);
+			return;
+			break;
+
+		case (DL_ESTABLISH | CONFIRM):
+			global_handler( st, MT_DL_ESTABLISHED, NULL );
+			return;
+
+		default:
+			printk(KERN_ERR "HiSax ni1up unknown pr=%04x\n", pr);
+			return;
+	}
+	if (skb->len < 3) {
+		l3_debug(st, "ni1up frame too short(%d)", skb->len);
+		dev_kfree_skb(skb);
+		return;
+	}
+
+	if (skb->data[0] != PROTO_DIS_EURO) {
+		if (st->l3.debug & L3_DEB_PROTERR) {
+			l3_debug(st, "ni1up%sunexpected discriminator %x message len %d",
+				 (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
+				 skb->data[0], skb->len);
+		}
+		dev_kfree_skb(skb);
+		return;
+	}
+	cr = getcallref(skb->data);
+	if (skb->len < ((skb->data[1] & 0x0f) + 3)) {
+		l3_debug(st, "ni1up frame too short(%d)", skb->len);
+		dev_kfree_skb(skb);
+		return;
+	}
+	mt = skb->data[skb->data[1] + 2];
+	if (st->l3.debug & L3_DEB_STATE)
+		l3_debug(st, "ni1up cr %d", cr);
+	if (cr == -2) {  /* wrong Callref */
+		if (st->l3.debug & L3_DEB_WARN)
+			l3_debug(st, "ni1up wrong Callref");
+		dev_kfree_skb(skb);
+		return;
+	} else if (cr == -1) {	/* Dummy Callref */
+		if (mt == MT_FACILITY)
+		{
+			if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) {
+				l3ni1_parse_facility(st, NULL, 
+					(pr == (DL_DATA | INDICATION)) ? -1 : -2, p); 
+				dev_kfree_skb(skb);
+				return;  
+			}
+		}
+		else
+		{
+			global_handler(st, mt, skb);
+			return;
+		}
+				
+		if (st->l3.debug & L3_DEB_WARN)
+			l3_debug(st, "ni1up dummy Callref (no facility msg or ie)");
+		dev_kfree_skb(skb);
+		return;
+	} else if ((((skb->data[1] & 0x0f) == 1) && (0==(cr & 0x7f))) ||
+		(((skb->data[1] & 0x0f) == 2) && (0==(cr & 0x7fff)))) {	/* Global CallRef */
+		if (st->l3.debug & L3_DEB_STATE)
+			l3_debug(st, "ni1up Global CallRef");
+		global_handler(st, mt, skb);
+		dev_kfree_skb(skb);
+		return;
+	} else if (!(proc = getl3proc(st, cr))) {
+		/* No transaction process exist, that means no call with
+		 * this callreference is active
+		 */
+		if (mt == MT_SETUP) {
+			/* Setup creates a new transaction process */
+			if (skb->data[2] & 0x80) {
+				/* Setup with wrong CREF flag */
+				if (st->l3.debug & L3_DEB_STATE)
+					l3_debug(st, "ni1up wrong CRef flag");
+				dev_kfree_skb(skb);
+				return;
+			}
+			if (!(proc = ni1_new_l3_process(st, cr))) {
+				/* May be to answer with RELEASE_COMPLETE and
+				 * CAUSE 0x2f "Resource unavailable", but this
+				 * need a new_l3_process too ... arghh
+				 */
+				dev_kfree_skb(skb);
+				return;
+			}
+		} else if (mt == MT_STATUS) {
+			cause = 0;
+			if ((ptr = findie(skb->data, skb->len, IE_CAUSE, 0)) != NULL) {
+				ptr++;
+				if (*ptr++ == 2)
+					ptr++;
+				cause = *ptr & 0x7f;
+			}
+			callState = 0;
+			if ((ptr = findie(skb->data, skb->len, IE_CALL_STATE, 0)) != NULL) {
+				ptr++;
+				if (*ptr++ == 2)
+					ptr++;
+				callState = *ptr;
+			}
+			/* ETS 300-104 part 2.4.1
+			 * if setup has not been made and a message type
+			 * MT_STATUS is received with call state == 0,
+			 * we must send nothing
+			 */
+			if (callState != 0) {
+				/* ETS 300-104 part 2.4.2
+				 * if setup has not been made and a message type
+				 * MT_STATUS is received with call state != 0,
+				 * we must send MT_RELEASE_COMPLETE cause 101
+				 */
+				if ((proc = ni1_new_l3_process(st, cr))) {
+					proc->para.cause = 101;
+					l3ni1_msg_without_setup(proc, 0, NULL);
+				}
+			}
+			dev_kfree_skb(skb);
+			return;
+		} else if (mt == MT_RELEASE_COMPLETE) {
+			dev_kfree_skb(skb);
+			return;
+		} else {
+			/* ETS 300-104 part 2
+			 * if setup has not been made and a message type
+			 * (except MT_SETUP and RELEASE_COMPLETE) is received,
+			 * we must send MT_RELEASE_COMPLETE cause 81 */
+			dev_kfree_skb(skb);
+			if ((proc = ni1_new_l3_process(st, cr))) {
+				proc->para.cause = 81;
+				l3ni1_msg_without_setup(proc, 0, NULL);
+			}
+			return;
+		}
+	}
+	if (l3ni1_check_messagetype_validity(proc, mt, skb)) {
+		dev_kfree_skb(skb);
+		return;
+	}
+	if ((p = findie(skb->data, skb->len, IE_DISPLAY, 0)) != NULL) 
+	  l3ni1_deliver_display(proc, pr, p); /* Display IE included */
+	for (i = 0; i < DATASLLEN; i++)
+		if ((mt == datastatelist[i].primitive) &&
+		    ((1 << proc->state) & datastatelist[i].state))
+			break;
+	if (i == DATASLLEN) {
+		if (st->l3.debug & L3_DEB_STATE) {
+			l3_debug(st, "ni1up%sstate %d mt %#x unhandled",
+				(pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
+				proc->state, mt);
+		}
+		if ((MT_RELEASE_COMPLETE != mt) && (MT_RELEASE != mt)) {
+			proc->para.cause = 101;
+			l3ni1_status_send(proc, pr, skb);
+		}
+	} else {
+		if (st->l3.debug & L3_DEB_STATE) {
+			l3_debug(st, "ni1up%sstate %d mt %x",
+				(pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
+				proc->state, mt);
+		}
+		datastatelist[i].rout(proc, pr, skb);
+	}
+	dev_kfree_skb(skb);
+	return;
+}
+
+static void
+ni1down(struct PStack *st, int pr, void *arg)
+{
+	int i, cr;
+	struct l3_process *proc;
+	struct Channel *chan;
+
+	if ((DL_ESTABLISH | REQUEST) == pr) {
+		l3_msg(st, pr, NULL);
+		return;
+	} else if (((CC_SETUP | REQUEST) == pr) || ((CC_RESUME | REQUEST) == pr)) {
+		chan = arg;
+		cr = newcallref();
+		cr |= 0x80;
+		if ((proc = ni1_new_l3_process(st, cr))) {
+			proc->chan = chan;
+			chan->proc = proc;
+			memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm));
+			proc->callref = cr;
+		}
+	} else {
+		proc = arg;
+	}
+	if (!proc) {
+		printk(KERN_ERR "HiSax ni1down without proc pr=%04x\n", pr);
+		return;
+	}
+
+	if ( pr == (CC_TNI1_IO | REQUEST)) {
+		l3ni1_io_timer(proc); /* timer expires */ 
+		return;
+	}  
+
+	for (i = 0; i < DOWNSLLEN; i++)
+		if ((pr == downstatelist[i].primitive) &&
+		    ((1 << proc->state) & downstatelist[i].state))
+			break;
+	if (i == DOWNSLLEN) {
+		if (st->l3.debug & L3_DEB_STATE) {
+			l3_debug(st, "ni1down state %d prim %#x unhandled",
+				proc->state, pr);
+		}
+	} else {
+		if (st->l3.debug & L3_DEB_STATE) {
+			l3_debug(st, "ni1down state %d prim %#x",
+				proc->state, pr);
+		}
+		downstatelist[i].rout(proc, pr, arg);
+	}
+}
+
+static void
+ni1man(struct PStack *st, int pr, void *arg)
+{
+        int i;
+        struct l3_process *proc = arg;
+
+        if (!proc) {
+                printk(KERN_ERR "HiSax ni1man without proc pr=%04x\n", pr);
+                return;
+        }
+        for (i = 0; i < MANSLLEN; i++)
+                if ((pr == manstatelist[i].primitive) &&
+                    ((1 << proc->state) & manstatelist[i].state))
+                        break;
+        if (i == MANSLLEN) {
+                if (st->l3.debug & L3_DEB_STATE) {
+                        l3_debug(st, "cr %d ni1man state %d prim %#x unhandled",
+                                proc->callref & 0x7f, proc->state, pr);
+                }
+        } else {
+                if (st->l3.debug & L3_DEB_STATE) {
+                        l3_debug(st, "cr %d ni1man state %d prim %#x",
+                                proc->callref & 0x7f, proc->state, pr);
+                }
+                manstatelist[i].rout(proc, pr, arg);
+        }
+}
+ 
+void
+setstack_ni1(struct PStack *st)
+{
+	char tmp[64];
+	int i;
+
+	st->lli.l4l3 = ni1down;
+	st->lli.l4l3_proto = l3ni1_cmd_global;
+	st->l2.l2l3 = ni1up;
+	st->l3.l3ml3 = ni1man;
+	st->l3.N303 = 1;
+	st->prot.ni1.last_invoke_id = 0;
+	st->prot.ni1.invoke_used[0] = 1; /* Bit 0 must always be set to 1 */
+	i = 1;
+	while (i < 32) 
+		st->prot.ni1.invoke_used[i++] = 0;   
+
+	if (!(st->l3.global = kmalloc(sizeof(struct l3_process), GFP_ATOMIC))) {
+		printk(KERN_ERR "HiSax can't get memory for ni1 global CR\n");
+	} else {
+		st->l3.global->state = 0;
+		st->l3.global->callref = 0;
+		st->l3.global->next = NULL;
+		st->l3.global->debug = L3_DEB_WARN;
+		st->l3.global->st = st;
+		st->l3.global->N303 = 1;
+		st->l3.global->prot.ni1.invoke_id = 0; 
+
+		L3InitTimer(st->l3.global, &st->l3.global->timer);
+	}
+	strcpy(tmp, ni1_revision);
+	printk(KERN_INFO "HiSax: National ISDN-1 Rev. %s\n", HiSax_getrev(tmp));
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/l3ni1.h linux.19p18/drivers/isdn/hisax/l3ni1.h
--- linux.vanilla/drivers/isdn/hisax/l3ni1.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/hisax/l3ni1.h	Sat Dec 30 19:33:52 2000
@@ -0,0 +1,137 @@
+// $Id: l3ni1.h,v 2.3 2000/11/16 13:50:43 keil Exp $
+//-----------------------------------------------------------------------------
+//
+// NI1 D-channel protocol
+//
+// Author       Matt Henderson & Guy Ellis - Traverse Tecnologies Pty Ltd
+//              www.traverse.com.au
+//
+// 2000.6.6 Initial implementation of routines for US NI1 
+// Layer 3 protocol based on the EURO/DSS1 D-channel protocol 
+// driver written by Karsten Keil et al.  Thanks also for the 
+// code provided by Ragnar Paulson.
+//
+//
+// This file is (c) under GNU PUBLIC LICENSE
+//
+//-----------------------------------------------------------------------------
+
+#ifndef l3ni1_process
+
+#define T302	15000
+#define T303	4000
+#define T304	30000
+#define T305	30000
+#define T308	4000
+/* for layer 1 certification T309 < layer1 T3 (e.g. 4000) */
+/* This makes some tests easier and quicker */
+#define T309	40000
+#define T310	30000
+#define T313	4000
+#define T318	4000
+#define T319	4000
+#define TSPID	5000 /* was 2000 - Guy Ellis */
+
+/*
+ * Message-Types
+ */
+
+#define MT_ALERTING		0x01
+#define MT_CALL_PROCEEDING	0x02
+#define MT_CONNECT		0x07
+#define MT_CONNECT_ACKNOWLEDGE	0x0f
+#define MT_PROGRESS		0x03
+#define MT_SETUP		0x05
+#define MT_SETUP_ACKNOWLEDGE	0x0d
+#define MT_RESUME		0x26
+#define MT_RESUME_ACKNOWLEDGE	0x2e
+#define MT_RESUME_REJECT	0x22
+#define MT_SUSPEND		0x25
+#define MT_SUSPEND_ACKNOWLEDGE	0x2d
+#define MT_SUSPEND_REJECT	0x21
+#define MT_USER_INFORMATION	0x20
+#define MT_DISCONNECT		0x45
+#define MT_RELEASE		0x4d
+#define MT_RELEASE_COMPLETE	0x5a
+#define MT_RESTART		0x46
+#define MT_RESTART_ACKNOWLEDGE	0x4e
+#define MT_SEGMENT		0x60
+#define MT_CONGESTION_CONTROL	0x79
+#define MT_INFORMATION		0x7b
+#define MT_FACILITY		0x62
+#define MT_NOTIFY		0x6e
+#define MT_STATUS		0x7d
+#define MT_STATUS_ENQUIRY	0x75
+#define MT_DL_ESTABLISHED	0xfe
+
+#define IE_SEGMENT	0x00
+#define IE_BEARER	0x04
+#define IE_CAUSE	0x08
+#define IE_CALL_ID	0x10
+#define IE_CALL_STATE	0x14
+#define IE_CHANNEL_ID	0x18
+#define IE_FACILITY	0x1c
+#define IE_PROGRESS	0x1e
+#define IE_NET_FAC	0x20
+#define IE_NOTIFY	0x27
+#define IE_DISPLAY	0x28
+#define IE_DATE		0x29
+#define IE_KEYPAD	0x2c
+#define IE_SIGNAL	0x34
+#define IE_SPID		0x3a
+#define IE_ENDPOINT_ID	0x3b
+#define IE_INFORATE	0x40
+#define IE_E2E_TDELAY	0x42
+#define IE_TDELAY_SEL	0x43
+#define IE_PACK_BINPARA	0x44
+#define IE_PACK_WINSIZE	0x45
+#define IE_PACK_SIZE	0x46
+#define IE_CUG		0x47
+#define	IE_REV_CHARGE	0x4a
+#define IE_CONNECT_PN	0x4c
+#define IE_CONNECT_SUB	0x4d
+#define IE_CALLING_PN	0x6c
+#define IE_CALLING_SUB	0x6d
+#define IE_CALLED_PN	0x70
+#define IE_CALLED_SUB	0x71
+#define IE_REDIR_NR	0x74
+#define IE_TRANS_SEL	0x78
+#define IE_RESTART_IND	0x79
+#define IE_LLC		0x7c
+#define IE_HLC		0x7d
+#define IE_USER_USER	0x7e
+#define IE_ESCAPE	0x7f
+#define IE_SHIFT	0x90
+#define IE_MORE_DATA	0xa0
+#define IE_COMPLETE	0xa1
+#define IE_CONGESTION	0xb0
+#define IE_REPEAT	0xd0
+
+#define IE_MANDATORY	0x0100
+/* mandatory not in every case */
+#define IE_MANDATORY_1	0x0200
+
+#define ERR_IE_COMPREHENSION	 1
+#define ERR_IE_UNRECOGNIZED	-1
+#define ERR_IE_LENGTH		-2
+#define ERR_IE_SEQUENCE		-3
+
+#else /* only l3ni1_process */
+
+/* l3ni1 specific data in l3 process */
+typedef struct
+  { unsigned char invoke_id; /* used invoke id in remote ops, 0 = not active */
+    ulong ll_id; /* remebered ll id */
+    u_char remote_operation; /* handled remote operation, 0 = not active */ 
+    int proc; /* rememered procedure */  
+    ulong remote_result; /* result of remote operation for statcallb */
+    char uus1_data[35]; /* data send during alerting or disconnect */
+  } ni1_proc_priv;
+
+/* l3dni1 specific data in protocol stack */
+typedef struct
+  { unsigned char last_invoke_id; /* last used value for invoking */
+    unsigned char invoke_used[32]; /* 256 bits for 256 values */
+  } ni1_stk_priv;        
+
+#endif /* only l3dni1_process */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/lmgr.c linux.19p18/drivers/isdn/hisax/lmgr.c
--- linux.vanilla/drivers/isdn/hisax/lmgr.c	Fri Apr 21 12:46:11 2000
+++ linux.19p18/drivers/isdn/hisax/lmgr.c	Wed Dec 13 22:08:26 2000
@@ -1,30 +1,10 @@
-/* $Id: lmgr.c,v 1.6 1999/07/01 08:12:04 keil Exp $
-
- * Author       Karsten Keil (keil@isdn4linux.de)
+/* $Id: lmgr.c,v 1.7 2000/06/26 08:59:14 keil Exp $
  *
+ * Author       Karsten Keil (keil@isdn4linux.de)
  *
  *  Layermanagement module
  *
- * $Log: lmgr.c,v $
- * Revision 1.6  1999/07/01 08:12:04  keil
- * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
- *
- * Revision 1.5  1998/11/15 23:55:12  keil
- * changes from 2.0
- *
- * Revision 1.4  1998/05/25 12:58:19  keil
- * HiSax golden code from certification, Don't use !!!
- * No leased lines, no X75, but many changes.
- *
- * Revision 1.3  1998/03/07 22:57:06  tsbogend
- * made HiSax working on Linux/Alpha
- *
- * Revision 1.2  1997/10/29 19:09:34  keil
- * new L1
- *
- * Revision 1.1  1997/06/26 11:17:25  keil
- * first version
- *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/md5sums.asc linux.19p18/drivers/isdn/hisax/md5sums.asc
--- linux.vanilla/drivers/isdn/hisax/md5sums.asc	Fri Apr 21 12:46:11 2000
+++ linux.19p18/drivers/isdn/hisax/md5sums.asc	Wed Dec 13 22:08:26 2000
@@ -2,30 +2,32 @@
 
 # This are valid md5sums for certificated HiSax driver.
 # The certification is valid only if the md5sums of all files match.
-# The certification is valid only for ELSA QuickStep cards and
-# Eicon Technology Diva 2.01 PCI cards in the moment.
+# The certification is valid only for ELSA Microlink PCI,
+# Eicon Technology Diva 2.01 PCI and Sedlbauer SpeedFax +
+# cards in the moment.
 # Read ../../../Documentation/isdn/HiSax.cert for more informations.
 # 
-3c2b1c96274cba97a8261d1cecc662b8  isac.c
-dd3955847bbf680b41233478fe521d88  isdnl1.c
-bb51bd223040b511c18f091da5ab6456  isdnl2.c
-b7aa7f97b2374967a4aca7c52991142c  isdnl3.c
-a23fbf8879c1432b04640b8b04bdf419  tei.c
-ce248e56c2e1326012d0b25f92bbf99b  callc.c
-bf9605b36429898f7be6630034e83230  cert.c
-6ce0a184127be1a44747e2017ed24ad9  l3dss1.c
-a3a570781f828b6d59e6b231653133de  l3_1tr6.c
-8188deeb4a1b34c574cd51638cd214d0  elsa.c
-a3c2b8e9d2c623658888b5f1d4317c2a  diva.c
+4131693d878d465faf0a4a4b4c6b811e  isac.c
+a29f5270c0c89626d8d6fa5dd09e7005  isdnl1.c
+fbe41751c8130a8c3c607bfe1b41cb4e  isdnl2.c
+7915b7e802b98f6f4f05b931c4736ad4  isdnl3.c
+7c31c12b3c2cfde33596bd2c406f775c  tei.c
+f1fbd532016f005e01decf36e5197d8f  callc.c
+a1834e9b2ec068440cff2e899eff4710  cert.c
+a1f908f8b4f225c5c2f2a13842549b72  l3dss1.c
+3d0a3f88fe48f3151813fafb22ea6119  l3_1tr6.c
+6f3420dca0f50084f82471a238545a95  elsa.c
+65da7b33bbfa454df2f99636b83f0610  diva.c
+4bdb7e35627b7e25f17fccb669fda835  sedlbauer.c
 # end of md5sums
 
 -----BEGIN PGP SIGNATURE-----
 Version: 2.6.3i
 Charset: noconv
 
-iQCVAwUBONEHHTpxHvX/mS9tAQG/pAP/UyLx23V9mOgiYaId1Gm6xthyM8TP4bfE
-ov4cNmUHQtHINLXtkAP+eacw/kCiiYhdxBIrNaUC+KQkyiFPOs8frx6espxTfDte
-VZDhKDY5NYch2n3OKPLX26pNNJeu7DELMpFR6vvGByokv1RRYVs2wBk0Q5dnfPaq
-WsW0HeL/vBA=
-=fSCb
+iQCVAwUBOVctcDpxHvX/mS9tAQFOhAP+OpOSxDz46cEHjy4jLsYz44/yKZzFAXz4
+s0tYmixrFbbS5XoT1GZqzEF0n/EycO9jsp6d0eanDCg25UX7ehu9dtOJw0o6qRr2
+4M/EbloHK2G1aW4gI8W2eWRNRqTZQJ2cjPJD/V/27jDbxBBP31NvOSYvVxrbBzJG
+qZHWUDiQxRo=
+=mYrg
 -----END PGP SIGNATURE-----
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/mic.c linux.19p18/drivers/isdn/hisax/mic.c
--- linux.vanilla/drivers/isdn/hisax/mic.c	Fri Apr 21 12:46:11 2000
+++ linux.19p18/drivers/isdn/hisax/mic.c	Mon Feb 12 15:09:50 2001
@@ -1,42 +1,17 @@
-/* $Id: mic.c,v 1.8 1999/07/12 21:05:20 keil Exp $
-
+/* $Id: mic.c,v 1.10 2000/11/24 17:05:38 kai Exp $
+ *
  * mic.c  low level stuff for mic cards
  *
  * Copyright (C) 1997 
  *
  * Author  Stephan von Krawczynski <skraw@ithnet.com>
  *
- *
- * $Log: mic.c,v $
- * Revision 1.8  1999/07/12 21:05:20  keil
- * fix race in IRQ handling
- * added watchdog for lost IRQs
- *
- * Revision 1.7  1998/04/15 16:44:32  keil
- * new init code
- *
- * Revision 1.6  1998/02/17 15:39:57  keil
- * fix reset problem
- *
- * Revision 1.5  1998/02/02 13:29:43  keil
- * fast io
- *
- * Revision 1.4  1997/11/08 21:35:51  keil
- * new l1 init
- *
- * Revision 1.3  1997/11/06 17:09:11  keil
- * New 2.1 init code
- *
- * Revision 1.2  1997/10/29 18:51:17  keil
- * New files
- *
- * Revision 1.1.2.1  1997/10/17 22:10:54  keil
- * new files on 2.0
- *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
@@ -44,7 +19,7 @@
 
 extern const char *CardType[];
 
-const char *mic_revision = "$Revision: 1.8 $";
+const char *mic_revision = "$Revision: 1.10 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -224,8 +199,8 @@
 	return(0);
 }
 
-__initfunc(int
-setup_mic(struct IsdnCard *card))
+int __init
+setup_mic(struct IsdnCard *card)
 {
 	int bytecnt;
 	struct IsdnCardState *cs = card->cs;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/netjet.c linux.19p18/drivers/isdn/hisax/netjet.c
--- linux.vanilla/drivers/isdn/hisax/netjet.c	Fri Apr 21 12:46:11 2000
+++ linux.19p18/drivers/isdn/hisax/netjet.c	Tue Feb 13 18:50:48 2001
@@ -1,143 +1,32 @@
-/* $Id: netjet.c,v 1.17 1999/12/19 13:09:42 keil Exp $
-
+/* $Id: netjet.c,v 1.24.6.3 2001/02/13 10:33:58 kai Exp $
+ *
  * netjet.c     low level stuff for Traverse Technologie NETJet ISDN cards
  *
  * Author     Karsten Keil (keil@isdn4linux.de)
  *
  * Thanks to Traverse Technologie Australia for documents and informations
  *
- * $Log: netjet.c,v $
- * Revision 1.17  1999/12/19 13:09:42  keil
- * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
- * signal proof delays
- *
- * Revision 1.16  1999/10/14 20:25:29  keil
- * add a statistic for error monitoring
- *
- * Revision 1.15  1999/09/04 06:20:06  keil
- * Changes from kernel set_current_state()
- *
- * Revision 1.14  1999/08/31 11:20:25  paul
- * various spelling corrections (new checksums may be needed, Karsten!)
- *
- * Revision 1.13  1999/08/11 21:01:31  keil
- * new PCI codefix
- *
- * Revision 1.12  1999/08/10 16:02:00  calle
- * struct pci_dev changed in 2.3.13. Made the necessary changes.
- *
- * Revision 1.11  1999/08/07 17:32:00  keil
- * Asymetric buffers for improved ping times.  Interframe spacing
- * fix for NJ<->NJ thoughput.  Matt Henderson - www.traverse.com.au
- *
- *
- * Revision 1.10  1999/07/12 21:05:22  keil
- * fix race in IRQ handling
- * added watchdog for lost IRQs
- *
- * Revision 1.9  1999/07/01 08:12:05  keil
- * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
- *
- * Revision 1.8  1998/11/15 23:55:14  keil
- * changes from 2.0
- *
- * Revision 1.7  1998/09/30 22:24:48  keil
- * Fix missing line in setstack*
- *
- * Revision 1.6  1998/08/13 23:36:54  keil
- * HiSax 3.1 - don't work stable with current LinkLevel
- *
- * Revision 1.5  1998/05/25 12:58:21  keil
- * HiSax golden code from certification, Don't use !!!
- * No leased lines, no X75, but many changes.
- *
- * Revision 1.4  1998/04/15 16:42:35  keil
- * new init code
- * new PCI init (2.1.94)
- *
- * Revision 1.3  1998/02/12 23:08:05  keil
- * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
- *
- * Revision 1.2  1998/02/02 13:32:06  keil
- * New
- *
- *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 
 #define __NO_VERSION__
-#include <linux/config.h>
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
 #include "isdnl1.h"
-#include <linux/pci.h>
 #include <linux/interrupt.h>
 #include <linux/ppp_defs.h>
+#include <asm/io.h>
+#include "netjet.h"
 
-#ifndef bus_to_virt
-#define bus_to_virt (u_int *)
-#endif
-
-#ifndef virt_to_bus
-#define virt_to_bus (u_int)
-#endif
-
-extern const char *CardType[];
-
-const char *NETjet_revision = "$Revision: 1.17 $";
-
-#define byteout(addr,val) outb(val,addr)
-#define bytein(addr) inb(addr)
-
-/* PCI stuff */
-#define PCI_VENDOR_TRAVERSE_TECH 0xe159
-#define PCI_NETJET_ID	0x0001
-
-#define NETJET_CTRL	0x00
-#define NETJET_DMACTRL	0x01
-#define NETJET_AUXCTRL	0x02
-#define NETJET_AUXDATA	0x03
-#define NETJET_IRQMASK0 0x04
-#define NETJET_IRQMASK1 0x05
-#define NETJET_IRQSTAT0 0x06
-#define NETJET_IRQSTAT1 0x07
-#define NETJET_DMA_READ_START	0x08
-#define NETJET_DMA_READ_IRQ	0x0c
-#define NETJET_DMA_READ_END	0x10
-#define NETJET_DMA_READ_ADR	0x14
-#define NETJET_DMA_WRITE_START	0x18
-#define NETJET_DMA_WRITE_IRQ	0x1c
-#define NETJET_DMA_WRITE_END	0x20
-#define NETJET_DMA_WRITE_ADR	0x24
-#define NETJET_PULSE_CNT	0x28
-
-#define NETJET_ISAC_OFF	0xc0
-#define NETJET_ISACIRQ	0x10
-#define NETJET_IRQM0_READ	0x0c
-#define NETJET_IRQM0_READ_1	0x04
-#define NETJET_IRQM0_READ_2	0x08
-#define NETJET_IRQM0_WRITE	0x03
-#define NETJET_IRQM0_WRITE_1	0x01
-#define NETJET_IRQM0_WRITE_2	0x02
-
-#define NETJET_DMA_TXSIZE 512
-#define NETJET_DMA_RXSIZE 128
-
-#define HDLC_ZERO_SEARCH 0
-#define HDLC_FLAG_SEARCH 1
-#define HDLC_FLAG_FOUND  2
-#define HDLC_FRAME_FOUND 3
-#define HDLC_NULL 4
-#define HDLC_PART 5
-#define HDLC_FULL 6
-
-#define HDLC_FLAG_VALUE	0x7e
+const char *NETjet_revision = "$Revision: 1.24.6.3 $";
 
 /* Interface functions */
 
-static u_char
-ReadISAC(struct IsdnCardState *cs, u_char offset)
+u_char
+NETjet_ReadIC(struct IsdnCardState *cs, u_char offset)
 {
 	long flags;
 	u_char ret;
@@ -152,8 +41,8 @@
 	return(ret);
 }
 
-static void
-WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
+void
+NETjet_WriteIC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
 	long flags;
 	
@@ -166,8 +55,8 @@
 	restore_flags(flags);
 }
 
-static void
-ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size)
+void
+NETjet_ReadICfifo(struct IsdnCardState *cs, u_char *data, int size)
 {
 	cs->hw.njet.auxd &= 0xfc;
 	byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
@@ -210,8 +99,8 @@
 	0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
 };
 
-static void 
-WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size)
+void 
+NETjet_WriteICfifo(struct IsdnCardState *cs, u_char *data, int size)
 {
 	cs->hw.njet.auxd &= 0xfc;
 	byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
@@ -265,7 +154,8 @@
 			break;
 		case (L1_MODE_TRANS):
 			break;
-		case (L1_MODE_HDLC): 
+		case (L1_MODE_HDLC_56K):
+		case (L1_MODE_HDLC):
 			fill_mem(bcs, bcs->hw.tiger.send,
 				NETJET_DMA_TXSIZE, bc, 0xff);
 			bcs->hw.tiger.r_state = HDLC_ZERO_SEARCH;
@@ -280,7 +170,8 @@
 				cs->hw.njet.dmactrl = 1;
 				byteout(cs->hw.njet.base + NETJET_DMACTRL,
 					cs->hw.njet.dmactrl);
-				byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0x3f);
+				byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0x0f);
+			/* was 0x3f now 0x0f for TJ300 and TJ320  GE 13/07/00 */
 			}
 			bcs->hw.tiger.sendp = bcs->hw.tiger.send;
 			bcs->hw.tiger.free = NETJET_DMA_TXSIZE;
@@ -297,15 +188,6 @@
 			bytein(cs->hw.njet.base + NETJET_PULSE_CNT));
 }
 
-static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off)
-{
-	return(5);
-}
-
-static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value)
-{
-}
-
 static void printframe(struct IsdnCardState *cs, u_char *buf, int count, char *s) {
 	char tmp[128];
 	char *t = tmp;
@@ -327,6 +209,8 @@
 	}
 }
 
+// macro for 64k
+
 #define MAKE_RAW_BYTE for (j=0; j<8; j++) { \
 			bitcnt++;\
 			s_val >>= 1;\
@@ -355,6 +239,7 @@
 		}
 
 static int make_raw_data(struct BCState *bcs) {
+// this make_raw is for 64k
 	register u_int i,s_cnt=0;
 	register u_char j;
 	register u_char val;
@@ -410,6 +295,113 @@
 	return(0);
 }
 
+// macro for 56k
+
+#define MAKE_RAW_BYTE_56K for (j=0; j<8; j++) { \
+			bitcnt++;\
+			s_val >>= 1;\
+			if (val & 1) {\
+				s_one++;\
+				s_val |= 0x80;\
+			} else {\
+				s_one = 0;\
+				s_val &= 0x7f;\
+			}\
+			if (bitcnt==7) {\
+				s_val >>= 1;\
+				s_val |= 0x80;\
+				bcs->hw.tiger.sendbuf[s_cnt++] = s_val;\
+				bitcnt = 0;\
+			}\
+			if (s_one == 5) {\
+				s_val >>= 1;\
+				s_val &= 0x7f;\
+				bitcnt++;\
+				s_one = 0;\
+			}\
+			if (bitcnt==7) {\
+				s_val >>= 1;\
+				s_val |= 0x80;\
+				bcs->hw.tiger.sendbuf[s_cnt++] = s_val;\
+				bitcnt = 0;\
+			}\
+			val >>= 1;\
+		}
+
+static int make_raw_data_56k(struct BCState *bcs) {
+// this make_raw is for 56k
+	register u_int i,s_cnt=0;
+	register u_char j;
+	register u_char val;
+	register u_char s_one = 0;
+	register u_char s_val = 0;
+	register u_char bitcnt = 0;
+	u_int fcs;
+	
+	if (!bcs->tx_skb) {
+		debugl1(bcs->cs, "tiger make_raw_56k: NULL skb");
+		return(1);
+	}
+	val = HDLC_FLAG_VALUE;
+	for (j=0; j<8; j++) { 
+		bitcnt++;
+		s_val >>= 1;
+		if (val & 1)
+			s_val |= 0x80;
+		else
+			s_val &= 0x7f;
+		if (bitcnt==7) {
+			s_val >>= 1;
+			s_val |= 0x80;
+			bcs->hw.tiger.sendbuf[s_cnt++] = s_val;
+			bitcnt = 0;
+		}
+		val >>= 1;
+	};
+	fcs = PPP_INITFCS;
+	for (i=0; i<bcs->tx_skb->len; i++) {
+		val = bcs->tx_skb->data[i];
+		fcs = PPP_FCS (fcs, val);
+		MAKE_RAW_BYTE_56K;
+	}
+	fcs ^= 0xffff;
+	val = fcs & 0xff;
+	MAKE_RAW_BYTE_56K;
+	val = (fcs>>8) & 0xff;
+	MAKE_RAW_BYTE_56K;
+	val = HDLC_FLAG_VALUE;
+	for (j=0; j<8; j++) { 
+		bitcnt++;
+		s_val >>= 1;
+		if (val & 1)
+			s_val |= 0x80;
+		else
+			s_val &= 0x7f;
+		if (bitcnt==7) {
+			s_val >>= 1;
+			s_val |= 0x80;
+			bcs->hw.tiger.sendbuf[s_cnt++] = s_val;
+			bitcnt = 0;
+		}
+		val >>= 1;
+	}
+	if (bcs->cs->debug & L1_DEB_HSCX)
+		debugl1(bcs->cs,"tiger make_raw_56k: in %ld out %d.%d",
+			bcs->tx_skb->len, s_cnt, bitcnt);
+	if (bitcnt) {
+		while (8>bitcnt++) {
+			s_val >>= 1;
+			s_val |= 0x80;
+		}
+		bcs->hw.tiger.sendbuf[s_cnt++] = s_val;
+		bcs->hw.tiger.sendbuf[s_cnt++] = 0xff;	// NJ<->NJ thoughput bug fix
+	}
+	bcs->hw.tiger.sendcnt = s_cnt;
+	bcs->tx_cnt -= bcs->tx_skb->len;
+	bcs->hw.tiger.sp = bcs->hw.tiger.sendbuf;
+	return(0);
+}
+
 static void got_frame(struct BCState *bcs, int count) {
 	struct sk_buff *skb;
 		
@@ -439,20 +431,30 @@
 	register u_char r_val = bcs->hw.tiger.r_val;
 	register u_int bitcnt = bcs->hw.tiger.r_bitcnt;
 	u_int *p = buf;
-        
+	int bits;
+	u_char mask;
+
+        if (bcs->mode == L1_MODE_HDLC) { // it's 64k
+		mask = 0xff;
+		bits = 8;
+	}
+	else { // it's 56K
+		mask = 0x7f;
+		bits = 7;
+	};
 	for (i=0;i<cnt;i++) {
 		val = bcs->channel ? ((*p>>8) & 0xff) : (*p & 0xff);
 		p++;
 		if (p > pend)
 			p = bcs->hw.tiger.rec;
-		if (val == 0xff) {
+		if ((val & mask) == mask) {
 			state = HDLC_ZERO_SEARCH;
 			bcs->hw.tiger.r_tot++;
 			bitcnt = 0;
 			r_one = 0;
 			continue;
 		}
-		for (j=0;j<8;j++) {
+		for (j=0;j<bits;j++) {
 			if (state == HDLC_ZERO_SEARCH) {
 				if (val & 1) {
 					r_one++;
@@ -596,7 +598,7 @@
 	bcs->hw.tiger.r_bitcnt = bitcnt;
 }
 
-static void read_tiger(struct IsdnCardState *cs) {
+void read_tiger(struct IsdnCardState *cs) {
 	u_int *p;
 	int cnt = NETJET_DMA_RXSIZE/2;
 	
@@ -618,16 +620,17 @@
 		p = cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE - 1;
 	else
 		p = cs->bcs[0].hw.tiger.rec + cnt - 1;
-	if (cs->bcs[0].mode == L1_MODE_HDLC)
+	if ((cs->bcs[0].mode == L1_MODE_HDLC) || (cs->bcs[0].mode == L1_MODE_HDLC_56K))
 		read_raw(cs->bcs, p, cnt);
-	if (cs->bcs[1].mode == L1_MODE_HDLC)
+
+	if ((cs->bcs[1].mode == L1_MODE_HDLC) || (cs->bcs[1].mode == L1_MODE_HDLC_56K))
 		read_raw(cs->bcs + 1, p, cnt);
 	cs->hw.njet.irqstat0 &= ~NETJET_IRQM0_READ;
 }
 
 static void write_raw(struct BCState *bcs, u_int *buf, int cnt);
 
-static void fill_dma(struct BCState *bcs)
+void netjet_fill_dma(struct BCState *bcs)
 {
 	register u_int *p, *sp;
 	register int cnt;
@@ -639,8 +642,14 @@
 			bcs->Flag);
 	if (test_and_set_bit(BC_FLG_BUSY, &bcs->Flag))
 		return;
-	if (make_raw_data(bcs))
-		return;		
+	if (bcs->mode == L1_MODE_HDLC) { // it's 64k
+		if (make_raw_data(bcs))
+			return;		
+	}
+	else { // it's 56k
+		if (make_raw_data_56k(bcs))
+			return;		
+	};
 	if (bcs->cs->debug & L1_DEB_HSCX)
 		debugl1(bcs->cs,"tiger fill_dma2: c%d %4x", bcs->channel,
 			bcs->Flag);
@@ -742,7 +751,7 @@
 				test_and_set_bit(BC_FLG_NOFRAME, &bcs->Flag);
 			}
 			if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
-				fill_dma(bcs);
+				netjet_fill_dma(bcs);
 			} else {
 				mask ^= 0xffffffff;
 				if (s_cnt < cnt) {
@@ -774,7 +783,7 @@
 	}
 }
 
-static void write_tiger(struct IsdnCardState *cs) {
+void write_tiger(struct IsdnCardState *cs) {
 	u_int *p, cnt = NETJET_DMA_TXSIZE/2;
 	
 	if ((cs->hw.njet.irqstat0 & cs->hw.njet.last_is0) & NETJET_IRQM0_WRITE) {
@@ -795,9 +804,9 @@
 		p = cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE - 1;
 	else
 		p = cs->bcs[0].hw.tiger.send + cnt - 1;
-	if (cs->bcs[0].mode == L1_MODE_HDLC)
+	if ((cs->bcs[0].mode == L1_MODE_HDLC) || (cs->bcs[0].mode == L1_MODE_HDLC_56K))
 		write_raw(cs->bcs, p, cnt);
-	if (cs->bcs[1].mode == L1_MODE_HDLC)
+	if ((cs->bcs[1].mode == L1_MODE_HDLC) || (cs->bcs[1].mode == L1_MODE_HDLC_56K))
 		write_raw(cs->bcs + 1, p, cnt);
 	cs->hw.njet.irqstat0 &= ~NETJET_IRQM0_WRITE;
 }
@@ -920,8 +929,8 @@
 }
 
  
-__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))) {
@@ -990,88 +999,6 @@
 	}
 }
 
-static void
-netjet_interrupt(int intno, void *dev_id, struct pt_regs *regs)
-{
-	struct IsdnCardState *cs = dev_id;
-	u_char val, sval;
-	long flags;
-
-	if (!cs) {
-		printk(KERN_WARNING "NETjet: Spurious interrupt!\n");
-		return;
-	}
-	if (!((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT1)) &
-		NETJET_ISACIRQ)) {
-		val = ReadISAC(cs, ISAC_ISTA);
-		if (cs->debug & L1_DEB_ISAC)
-			debugl1(cs, "tiger: i1 %x %x", sval, val);
-		if (val) {
-			isac_interrupt(cs, val);
-			WriteISAC(cs, ISAC_MASK, 0xFF);
-			WriteISAC(cs, ISAC_MASK, 0x0);
-		}
-	}
-	save_flags(flags);
-	cli();
-	if ((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT0))) {
-		if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
-			restore_flags(flags);
-			return;
-		}
-		cs->hw.njet.irqstat0 = sval;
-		restore_flags(flags);
-/*		debugl1(cs, "tiger: ist0 %x  %x %x  %x/%x  pulse=%d",
-			sval, 
-			bytein(cs->hw.njet.base + NETJET_DMACTRL),
-			bytein(cs->hw.njet.base + NETJET_IRQMASK0),
-			inl(cs->hw.njet.base + NETJET_DMA_READ_ADR),
-			inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR),
-			bytein(cs->hw.njet.base + NETJET_PULSE_CNT));
-*/
-/*		cs->hw.njet.irqmask0 = ((0x0f & cs->hw.njet.irqstat0) ^ 0x0f) | 0x30;
-*/		byteout(cs->hw.njet.base + NETJET_IRQSTAT0, cs->hw.njet.irqstat0);
-/*		byteout(cs->hw.njet.base + NETJET_IRQMASK0, cs->hw.njet.irqmask0);
-*/		if (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ)
-			read_tiger(cs);
-		if (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE)
-			write_tiger(cs);
-		test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
-	} else
-		restore_flags(flags);
-
-/*	if (!testcnt--) {
-		cs->hw.njet.dmactrl = 0;
-		byteout(cs->hw.njet.base + NETJET_DMACTRL,
-			cs->hw.njet.dmactrl);
-		byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0);
-	}
-*/
-}
-
-static void
-reset_netjet(struct IsdnCardState *cs)
-{
-	long flags;
-
-	save_flags(flags);
-	sti();
-	cs->hw.njet.ctrl_reg = 0xff;  /* Reset On */
-	byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
-	current->state = TASK_UNINTERRUPTIBLE;
-	schedule_timeout((10*HZ)/1000);	/* Timeout 10ms */
-	cs->hw.njet.ctrl_reg = 0x00;  /* Reset Off and status read clear */
-	byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
-	current->state = TASK_UNINTERRUPTIBLE;
-	schedule_timeout((10*HZ)/1000);	/* Timeout 10ms */
-	restore_flags(flags);
-	cs->hw.njet.auxd = 0;
-	cs->hw.njet.dmactrl = 0;
-	byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
-	byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
-	byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
-}
-
 void
 release_io_netjet(struct IsdnCardState *cs)
 {
@@ -1081,99 +1008,3 @@
 	release_region(cs->hw.njet.base, 256);
 }
 
-
-static int
-NETjet_card_msg(struct IsdnCardState *cs, int mt, void *arg)
-{
-	switch (mt) {
-		case CARD_RESET:
-			reset_netjet(cs);
-			return(0);
-		case CARD_RELEASE:
-			release_io_netjet(cs);
-			return(0);
-		case CARD_INIT:
-			inittiger(cs);
-			clear_pending_isac_ints(cs);
-			initisac(cs);
-			/* Reenable all IRQ */
-			cs->writeisac(cs, ISAC_MASK, 0);
-			return(0);
-		case CARD_TEST:
-			return(0);
-	}
-	return(0);
-}
-
-static 	struct pci_dev *dev_netjet __initdata = NULL;
-
-__initfunc(int
-setup_netjet(struct IsdnCard *card))
-{
-	int bytecnt;
-	struct IsdnCardState *cs = card->cs;
-	char tmp[64];
-#if CONFIG_PCI
-#endif
-	strcpy(tmp, NETjet_revision);
-	printk(KERN_INFO "HiSax: Traverse Tech. NETjet driver Rev. %s\n", HiSax_getrev(tmp));
-	if (cs->typ != ISDN_CTYPE_NETJET)
-		return(0);
-	test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
-#if CONFIG_PCI
-	if (!pci_present()) {
-		printk(KERN_ERR "Netjet: no PCI bus present\n");
-		return(0);
-	}
-	if ((dev_netjet = pci_find_device(PCI_VENDOR_TRAVERSE_TECH,
-		PCI_NETJET_ID,  dev_netjet))) {
-		cs->irq = dev_netjet->irq;
-		if (!cs->irq) {
-			printk(KERN_WARNING "NETjet: No IRQ for PCI card found\n");
-			return(0);
-		}
-		cs->hw.njet.base = dev_netjet->base_address[ 0]
-			& PCI_BASE_ADDRESS_IO_MASK; 
-		if (!cs->hw.njet.base) {
-			printk(KERN_WARNING "NETjet: No IO-Adr for PCI card found\n");
-			return(0);
-		}
-	} else {
-		printk(KERN_WARNING "NETjet: No PCI card found\n");
-		return(0);
-	}
-	cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
-	cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF;
-	bytecnt = 256;
-#else
-	printk(KERN_WARNING "NETjet: NO_PCI_BIOS\n");
-	printk(KERN_WARNING "NETjet: unable to config NETJET PCI\n");
-	return (0);
-#endif /* CONFIG_PCI */
-	printk(KERN_INFO
-		"NETjet: PCI card configured at 0x%x IRQ %d\n",
-		cs->hw.njet.base, cs->irq);
-	if (check_region(cs->hw.njet.base, bytecnt)) {
-		printk(KERN_WARNING
-		       "HiSax: %s config port %x-%x already in use\n",
-		       CardType[card->typ],
-		       cs->hw.njet.base,
-		       cs->hw.njet.base + bytecnt);
-		return (0);
-	} else {
-		request_region(cs->hw.njet.base, bytecnt, "netjet isdn");
-	}
-	reset_netjet(cs);
-	cs->readisac  = &ReadISAC;
-	cs->writeisac = &WriteISAC;
-	cs->readisacfifo  = &ReadISACfifo;
-	cs->writeisacfifo = &WriteISACfifo;
-	cs->BC_Read_Reg  = &dummyrr;
-	cs->BC_Write_Reg = &dummywr;
-	cs->BC_Send_Data = &fill_dma;
-	cs->cardmsg = &NETjet_card_msg;
-	cs->irq_func = &netjet_interrupt;
-	cs->irq_flags |= SA_SHIRQ;
-	ISACVersion(cs, "NETjet:");
-	return (1);
-}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/netjet.h linux.19p18/drivers/isdn/hisax/netjet.h
--- linux.vanilla/drivers/isdn/hisax/netjet.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/hisax/netjet.h	Mon Feb 12 15:09:50 2001
@@ -0,0 +1,70 @@
+// $Id: netjet.h,v 2.5.6.1 2000/11/28 12:02:46 kai Exp $
+//-----------------------------------------------------------------------------
+//
+// NETjet common header file
+//
+// Author       Kerstern Keil repackaged by
+//              Matt Henderson - Traverse Technologies P/L www.traverse.com.au
+//
+// This file is (c) under GNU PUBLIC LICENSE
+//
+//-----------------------------------------------------------------------------
+
+extern const char *CardType[];
+
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
+
+#define NETJET_CTRL	0x00
+#define NETJET_DMACTRL	0x01
+#define NETJET_AUXCTRL	0x02
+#define NETJET_AUXDATA	0x03
+#define NETJET_IRQMASK0 0x04
+#define NETJET_IRQMASK1 0x05
+#define NETJET_IRQSTAT0 0x06
+#define NETJET_IRQSTAT1 0x07
+#define NETJET_DMA_READ_START	0x08
+#define NETJET_DMA_READ_IRQ	0x0c
+#define NETJET_DMA_READ_END	0x10
+#define NETJET_DMA_READ_ADR	0x14
+#define NETJET_DMA_WRITE_START	0x18
+#define NETJET_DMA_WRITE_IRQ	0x1c
+#define NETJET_DMA_WRITE_END	0x20
+#define NETJET_DMA_WRITE_ADR	0x24
+#define NETJET_PULSE_CNT	0x28
+
+#define NETJET_ISAC_OFF	0xc0
+#define NETJET_ISACIRQ	0x10
+#define NETJET_IRQM0_READ	0x0c
+#define NETJET_IRQM0_READ_1	0x04
+#define NETJET_IRQM0_READ_2	0x08
+#define NETJET_IRQM0_WRITE	0x03
+#define NETJET_IRQM0_WRITE_1	0x01
+#define NETJET_IRQM0_WRITE_2	0x02
+
+#define NETJET_DMA_TXSIZE 512
+#define NETJET_DMA_RXSIZE 128
+
+#define HDLC_ZERO_SEARCH 0
+#define HDLC_FLAG_SEARCH 1
+#define HDLC_FLAG_FOUND  2
+#define HDLC_FRAME_FOUND 3
+#define HDLC_NULL 4
+#define HDLC_PART 5
+#define HDLC_FULL 6
+
+#define HDLC_FLAG_VALUE	0x7e
+
+u_char NETjet_ReadIC(struct IsdnCardState *cs, u_char offset);
+void NETjet_WriteIC(struct IsdnCardState *cs, u_char offset, u_char value);
+void NETjet_ReadICfifo(struct IsdnCardState *cs, u_char *data, int size);
+void NETjet_WriteICfifo(struct IsdnCardState *cs, u_char *data, int size);
+
+void read_tiger(struct IsdnCardState *cs);
+void write_tiger(struct IsdnCardState *cs);
+
+void netjet_fill_dma(struct BCState *bcs);
+void netjet_interrupt(int intno, void *dev_id, struct pt_regs *regs);
+void inittiger(struct IsdnCardState *cs);
+void release_io_netjet(struct IsdnCardState *cs);
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/niccy.c linux.19p18/drivers/isdn/hisax/niccy.c
--- linux.vanilla/drivers/isdn/hisax/niccy.c	Fri Apr 21 12:46:11 2000
+++ linux.19p18/drivers/isdn/hisax/niccy.c	Tue Feb 13 18:50:48 2001
@@ -1,5 +1,5 @@
-/* $Id: niccy.c,v 1.8 1999/08/11 21:01:33 keil Exp $
-
+/* $Id: niccy.c,v 1.15.6.3 2001/02/13 10:33:58 kai Exp $
+ *
  * niccy.c  low level stuff for Dr. Neuhaus NICCY PnP and NICCY PCI and
  *          compatible (SAGEM cybermodem)
  *
@@ -7,42 +7,23 @@
  * 
  * Thanks to Dr. Neuhaus and SAGEM for informations
  *
- * $Log: niccy.c,v $
- * Revision 1.8  1999/08/11 21:01:33  keil
- * new PCI codefix
- *
- * Revision 1.7  1999/08/10 16:02:04  calle
- * struct pci_dev changed in 2.3.13. Made the necessary changes.
- *
- * Revision 1.6  1999/07/12 21:05:23  keil
- * fix race in IRQ handling
- * added watchdog for lost IRQs
- *
- * Revision 1.5  1999/07/01 08:12:07  keil
- * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
- *
- * Revision 1.4  1998/04/16 19:16:48  keil
- * need config.h
- *
- * Revision 1.3  1998/04/15 16:42:59  keil
- * new init code
- *
- * Revision 1.2  1998/02/11 17:31:04  keil
- * new file
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 
 
 #define __NO_VERSION__
 #include <linux/config.h>
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
 #include "isdnl1.h"
 #include <linux/pci.h>
+#include <linux/isdn_compat.h>
 
 extern const char *CardType[];
-const char *niccy_revision = "$Revision: 1.8 $";
+const char *niccy_revision = "$Revision: 1.15.6.3 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -59,8 +40,6 @@
 #define NICCY_PCI	2
 
 /* PCI stuff */
-#define PCI_VENDOR_DR_NEUHAUS	0x1267
-#define PCI_NICCY_ID		0x1016
 #define PCI_IRQ_CTRL_REG	0x38
 #define PCI_IRQ_ENABLE		0x1f00
 #define PCI_IRQ_DISABLE		0xff0000
@@ -228,12 +207,13 @@
 static void
 niccy_reset(struct IsdnCardState *cs)
 {
-	int val, nval;
-	
-	val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
-	nval = val | PCI_IRQ_ENABLE;
-	outl(nval, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
+	if (cs->subtyp == NICCY_PCI) {
+		int val;
 
+		val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
+		val |= PCI_IRQ_ENABLE;
+		outl(val, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
+	}
 	inithscxisac(cs, 3);
 }
 
@@ -256,10 +236,10 @@
 	return(0);
 }
 
-static 	struct pci_dev *niccy_dev __initdata = NULL;
+static struct pci_dev *niccy_dev __initdata = NULL;
 
-__initfunc(int
-setup_niccy(struct IsdnCard *card))
+int __init
+setup_niccy(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
@@ -304,24 +284,26 @@
 			return(0);
 		}
 		cs->subtyp = 0;
-		if ((niccy_dev = pci_find_device(PCI_VENDOR_DR_NEUHAUS,
-			   PCI_NICCY_ID, niccy_dev))) {
+		if ((niccy_dev = pci_find_device(PCI_VENDOR_ID_SATSAGEM,
+			PCI_DEVICE_ID_SATSAGEM_NICCY, niccy_dev))) {
+			if (pci_enable_device(niccy_dev))
+				return(0);
 			/* get IRQ */
 			if (!niccy_dev->irq) {
 				printk(KERN_WARNING "Niccy: No IRQ for PCI card found\n");
 				return(0);
 			}
 			cs->irq = niccy_dev->irq;
-			if (!niccy_dev->base_address[ 0]) {
+			cs->hw.niccy.cfg_reg = niccy_dev->base_address[ 0] & PCI_BASE_ADDRESS_IO_MASK;
+			if (!cs->hw.niccy.cfg_reg) {
 				printk(KERN_WARNING "Niccy: No IO-Adr for PCI cfg found\n");
 				return(0);
 			}
-			cs->hw.niccy.cfg_reg = niccy_dev->base_address[ 0] & PCI_BASE_ADDRESS_IO_MASK;
-			if (!niccy_dev->base_address[ 1]) {
+			pci_ioaddr = niccy_dev->base_address[ 1] & PCI_BASE_ADDRESS_IO_MASK;
+			if (!pci_ioaddr) {
 				printk(KERN_WARNING "Niccy: No IO-Adr for PCI card found\n");
 				return(0);
 			}
-			pci_ioaddr = niccy_dev->base_address[ 1] & PCI_BASE_ADDRESS_IO_MASK;
 			cs->subtyp = NICCY_PCI;
 		} else {
 			printk(KERN_WARNING "Niccy: No PCI card found\n");
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/nj_s.c linux.19p18/drivers/isdn/hisax/nj_s.c
--- linux.vanilla/drivers/isdn/hisax/nj_s.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/hisax/nj_s.c	Tue Feb 13 18:50:48 2001
@@ -0,0 +1,269 @@
+// $Id: nj_s.c,v 2.7.6.3 2001/02/13 10:33:58 kai Exp $
+//
+// This file is (c) under GNU PUBLIC LICENSE
+//
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include <linux/init.h>
+#include "hisax.h"
+#include "isac.h"
+#include "isdnl1.h"
+#include <linux/pci.h>
+#include <linux/isdn_compat.h>
+#include <linux/interrupt.h>
+#include <linux/ppp_defs.h>
+#include "netjet.h"
+
+const char *NETjet_S_revision = "$Revision: 2.7.6.3 $";
+
+static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off)
+{
+	return(5);
+}
+
+static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value)
+{
+}
+
+static void
+netjet_s_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+	struct IsdnCardState *cs = dev_id;
+	u_char val, sval;
+	long flags;
+
+	if (!cs) {
+		printk(KERN_WARNING "NETjet-S: Spurious interrupt!\n");
+		return;
+	}
+	if (!((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT1)) &
+		NETJET_ISACIRQ)) {
+		val = NETjet_ReadIC(cs, ISAC_ISTA);
+		if (cs->debug & L1_DEB_ISAC)
+			debugl1(cs, "tiger: i1 %x %x", sval, val);
+		if (val) {
+			isac_interrupt(cs, val);
+			NETjet_WriteIC(cs, ISAC_MASK, 0xFF);
+			NETjet_WriteIC(cs, ISAC_MASK, 0x0);
+		}
+	}
+	save_flags(flags);
+	cli();
+	/* start new code 13/07/00 GE */
+	/* set bits in sval to indicate which page is free */
+	if (inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR) <
+		inl(cs->hw.njet.base + NETJET_DMA_WRITE_IRQ))
+		/* the 2nd write page is free */
+		sval = 0x08;
+	else	/* the 1st write page is free */
+		sval = 0x04;	
+	if (inl(cs->hw.njet.base + NETJET_DMA_READ_ADR) <
+		inl(cs->hw.njet.base + NETJET_DMA_READ_IRQ))
+		/* the 2nd read page is free */
+		sval = sval | 0x02;
+	else	/* the 1st read page is free */
+		sval = sval | 0x01;	
+	if (sval != cs->hw.njet.last_is0) /* we have a DMA interrupt */
+	{
+		if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+			restore_flags(flags);
+			return;
+		}
+		cs->hw.njet.irqstat0 = sval;
+		restore_flags(flags);
+		if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) != 
+			(cs->hw.njet.last_is0 & NETJET_IRQM0_READ))
+			/* we have a read dma int */
+			read_tiger(cs);
+		if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) !=
+			(cs->hw.njet.last_is0 & NETJET_IRQM0_WRITE))
+			/* we have a write dma int */
+			write_tiger(cs);
+		/* end new code 13/07/00 GE */
+		test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+	} else
+		restore_flags(flags);
+
+/*	if (!testcnt--) {
+		cs->hw.njet.dmactrl = 0;
+		byteout(cs->hw.njet.base + NETJET_DMACTRL,
+			cs->hw.njet.dmactrl);
+		byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0);
+	}
+*/
+}
+
+static void
+reset_netjet_s(struct IsdnCardState *cs)
+{
+	long flags;
+
+	save_flags(flags);
+	sti();
+	cs->hw.njet.ctrl_reg = 0xff;  /* Reset On */
+	byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout((10*HZ)/1000);	/* Timeout 10ms */
+	cs->hw.njet.ctrl_reg = 0x40;  /* Reset Off and status read clear */
+	/* now edge triggered for TJ320 GE 13/07/00 */
+	byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout((10*HZ)/1000);	/* Timeout 10ms */
+	restore_flags(flags);
+	cs->hw.njet.auxd = 0;
+	cs->hw.njet.dmactrl = 0;
+	byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
+	byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
+	byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+}
+
+static int
+NETjet_S_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+	switch (mt) {
+		case CARD_RESET:
+			reset_netjet_s(cs);
+			return(0);
+		case CARD_RELEASE:
+			release_io_netjet(cs);
+			return(0);
+		case CARD_INIT:
+			inittiger(cs);
+			clear_pending_isac_ints(cs);
+			initisac(cs);
+			/* Reenable all IRQ */
+			cs->writeisac(cs, ISAC_MASK, 0);
+			return(0);
+		case CARD_TEST:
+			return(0);
+	}
+	return(0);
+}
+
+static struct pci_dev *dev_netjet __initdata = NULL;
+
+int __init
+setup_netjet_s(struct IsdnCard *card)
+{
+	int bytecnt;
+	struct IsdnCardState *cs = card->cs;
+	char tmp[64];
+	long flags;
+
+#ifdef __BIG_ENDIAN
+#error "not running on big endian machines now"
+#endif
+	strcpy(tmp, NETjet_S_revision);
+	printk(KERN_INFO "HiSax: Traverse Tech. NETjet-S driver Rev. %s\n", HiSax_getrev(tmp));
+	if (cs->typ != ISDN_CTYPE_NETJET_S)
+		return(0);
+	test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+
+#if CONFIG_PCI
+
+	for ( ;; )
+	{
+		if (!pci_present()) {
+			printk(KERN_ERR "Netjet: no PCI bus present\n");
+			return(0);
+		}
+		if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET,
+			PCI_DEVICE_ID_TIGERJET_300,  dev_netjet))) {
+			if (pci_enable_device(dev_netjet))
+				return(0);
+			pci_set_master(dev_netjet);
+			cs->irq = dev_netjet->irq;
+			if (!cs->irq) {
+				printk(KERN_WARNING "NETjet-S: No IRQ for PCI card found\n");
+				return(0);
+			}
+			cs->hw.njet.base = dev_netjet->base_address[ 0] & PCI_BASE_ADDRESS_IO_MASK;
+			if (!cs->hw.njet.base) {
+				printk(KERN_WARNING "NETjet-S: No IO-Adr for PCI card found\n");
+				return(0);
+			}
+		} else {
+			printk(KERN_WARNING "NETjet-S: No PCI card found\n");
+			return(0);
+		}
+
+		cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
+		cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF;
+
+		save_flags(flags);
+		sti();
+
+		cs->hw.njet.ctrl_reg = 0xff;  /* Reset On */
+		byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout((10*HZ)/1000);	/* Timeout 10ms */
+
+		cs->hw.njet.ctrl_reg = 0x00;  /* Reset Off and status read clear */
+		byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout((10*HZ)/1000);	/* Timeout 10ms */
+
+		restore_flags(flags);
+
+		cs->hw.njet.auxd = 0xC0;
+		cs->hw.njet.dmactrl = 0;
+
+		byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
+		byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
+		byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+
+		switch ( ( ( NETjet_ReadIC( cs, ISAC_RBCH ) >> 5 ) & 3 ) )
+		{
+			case 0 :
+				break;
+
+			case 3 :
+				printk( KERN_WARNING "NETjet-S: NETspider-U PCI card found\n" );
+				continue;
+
+			default :
+				printk( KERN_WARNING "NETjet-S: No PCI card found\n" );
+				return 0;
+                }
+                break;
+	}
+#else
+
+	printk(KERN_WARNING "NETjet-S: NO_PCI_BIOS\n");
+	printk(KERN_WARNING "NETjet-S: unable to config NETJET-S PCI\n");
+	return (0);
+
+#endif /* CONFIG_PCI */
+
+	bytecnt = 256;
+
+	printk(KERN_INFO
+		"NETjet-S: PCI card configured at 0x%x IRQ %d\n",
+		cs->hw.njet.base, cs->irq);
+	if (check_region(cs->hw.njet.base, bytecnt)) {
+		printk(KERN_WARNING
+		       "HiSax: %s config port %x-%x already in use\n",
+		       CardType[card->typ],
+		       cs->hw.njet.base,
+		       cs->hw.njet.base + bytecnt);
+		return (0);
+	} else {
+		request_region(cs->hw.njet.base, bytecnt, "netjet-s isdn");
+	}
+	reset_netjet_s(cs);
+	cs->readisac  = &NETjet_ReadIC;
+	cs->writeisac = &NETjet_WriteIC;
+	cs->readisacfifo  = &NETjet_ReadICfifo;
+	cs->writeisacfifo = &NETjet_WriteICfifo;
+	cs->BC_Read_Reg  = &dummyrr;
+	cs->BC_Write_Reg = &dummywr;
+	cs->BC_Send_Data = &netjet_fill_dma;
+	cs->cardmsg = &NETjet_S_card_msg;
+	cs->irq_func = &netjet_s_interrupt;
+	cs->irq_flags |= SA_SHIRQ;
+	ISACVersion(cs, "NETjet-S:");
+	return (1);
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/nj_u.c linux.19p18/drivers/isdn/hisax/nj_u.c
--- linux.vanilla/drivers/isdn/hisax/nj_u.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/hisax/nj_u.c	Tue Feb 13 18:50:48 2001
@@ -0,0 +1,273 @@
+/* $Id: nj_u.c,v 2.8.6.3 2001/02/13 10:33:58 kai Exp $ 
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include <linux/init.h>
+#include "hisax.h"
+#include "icc.h"
+#include "isdnl1.h"
+#include <linux/pci.h>
+#include <linux/isdn_compat.h>
+#include <linux/interrupt.h>
+#include <linux/ppp_defs.h>
+#include "netjet.h"
+
+const char *NETjet_U_revision = "$Revision: 2.8.6.3 $";
+
+static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off)
+{
+	return(5);
+}
+
+static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value)
+{
+}
+
+static void
+netjet_u_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+	struct IsdnCardState *cs = dev_id;
+	u_char val, sval;
+	long flags;
+
+	if (!cs) {
+		printk(KERN_WARNING "NETspider-U: Spurious interrupt!\n");
+		return;
+	}
+	if (!((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT1)) &
+		NETJET_ISACIRQ)) {
+		val = NETjet_ReadIC(cs, ICC_ISTA);
+		if (cs->debug & L1_DEB_ISAC)
+			debugl1(cs, "tiger: i1 %x %x", sval, val);
+		if (val) {
+			icc_interrupt(cs, val);
+			NETjet_WriteIC(cs, ICC_MASK, 0xFF);
+			NETjet_WriteIC(cs, ICC_MASK, 0x0);
+		}
+	}
+	save_flags(flags);
+	cli();
+	/* start new code 13/07/00 GE */
+	/* set bits in sval to indicate which page is free */
+	if (inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR) <
+		inl(cs->hw.njet.base + NETJET_DMA_WRITE_IRQ))
+		/* the 2nd write page is free */
+		sval = 0x08;
+	else	/* the 1st write page is free */
+		sval = 0x04;	
+	if (inl(cs->hw.njet.base + NETJET_DMA_READ_ADR) <
+		inl(cs->hw.njet.base + NETJET_DMA_READ_IRQ))
+		/* the 2nd read page is free */
+		sval = sval | 0x02;
+	else	/* the 1st read page is free */
+		sval = sval | 0x01;	
+	if (sval != cs->hw.njet.last_is0) /* we have a DMA interrupt */
+	{
+		if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+			restore_flags(flags);
+			return;
+		}
+		cs->hw.njet.irqstat0 = sval;
+		restore_flags(flags);
+		if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) != 
+			(cs->hw.njet.last_is0 & NETJET_IRQM0_READ))
+			/* we have a read dma int */
+			read_tiger(cs);
+		if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) !=
+			(cs->hw.njet.last_is0 & NETJET_IRQM0_WRITE))
+			/* we have a write dma int */
+			write_tiger(cs);
+		/* end new code 13/07/00 GE */
+		test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+	} else
+		restore_flags(flags);
+
+/*	if (!testcnt--) {
+		cs->hw.njet.dmactrl = 0;
+		byteout(cs->hw.njet.base + NETJET_DMACTRL,
+			cs->hw.njet.dmactrl);
+		byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0);
+	}
+*/
+}
+
+static void
+reset_netjet_u(struct IsdnCardState *cs)
+{
+	long flags;
+
+	save_flags(flags);
+	sti();
+	cs->hw.njet.ctrl_reg = 0xff;  /* Reset On */
+	byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout((10*HZ)/1000);	/* Timeout 10ms */
+	cs->hw.njet.ctrl_reg = 0x40;  /* Reset Off and status read clear */
+	/* now edge triggered for TJ320 GE 13/07/00 */
+	byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout((10*HZ)/1000);	/* Timeout 10ms */
+	restore_flags(flags);
+	cs->hw.njet.auxd = 0xC0;
+	cs->hw.njet.dmactrl = 0;
+	byteout(cs->hw.njet.auxa, 0);
+	byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
+	byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
+	byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+}
+
+static int
+NETjet_U_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+	switch (mt) {
+		case CARD_RESET:
+			reset_netjet_u(cs);
+			return(0);
+		case CARD_RELEASE:
+			release_io_netjet(cs);
+			return(0);
+		case CARD_INIT:
+			inittiger(cs);
+			clear_pending_icc_ints(cs);
+			initicc(cs);
+			/* Reenable all IRQ */
+			cs->writeisac(cs, ICC_MASK, 0);
+			return(0);
+		case CARD_TEST:
+			return(0);
+	}
+	return(0);
+}
+
+static struct pci_dev *dev_netjet __initdata = NULL;
+
+int __init
+setup_netjet_u(struct IsdnCard *card)
+{
+	int bytecnt;
+	struct IsdnCardState *cs = card->cs;
+	char tmp[64];
+	long flags;
+#if CONFIG_PCI
+#endif
+#ifdef __BIG_ENDIAN
+#error "not running on big endian machines now"
+#endif
+	strcpy(tmp, NETjet_U_revision);
+	printk(KERN_INFO "HiSax: Traverse Tech. NETspider-U driver Rev. %s\n", HiSax_getrev(tmp));
+	if (cs->typ != ISDN_CTYPE_NETJET_U)
+		return(0);
+	test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+
+#if CONFIG_PCI
+
+	for ( ;; )
+	{
+		if (!pci_present()) {
+			printk(KERN_ERR "Netjet: no PCI bus present\n");
+			return(0);
+		}
+		if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET,
+			PCI_DEVICE_ID_TIGERJET_300,  dev_netjet))) {
+			if (pci_enable_device(dev_netjet))
+				return(0);
+			pci_set_master(dev_netjet);
+			cs->irq = dev_netjet->irq;
+			if (!cs->irq) {
+				printk(KERN_WARNING "NETspider-U: No IRQ for PCI card found\n");
+				return(0);
+			}
+			cs->hw.njet.base = dev_netjet->base_address[ 0] & PCI_BASE_ADDRESS_IO_MASK;
+			if (!cs->hw.njet.base) {
+				printk(KERN_WARNING "NETspider-U: No IO-Adr for PCI card found\n");
+				return(0);
+			}
+		} else {
+			printk(KERN_WARNING "NETspider-U: No PCI card found\n");
+			return(0);
+		}
+
+		cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
+		cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF;
+
+		save_flags(flags);
+		sti();
+
+		cs->hw.njet.ctrl_reg = 0xff;  /* Reset On */
+		byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout((10*HZ)/1000);	/* Timeout 10ms */
+
+		cs->hw.njet.ctrl_reg = 0x00;  /* Reset Off and status read clear */
+		byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout((10*HZ)/1000);	/* Timeout 10ms */
+
+		restore_flags(flags);
+
+		cs->hw.njet.auxd = 0xC0;
+		cs->hw.njet.dmactrl = 0;
+
+		byteout(cs->hw.njet.auxa, 0);
+		byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ);
+		byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ);
+		byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+
+		switch ( ( ( NETjet_ReadIC( cs, ICC_RBCH ) >> 5 ) & 3 ) )
+		{
+			case 3 :
+				break;
+
+			case 0 :
+				printk( KERN_WARNING "NETspider-U: NETjet-S PCI card found\n" );
+				continue;
+
+			default :
+				printk( KERN_WARNING "NETspider-U: No PCI card found\n" );
+				return 0;
+                }
+                break;
+	}
+#else
+
+	printk(KERN_WARNING "NETspider-U: NO_PCI_BIOS\n");
+	printk(KERN_WARNING "NETspider-U: unable to config NETspider-U PCI\n");
+	return (0);
+
+#endif /* CONFIG_PCI */
+
+	bytecnt = 256;
+
+	printk(KERN_INFO
+		"NETspider-U: PCI card configured at 0x%x IRQ %d\n",
+		cs->hw.njet.base, cs->irq);
+	if (check_region(cs->hw.njet.base, bytecnt)) {
+		printk(KERN_WARNING
+		       "HiSax: %s config port %x-%x already in use\n",
+		       CardType[card->typ],
+		       cs->hw.njet.base,
+		       cs->hw.njet.base + bytecnt);
+		return (0);
+	} else {
+		request_region(cs->hw.njet.base, bytecnt, "netspider-u isdn");
+	}
+	reset_netjet_u(cs);
+	cs->readisac  = &NETjet_ReadIC;
+	cs->writeisac = &NETjet_WriteIC;
+	cs->readisacfifo  = &NETjet_ReadICfifo;
+	cs->writeisacfifo = &NETjet_WriteICfifo;
+	cs->BC_Read_Reg  = &dummyrr;
+	cs->BC_Write_Reg = &dummywr;
+	cs->BC_Send_Data = &netjet_fill_dma;
+	cs->cardmsg = &NETjet_U_card_msg;
+	cs->irq_func = &netjet_u_interrupt;
+	cs->irq_flags |= SA_SHIRQ;
+	ICCVersion(cs, "NETspider-U:");
+	return (1);
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/q931.c linux.19p18/drivers/isdn/hisax/q931.c
--- linux.vanilla/drivers/isdn/hisax/q931.c	Fri Apr 21 12:46:11 2000
+++ linux.19p18/drivers/isdn/hisax/q931.c	Wed Dec 13 22:08:26 2000
@@ -1,9 +1,11 @@
-/* $Id: q931.c,v 1.7 1998/11/15 23:55:17 keil Exp $
-
+/* $Id: q931.c,v 1.10 2000/06/26 08:59:14 keil Exp $
+ *
  * q931.c       code to decode ITU Q.931 call control messages
  *
  * Author       Jan den Ouden
  *
+ * This file is (c) under GNU PUBLIC LICENSE
+ *
  * Changelog
  *
  * Pauline Middelink    general improvements
@@ -12,30 +14,6 @@
  *
  * Karsten Keil         cause texts, display information element for 1TR6
  *
- *
- * $Log: q931.c,v $
- * Revision 1.7  1998/11/15 23:55:17  keil
- * changes from 2.0
- *
- * Revision 1.6  1997/07/27 21:09:44  keil
- * move functions to isdnl3.c
- *
- * Revision 1.5  1997/04/06 22:56:43  keil
- * Some cosmetic changes
- *
- * Revision 1.4  1997/02/09 00:29:11  keil
- * new interface handling, one interface per card
- *
- * Revision 1.3  1997/01/21 22:24:59  keil
- * cleanups
- *
- * Revision 1.2  1996/10/27 22:12:45  keil
- * reporting unknown level 3 protocol ids
- *
- * Revision 1.1  1996/10/13 20:04:56  keil
- * Initial revision
- *
- *
  */
 
 
@@ -87,6 +65,24 @@
 		0xd, "SETUP ACKNOWLEDGE"
 	},
 	{
+		0x24, "HOLD"
+	},
+	{
+		0x28, "HOLD ACKNOWLEDGE"
+	},
+	{
+		0x30, "HOLD REJECT"
+	},
+	{
+		0x31, "RETRIEVE"
+	},
+	{
+		0x33, "RETRIEVE ACKNOWLEDGE"
+	},
+	{
+		0x37, "RETRIEVE REJECT"
+	},
+	{
 		0x26, "RESUME"
 	},
 	{
@@ -201,29 +197,6 @@
 
 #define MT_N1_LEN (sizeof(mt_n1) / sizeof(struct MessageType))
 
-static struct MessageType fac_1tr6[] =
-{
-	{FAC_Sperre, "Sperre"},
-	{FAC_Forward1, "Forward 1"},
-	{FAC_Forward2, "Forward 2"},
-	{FAC_Konferenz, "Konferenz"},
-	{FAC_GrabBchan, "Grab Bchannel"},
-	{FAC_Reactivate, "Reactivate"},
-	{FAC_Konferenz3, "Dreier Konferenz"},
-	{FAC_Dienstwechsel1, "Einseitiger Dienstwechsel"},
-	{FAC_Dienstwechsel2, "Zweiseitiger Dienstwechsel"},
-	{FAC_NummernIdent, "Rufnummer-Identifizierung"},
-	{FAC_GBG, "GBG"},
-	{FAC_DisplayUebergeben, "Display Uebergeben"},
-	{FAC_DisplayUmgeleitet, "Display Umgeleitet"},
-	{FAC_Unterdruecke, "Unterdruecke Rufnummer"},
-	{FAC_Deactivate, "Deactivate"},
-	{FAC_Activate, "Activate"},
-	{FAC_SPV, "SPV"},
-	{FAC_Rueckwechsel, "Rueckwechsel"},
-	{FAC_Umleitung, "Umleitung"}
-};
-#define FAC_1TR6_LEN (sizeof(fac_1tr6) / sizeof(struct MessageType))
 
 static int
 prbits(char *dest, u_char b, int start, int len)
@@ -683,6 +656,65 @@
 	return (dp - dest);
 }
 
+
+static
+int
+prbearer_ni1(char *dest, u_char * p)
+{
+	char *dp = dest;
+	u_char len;
+
+	p++;
+	len = *p++;
+	dp += sprintf(dp, "    octet 3  ");
+	dp += prbits(dp, *p, 8, 8);
+	switch (*p++) {
+		case 0x80:
+			dp += sprintf(dp, " Speech");
+			break;
+		case 0x88:
+			dp += sprintf(dp, " Unrestricted digital information");
+			break;
+		case 0x90:
+			dp += sprintf(dp, " 3.1 kHz audio");
+			break;
+		default:
+			dp += sprintf(dp, " Unknown information-transfer capability");
+	}
+	*dp++ = '\n';
+	dp += sprintf(dp, "    octet 4  ");
+	dp += prbits(dp, *p, 8, 8);
+	switch (*p++) {
+		case 0x90:
+			dp += sprintf(dp, " 64 kbps, circuit mode");
+			break;
+		case 0xc0:
+			dp += sprintf(dp, " Packet mode");
+			break;
+		default:
+			dp += sprintf(dp, " Unknown transfer mode");
+	}
+	*dp++ = '\n';
+	if (len > 2) {
+		dp += sprintf(dp, "    octet 5  ");
+		dp += prbits(dp, *p, 8, 8);
+		switch (*p++) {
+			case 0x21:
+				dp += sprintf(dp, " Rate adaption\n");
+				dp += sprintf(dp, "    octet 5a ");
+				dp += prbits(dp, *p, 8, 8);
+				break;
+			case 0xa2:
+				dp += sprintf(dp, " u-law");
+				break;
+			default:
+				dp += sprintf(dp, " Unknown UI layer 1 protocol");
+		}
+		*dp++ = '\n';
+	}
+	return (dp - dest);
+}
+
 static int
 general(char *dest, u_char * p)
 {
@@ -711,6 +743,33 @@
 }
 
 static int
+general_ni1(char *dest, u_char * p)
+{
+	char *dp = dest;
+	char ch = ' ';
+	int l, octet = 3;
+
+	p++;
+	l = *p++;
+	/* Iterate over all octets in the information element */
+	while (l--) {
+		dp += sprintf(dp, "    octet %d%c ", octet, ch);
+		dp += prbits(dp, *p, 8, 8);
+		*dp++ = '\n';
+
+		/* last octet in group? */
+		if (*p++ & 0x80) {
+			octet++;
+			ch = ' ';
+		} else if (ch == ' ')
+			ch = 'a';
+		else
+			ch++;
+	}
+	return (dp - dest);
+}
+
+static int
 prcharge(char *dest, u_char * p)
 {
 	char *dp = dest;
@@ -742,6 +801,112 @@
 	*dp++ = '\n';
 	return (dp - dest);
 }
+
+static int
+prfeatureind(char *dest, u_char * p)
+{
+	char *dp = dest;
+
+	p += 2; /* skip id, len */
+	dp += sprintf(dp, "    octet 3  ");
+	dp += prbits(dp, *p, 8, 8);
+	*dp++ = '\n';
+	if (!(*p++ & 80)) {
+		dp += sprintf(dp, "    octet 4  ");
+		dp += prbits(dp, *p++, 8, 8);
+		*dp++ = '\n';
+	}
+	dp += sprintf(dp, "    Status:  ");
+	switch (*p) {
+		case 0:
+			dp += sprintf(dp, "Idle");
+			break;
+		case 1:
+			dp += sprintf(dp, "Active");
+			break;
+		case 2:
+			dp += sprintf(dp, "Prompt");
+			break;
+		case 3:
+			dp += sprintf(dp, "Pending");
+			break;
+		default:
+			dp += sprintf(dp, "(Reserved)");
+			break;
+	}
+	*dp++ = '\n';
+	return (dp - dest);
+}
+
+static
+struct DTag { /* Display tags */
+	u_char nr;
+	char *descr;
+} dtaglist[] = {
+	{ 0x82, "Continuation" },
+	{ 0x83, "Called address" },
+	{ 0x84, "Cause" },
+	{ 0x85, "Progress indicator" },
+	{ 0x86, "Notification indicator" },
+	{ 0x87, "Prompt" },
+	{ 0x88, "Accumlated digits" },
+	{ 0x89, "Status" },
+	{ 0x8a, "Inband" },
+	{ 0x8b, "Calling address" },
+	{ 0x8c, "Reason" },
+	{ 0x8d, "Calling party name" },
+	{ 0x8e, "Called party name" },
+	{ 0x8f, "Orignal called name" },
+	{ 0x90, "Redirecting name" },
+	{ 0x91, "Connected name" },
+	{ 0x92, "Originating restrictions" },
+	{ 0x93, "Date & time of day" },
+	{ 0x94, "Call Appearance ID" },
+	{ 0x95, "Feature address" },
+	{ 0x96, "Redirection name" },
+	{ 0x9e, "Text" },
+};
+#define DTAGSIZE sizeof(dtaglist)/sizeof(struct DTag)
+
+static int
+disptext_ni1(char *dest, u_char * p)
+{
+	char *dp = dest;
+	int l, tag, len, i;
+
+	p++;
+	l = *p++ - 1;
+	if (*p++ != 0x80) {
+		dp += sprintf(dp, "    Unknown display type\n");
+		return (dp - dest);
+	}
+	/* Iterate over all tag,length,text fields */
+	while (l > 0) {
+		tag = *p++;
+		len = *p++;
+		l -= len + 2;
+		/* Don't space or skip */
+		if ((tag == 0x80) || (tag == 0x81)) p++;
+		else {
+			for (i = 0; i < DTAGSIZE; i++)
+				if (tag == dtaglist[i].nr)
+					break;
+
+			/* When not found, give appropriate msg */
+			if (i != DTAGSIZE) {
+				dp += sprintf(dp, "    %s: ", dtaglist[i].descr);
+				while (len--)
+					*dp++ = *p++;
+			} else {
+				dp += sprintf(dp, "    (unknown display tag %2x): ", tag);
+				while (len--)
+					*dp++ = *p++;
+			}
+			dp += sprintf(dp, "\n");
+                }
+	}
+	return (dp - dest);
+}
 static int
 display(char *dest, u_char * p)
 {
@@ -912,6 +1077,49 @@
 
 #define IESIZE sizeof(ielist)/sizeof(struct InformationElement)
 
+static
+struct InformationElement ielist_ni1[] = {
+	{ 0x04, "Bearer Capability", prbearer_ni1 },
+	{ 0x08, "Cause", prcause },
+	{ 0x14, "Call State", general_ni1 },
+	{ 0x18, "Channel Identification", prchident },
+	{ 0x1e, "Progress Indicator", general_ni1 },
+	{ 0x27, "Notification Indicator", general_ni1 },
+	{ 0x2c, "Keypad Facility", prtext },
+	{ 0x32, "Information Request", general_ni1 },
+	{ 0x34, "Signal", general_ni1 },
+	{ 0x38, "Feature Activation", general_ni1 },
+	{ 0x39, "Feature Indication", prfeatureind },
+	{ 0x3a, "Service Profile Identification (SPID)", prtext },
+	{ 0x3b, "Endpoint Identifier", general_ni1 },
+	{ 0x6c, "Calling Party Number", prcalling },
+	{ 0x6d, "Calling Party Subaddress", general_ni1 },
+	{ 0x70, "Called Party Number", prcalled },
+	{ 0x71, "Called Party Subaddress", general_ni1 },
+	{ 0x74, "Redirecting Number", general_ni1 },
+	{ 0x78, "Transit Network Selection", general_ni1 },
+	{ 0x7c, "Low Layer Compatibility", general_ni1 },
+	{ 0x7d, "High Layer Compatibility", general_ni1 },
+};
+
+
+#define IESIZE_NI1 sizeof(ielist_ni1)/sizeof(struct InformationElement)
+
+static
+struct InformationElement ielist_ni1_cs5[] = {
+	{ 0x1d, "Operator system access", general_ni1 },
+	{ 0x2a, "Display text", disptext_ni1 },
+};
+
+#define IESIZE_NI1_CS5 sizeof(ielist_ni1_cs5)/sizeof(struct InformationElement)
+
+static
+struct InformationElement ielist_ni1_cs6[] = {
+	{ 0x7b, "Call appearance", general_ni1 },
+};
+
+#define IESIZE_NI1_CS6 sizeof(ielist_ni1_cs6)/sizeof(struct InformationElement)
+
 static struct InformationElement we_0[] =
 {
 	{WE0_cause, "Cause", prcause_1tr6},
@@ -1152,7 +1360,93 @@
 			}
 			buf += buf[1] + 2;
 		}
-	} else if (buf[0] == 8) {	/* EURO */
+	} else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_NI1)) {	/* NI-1 */
+		/* locate message type */
+		buf++;
+		cr_l = *buf++;
+		if (cr_l)
+			cr = *buf++;
+		else
+			cr = 0;
+		mt = *buf++;
+		for (i = 0; i < MTSIZE; i++)
+			if (mtlist[i].nr == mt)
+				break;
+
+		/* display message type if it exists */
+		if (i == MTSIZE)
+			dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n",
+			    cr & 0x7f, (cr & 0x80) ? "called" : "caller",
+				      size, mt);
+		else
+			dp += sprintf(dp, "callref %d %s size %d message type %s\n",
+			    cr & 0x7f, (cr & 0x80) ? "called" : "caller",
+				      size, mtlist[i].descr);
+
+		/* display each information element */
+		while (buf < bend) {
+			/* Is it a single octet information element? */
+			if (*buf & 0x80) {
+				switch ((*buf >> 4) & 7) {
+					case 1:
+						dp += sprintf(dp, "  Shift %x\n", *buf & 0xf);
+						cs_old = cset;
+						cset = *buf & 7;
+						cs_fest = *buf & 8;
+						break;
+					default:
+						dp += sprintf(dp, "  Unknown single-octet IE %x\n", *buf);
+						break;
+				}
+				buf++;
+				continue;
+			}
+			/* No, locate it in the table */
+			if (cset == 0) {
+				for (i = 0; i < IESIZE; i++)
+					if (*buf == ielist_ni1[i].nr)
+						break;
+
+				/* When not found, give appropriate msg */
+				if (i != IESIZE) {
+					dp += sprintf(dp, "  %s\n", ielist_ni1[i].descr);
+					dp += ielist_ni1[i].f(dp, buf);
+				} else
+					dp += sprintf(dp, "  attribute %x attribute size %d\n", *buf, buf[1]);
+			} else if (cset == 5) {
+				for (i = 0; i < IESIZE_NI1_CS5; i++)
+					if (*buf == ielist_ni1_cs5[i].nr)
+						break;
+
+				/* When not found, give appropriate msg */
+				if (i != IESIZE_NI1_CS5) {
+					dp += sprintf(dp, "  %s\n", ielist_ni1_cs5[i].descr);
+					dp += ielist_ni1_cs5[i].f(dp, buf);
+				} else
+					dp += sprintf(dp, "  attribute %x attribute size %d\n", *buf, buf[1]);
+			} else if (cset == 6) {
+				for (i = 0; i < IESIZE_NI1_CS6; i++)
+					if (*buf == ielist_ni1_cs6[i].nr)
+						break;
+
+				/* When not found, give appropriate msg */
+				if (i != IESIZE_NI1_CS6) {
+					dp += sprintf(dp, "  %s\n", ielist_ni1_cs6[i].descr);
+					dp += ielist_ni1_cs6[i].f(dp, buf);
+				} else
+					dp += sprintf(dp, "  attribute %x attribute size %d\n", *buf, buf[1]);
+			} else
+				dp += sprintf(dp, "  Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]);
+
+			/* Skip to next element */
+			if (cs_fest == 8) {
+				cset = cs_old;
+				cs_old = 0;
+				cs_fest = 0;
+			}
+			buf += buf[1] + 2;
+		}
+	} else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_EURO)) { /* EURO */
 		/* locate message type */
 		buf++;
 		cr_l = *buf++;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/rawhdlc.c linux.19p18/drivers/isdn/hisax/rawhdlc.c
--- linux.vanilla/drivers/isdn/hisax/rawhdlc.c	Fri Apr 21 12:46:11 2000
+++ linux.19p18/drivers/isdn/hisax/rawhdlc.c	Wed Dec 13 22:08:26 2000
@@ -1,10 +1,11 @@
-/* $Id: rawhdlc.c,v 1.4 1999/12/23 15:09:32 keil Exp $
-
+/* $Id: rawhdlc.c,v 1.5 2000/06/26 08:59:14 keil Exp $
+ *
  * rawhdlc.c     support routines for cards that don't support HDLC
  *
  * Author     Karsten Keil (keil@isdn4linux.de)
  *            Brent Baccala <baccala@FreeSoft.org>
  *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  * Some passive ISDN cards, such as the Traverse NETJet and the AMD 7930,
  * don't perform HDLC encapsulation over the B channel.  Drivers for
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/rawhdlc.h linux.19p18/drivers/isdn/hisax/rawhdlc.h
--- linux.vanilla/drivers/isdn/hisax/rawhdlc.h	Fri Apr 21 12:46:11 2000
+++ linux.19p18/drivers/isdn/hisax/rawhdlc.h	Wed Dec 13 22:08:26 2000
@@ -1,8 +1,10 @@
-/* $Id: rawhdlc.h,v 1.2 1998/02/09 10:53:53 keil Exp $
-
+/* $Id: rawhdlc.h,v 1.3 2000/06/26 08:59:14 keil Exp $
+ *
  * rawhdlc.h     support routines for cards that don't support HDLC
  *
  * Author     Brent Baccala <baccala@FreeSoft.org>
+ *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/s0box.c linux.19p18/drivers/isdn/hisax/s0box.c
--- linux.vanilla/drivers/isdn/hisax/s0box.c	Fri Apr 21 12:46:11 2000
+++ linux.19p18/drivers/isdn/hisax/s0box.c	Mon Feb 12 15:09:50 2001
@@ -1,19 +1,21 @@
-/* $Id: s0box.c,v 2.2 1999/07/12 21:05:25 keil Exp $
-
+/* $Id: s0box.c,v 2.4 2000/11/24 17:05:38 kai Exp $
+ *
  * s0box.c      low level stuff for Creatix S0BOX
  *
  * Author       S0BOX specific stuff: Enrik Berkhan (enrik@starfleet.inka.de)
  *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
 #include "isdnl1.h"
 
 extern const char *CardType[];
-const char *s0box_revision = "$Revision: 2.2 $";
+const char *s0box_revision = "$Revision: 2.4 $";
 
 static inline void
 writereg(unsigned int padr, signed int addr, u_char off, u_char val) {
@@ -212,8 +214,8 @@
 	return(0);
 }
 
-__initfunc(int
-setup_s0box(struct IsdnCard *card))
+int __init
+setup_s0box(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/saphir.c linux.19p18/drivers/isdn/hisax/saphir.c
--- linux.vanilla/drivers/isdn/hisax/saphir.c	Fri Apr 21 12:46:11 2000
+++ linux.19p18/drivers/isdn/hisax/saphir.c	Mon Feb 12 15:09:50 2001
@@ -1,39 +1,25 @@
-/* $Id: saphir.c,v 1.5 1999/12/19 13:09:42 keil Exp $
-
+/* $Id: saphir.c,v 1.8 2000/11/24 17:05:38 kai Exp $
+ *
  * saphir.c low level stuff for HST Saphir 1
  *
  * Author     Karsten Keil (keil@isdn4linux.de)
  *
  * Thanks to    HST High Soft Tech GmbH
  *
- *
- * $Log: saphir.c,v $
- * Revision 1.5  1999/12/19 13:09:42  keil
- * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
- * signal proof delays
- *
- * Revision 1.4  1999/09/04 06:20:06  keil
- * Changes from kernel set_current_state()
- *
- * Revision 1.3  1999/07/12 21:05:26  keil
- * fix race in IRQ handling
- * added watchdog for lost IRQs
- *
- * Revision 1.2  1999/07/01 08:07:55  keil
- * Initial version
- *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
 #include "isdnl1.h"
 
 extern const char *CardType[];
-static char *saphir_rev = "$Revision: 1.5 $";
+static char *saphir_rev = "$Revision: 1.8 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -173,11 +159,9 @@
 		goto Start_ISAC;
 	}
 	/* Watchdog */
-	if (cs->hw.saphir.timer.function) {
-		del_timer(&cs->hw.saphir.timer);
-		cs->hw.saphir.timer.expires = jiffies + 1*HZ;
-		add_timer(&cs->hw.saphir.timer);
-	} else
+	if (cs->hw.saphir.timer.function) 
+		mod_timer(&cs->hw.saphir.timer, jiffies+1*HZ);
+	else
 		printk(KERN_WARNING "saphir: Spurious timer!\n");
 	writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK, 0xFF);
 	writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK + 0x40, 0xFF);
@@ -192,9 +176,7 @@
 {
         /* 5 sec WatchDog, so read at least every 4 sec */
 	cs->readisac(cs, ISAC_RBCH);
-	del_timer(&cs->hw.saphir.timer);
-	cs->hw.saphir.timer.expires = jiffies + 1*HZ;
-	add_timer(&cs->hw.saphir.timer);
+	mod_timer(&cs->hw.saphir.timer, jiffies+1*HZ);
 }
 
 void
@@ -241,10 +223,10 @@
 	save_flags(flags);
 	sti();
 	byteout(cs->hw.saphir.cfg_reg + RESET_REG, 1);
-	current->state = TASK_UNINTERRUPTIBLE;
+	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout((30*HZ)/1000);	/* Timeout 30ms */
 	byteout(cs->hw.saphir.cfg_reg + RESET_REG, 0);
-	current->state = TASK_UNINTERRUPTIBLE;
+	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout((30*HZ)/1000);	/* Timeout 30ms */
 	restore_flags(flags);
 	byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val);
@@ -272,8 +254,8 @@
 }
 
 
-__initfunc(int
-setup_saphir(struct IsdnCard *card))
+int __init
+setup_saphir(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/sedlbauer.c linux.19p18/drivers/isdn/hisax/sedlbauer.c
--- linux.vanilla/drivers/isdn/hisax/sedlbauer.c	Fri Apr 21 12:46:11 2000
+++ linux.19p18/drivers/isdn/hisax/sedlbauer.c	Tue Feb 13 18:50:48 2001
@@ -1,5 +1,5 @@
-/* $Id: sedlbauer.c,v 1.20 2000/01/20 19:47:45 keil Exp $
-
+/* $Id: sedlbauer.c,v 1.25.6.3 2001/02/13 10:33:58 kai Exp $
+ *
  * sedlbauer.c  low level stuff for Sedlbauer cards
  *              includes support for the Sedlbauer speed star (speed star II),
  *              support for the Sedlbauer speed fax+,
@@ -16,71 +16,7 @@
  *            Sedlbauer AG for informations
  *            Edgar Toernig
  *
- * $Log: sedlbauer.c,v $
- * Revision 1.20  2000/01/20 19:47:45  keil
- * Add Fax Class 1 support
- *
- * Revision 1.19  1999/12/19 13:09:42  keil
- * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
- * signal proof delays
- *
- * Revision 1.18  1999/11/13 21:25:03  keil
- * Support for Speedfax+ PCI
- *
- * Revision 1.17  1999/09/04 06:20:06  keil
- * Changes from kernel set_current_state()
- *
- * Revision 1.16  1999/08/29 18:23:01  niemann
- * Fixed typo in errormsg
- *
- * Revision 1.15  1999/08/25 17:00:00  keil
- * Make ISAR V32bis modem running
- * Make LL->HL interface open for additional commands
- *
- * Revision 1.14  1999/08/11 20:59:22  keil
- * new PCI codefix
- * fix IRQ problem while unload
- *
- * Revision 1.13  1999/08/10 16:02:08  calle
- * struct pci_dev changed in 2.3.13. Made the necessary changes.
- *
- * Revision 1.12  1999/08/05 20:43:22  keil
- * ISAR analog modem support
- *
- * Revision 1.11  1999/07/12 21:05:27  keil
- * fix race in IRQ handling
- * added watchdog for lost IRQs
- *
- * Revision 1.10  1999/07/01 08:12:09  keil
- * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
- *
- * Revision 1.9  1998/11/15 23:55:20  keil
- * changes from 2.0
- *
- * Revision 1.8  1998/08/13 23:34:51  keil
- * starting speedfax+ (ISAR) support
- *
- * Revision 1.7  1998/04/15 16:44:33  keil
- * new init code
- *
- * Revision 1.6  1998/02/09 18:46:06  keil
- * Support for Sedlbauer PCMCIA (Marcus Niemann)
- *
- * Revision 1.5  1998/02/02 13:29:45  keil
- * fast io
- *
- * Revision 1.4  1997/11/08 21:35:52  keil
- * new l1 init
- *
- * Revision 1.3  1997/11/06 17:09:28  keil
- * New 2.1 init code
- *
- * Revision 1.2  1997/10/29 18:55:52  keil
- * changes for 2.1.60 (irq2dev_map)
- *
- * Revision 1.1  1997/09/11 17:32:04  keil
- * new
- *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 
@@ -103,9 +39,8 @@
  * For example: hisaxctrl <DriverID> 9 ISAR.BIN
 */
 
-#define SEDLBAUER_PCI 1
-
 #define __NO_VERSION__
+#include <linux/init.h>
 #include <linux/config.h>
 #include "hisax.h"
 #include "isac.h"
@@ -114,22 +49,21 @@
 #include "isar.h"
 #include "isdnl1.h"
 #include <linux/pci.h>
+#include <linux/isdn_compat.h>
 
 extern const char *CardType[];
 
-const char *Sedlbauer_revision = "$Revision: 1.20 $";
+const char *Sedlbauer_revision = "$Revision: 1.25.6.3 $";
 
 const char *Sedlbauer_Types[] =
 	{"None", "speed card/win", "speed star", "speed fax+", 
 	"speed win II / ISDN PC/104", "speed star II", "speed pci",
-	"speed fax+ pci"};
+	"speed fax+ pyramid", "speed fax+ pci"};
 
-#ifdef SEDLBAUER_PCI
-#define PCI_VENDOR_SEDLBAUER	0xe159
-#define PCI_SPEEDPCI_ID		0x02
-#define PCI_SUBVENDOR_SEDLBAUER	0x51
-#define PCI_SUB_ID_SPEEDFAXP	0x01
-#endif
+#define PCI_SUBVENDOR_SPEEDFAX_PYRAMID	0x51
+#define PCI_SUBVENDOR_SEDLBAUER_PCI	0x53
+#define PCI_SUBVENDOR_SPEEDFAX_PCI	0x54
+#define PCI_SUB_ID_SEDLBAUER		0x01
  
 #define SEDL_SPEED_CARD_WIN	1
 #define SEDL_SPEED_STAR 	2
@@ -137,7 +71,8 @@
 #define SEDL_SPEED_WIN2_PC104 	4
 #define SEDL_SPEED_STAR2 	5
 #define SEDL_SPEED_PCI   	6
-#define SEDL_SPEEDFAX_PCI	7
+#define SEDL_SPEEDFAX_PYRAMID	7
+#define SEDL_SPEEDFAX_PCI	8
 
 #define SEDL_CHIP_TEST		0
 #define SEDL_CHIP_ISAC_HSCX	1
@@ -349,10 +284,10 @@
 	}
 
 	if ((cs->hw.sedl.bus == SEDL_BUS_PCMCIA) && (*cs->busy_flag == 1)) {
-          /* The card tends to generate interrupts while being removed
-             causing us to just crash the kernel. bad. */
-          printk(KERN_WARNING "Sedlbauer: card not available!\n");
-          return;
+		/* The card tends to generate interrupts while being removed
+		   causing us to just crash the kernel. bad. */
+		printk(KERN_WARNING "Sedlbauer: card not available!\n");
+		return;
         }
 
 	val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40);
@@ -424,7 +359,8 @@
 		goto Start_IPAC;
 	}
 	if (!icnt)
-		printk(KERN_WARNING "Sedlbauer IRQ LOOP\n");
+		if (cs->debug & L1_DEB_ISAC)
+			debugl1(cs, "Sedlbauer IRQ LOOP");
 	writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xFF);
 	writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xC0);
 }
@@ -462,7 +398,8 @@
 		goto Start_ISAC;
 	}
 	if (!cnt)
-		printk(KERN_WARNING "Sedlbauer IRQ LOOP\n");
+		if (cs->debug & L1_DEB_ISAC)
+			debugl1(cs, "Sedlbauer IRQ LOOP");
 
 	writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT, 0);
 	writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0xFF);
@@ -497,10 +434,10 @@
 			writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_POTA2, 0x20);
 			save_flags(flags);
 			sti();
-			current->state = TASK_UNINTERRUPTIBLE;
+			set_current_state(TASK_UNINTERRUPTIBLE);
 			schedule_timeout((10*HZ)/1000);
 			writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_POTA2, 0x0);
-			current->state = TASK_UNINTERRUPTIBLE;
+			set_current_state(TASK_UNINTERRUPTIBLE);
 			schedule_timeout((10*HZ)/1000);
 			writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_CONF, 0x0);
 			writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ACFG, 0xff);
@@ -523,10 +460,10 @@
 			byteout(cs->hw.sedl.reset_on, SEDL_RESET);	/* Reset On */
 			save_flags(flags);
 			sti();
-			current->state = TASK_UNINTERRUPTIBLE;
+			set_current_state(TASK_UNINTERRUPTIBLE);
 			schedule_timeout((10*HZ)/1000);
 			byteout(cs->hw.sedl.reset_off, 0);	/* Reset Off */
-			current->state = TASK_UNINTERRUPTIBLE;
+			set_current_state(TASK_UNINTERRUPTIBLE);
 			schedule_timeout((10*HZ)/1000);
 			restore_flags(flags);
 		}
@@ -572,7 +509,7 @@
 		case CARD_TEST:
 			return(0);
 		case MDL_INFO_CONN:
-			if (cs->subtyp != SEDL_SPEEDFAX_PCI)
+			if (cs->subtyp != SEDL_SPEEDFAX_PYRAMID)
 				return(0);
 			if ((long) arg)
 				cs->hw.sedl.reset_off &= ~SEDL_ISAR_PCI_LED2;
@@ -581,7 +518,7 @@
 			byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
 			break;
 		case MDL_INFO_REL:
-			if (cs->subtyp != SEDL_SPEEDFAX_PCI)
+			if (cs->subtyp != SEDL_SPEEDFAX_PYRAMID)
 				return(0);
 			if ((long) arg)
 				cs->hw.sedl.reset_off |= SEDL_ISAR_PCI_LED2;
@@ -593,12 +530,10 @@
 	return(0);
 }
 
-#ifdef SEDLBAUER_PCI
-static 	struct pci_dev *dev_sedl __initdata = NULL;
-#endif
+static struct pci_dev *dev_sedl  = NULL;
 
-__initfunc(int
-setup_sedlbauer(struct IsdnCard *card))
+int 
+setup_sedlbauer(struct IsdnCard *card)
 {
 	int bytecnt, ver, val;
 	struct IsdnCardState *cs = card->cs;
@@ -633,42 +568,50 @@
 		}
 	} else {
 /* Probe for Sedlbauer speed pci */
-#if SEDLBAUER_PCI
 #if CONFIG_PCI
 		if (!pci_present()) {
 			printk(KERN_ERR "Sedlbauer: no PCI bus present\n");
 			return(0);
 		}
-		if ((dev_sedl = pci_find_device(PCI_VENDOR_SEDLBAUER,
-				PCI_SPEEDPCI_ID, dev_sedl))) {
+		if ((dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET,
+				PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) {
+			if (pci_enable_device(dev_sedl))
+				return(0);
 			cs->irq = dev_sedl->irq;
 			if (!cs->irq) {
 				printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n");
 				return(0);
 			}
-			cs->hw.sedl.cfg_reg = dev_sedl->base_address[ 0] &
-				PCI_BASE_ADDRESS_IO_MASK; 
+			cs->hw.sedl.cfg_reg = dev_sedl->base_address[ 0] & PCI_BASE_ADDRESS_IO_MASK;
 		} else {
 			printk(KERN_WARNING "Sedlbauer: No PCI card found\n");
 			return(0);
 		}
 		cs->irq_flags |= SA_SHIRQ;
 		cs->hw.sedl.bus = SEDL_BUS_PCI;
-		pci_read_config_word(dev_sedl, PCI_SUBSYSTEM_VENDOR_ID,
-			&sub_vendor_id);
-		pci_read_config_word(dev_sedl, PCI_SUBSYSTEM_ID,
-			&sub_id);
+		pci_read_config_word(dev_sedl, PCI_SUBSYSTEM_VENDOR_ID, &sub_vendor_id);
+		pci_read_config_word(dev_sedl, PCI_SUBSYSTEM_ID, &sub_id);
 		printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n",
 			sub_vendor_id, sub_id);
 		printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n",
 			cs->hw.sedl.cfg_reg);
-		if ((sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER) &&
-			(sub_id == PCI_SUB_ID_SPEEDFAXP)) {
+		if (sub_id != PCI_SUB_ID_SEDLBAUER) {
+			printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id);
+			return(0);
+		}
+		if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) {
+			cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
+			cs->subtyp = SEDL_SPEEDFAX_PYRAMID;
+		} else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) {
 			cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
 			cs->subtyp = SEDL_SPEEDFAX_PCI;
-		} else {
+		} else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) {
 			cs->hw.sedl.chip = SEDL_CHIP_IPAC;
 			cs->subtyp = SEDL_SPEED_PCI;
+		} else {
+			printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n",
+				sub_vendor_id);
+			return(0);
 		}
 		bytecnt = 256;
 		cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON;
@@ -688,7 +631,6 @@
 		printk(KERN_WARNING "Sedlbauer: NO_PCI_BIOS\n");
 		return (0);
 #endif /* CONFIG_PCI */
-#endif /* SEDLBAUER_PCI */
 	}	
 	
        	/* In case of the sedlbauer pcmcia card, this region is in use,
@@ -748,7 +690,6 @@
 
 
 	if (cs->hw.sedl.chip == SEDL_CHIP_IPAC) {
-	/* IPAC */
 		if (cs->hw.sedl.bus == SEDL_BUS_PCI) {
 	                cs->hw.sedl.adr  = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_ADR;
         	        cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_IPAC;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/sportster.c linux.19p18/drivers/isdn/hisax/sportster.c
--- linux.vanilla/drivers/isdn/hisax/sportster.c	Fri Apr 21 12:46:12 2000
+++ linux.19p18/drivers/isdn/hisax/sportster.c	Tue Feb 13 18:50:48 2001
@@ -1,59 +1,23 @@
-/* $Id: sportster.c,v 1.12 1999/12/23 15:09:32 keil Exp $
-
+/* $Id: sportster.c,v 1.14 2000/11/24 17:05:38 kai Exp $
+ *
  * sportster.c     low level stuff for USR Sportster internal TA
  *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *
  * Thanks to Christian "naddy" Weisgerber (3Com, US Robotics) for documentation
  *
- * $Log: sportster.c,v $
- * Revision 1.12  1999/12/23 15:09:32  keil
- * change email
- *
- * Revision 1.11  1999/12/19 13:09:42  keil
- * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
- * signal proof delays
- *
- * Revision 1.10  1999/09/04 06:20:06  keil
- * Changes from kernel set_current_state()
- *
- * Revision 1.9  1999/07/12 21:05:29  keil
- * fix race in IRQ handling
- * added watchdog for lost IRQs
- *
- * Revision 1.8  1999/07/01 08:12:10  keil
- * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
- *
- * Revision 1.7  1998/11/15 23:55:22  keil
- * changes from 2.0
- *
- * Revision 1.6  1998/04/15 16:44:35  keil
- * new init code
- *
- * Revision 1.5  1998/02/02 13:29:46  keil
- * fast io
- *
- * Revision 1.4  1997/11/08 21:35:52  keil
- * new l1 init
- *
- * Revision 1.3  1997/11/06 17:09:29  keil
- * New 2.1 init code
- *
- * Revision 1.2  1997/10/29 18:51:18  keil
- * New files
- *
- * Revision 1.1.2.1  1997/10/17 22:10:58  keil
- * new files on 2.0
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
 #include "isdnl1.h"
 
 extern const char *CardType[];
-const char *sportster_revision = "$Revision: 1.12 $";
+const char *sportster_revision = "$Revision: 1.14 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -187,11 +151,11 @@
 	byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
 	save_flags(flags);
 	sti();
-	current->state = TASK_UNINTERRUPTIBLE;
+	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout((10*HZ)/1000);
 	cs->hw.spt.res_irq &= ~SPORTSTER_RESET; /* Reset Off */
 	byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq);
-	current->state = TASK_UNINTERRUPTIBLE;
+	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout((10*HZ)/1000);
 	restore_flags(flags);
 }
@@ -218,8 +182,8 @@
 	return(0);
 }
 
-__initfunc(int
-get_io_range(struct IsdnCardState *cs))
+static int __init
+get_io_range(struct IsdnCardState *cs)
 {
 	int i, j, adr;
 	
@@ -244,8 +208,8 @@
 	}
 }
 
-__initfunc(int
-setup_sportster(struct IsdnCard *card))
+int __init
+setup_sportster(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/tei.c linux.19p18/drivers/isdn/hisax/tei.c
--- linux.vanilla/drivers/isdn/hisax/tei.c	Fri Apr 21 12:46:12 2000
+++ linux.19p18/drivers/isdn/hisax/tei.c	Tue Feb 13 18:50:48 2001
@@ -1,5 +1,5 @@
-/* $Id: tei.c,v 2.13 1999/07/21 14:46:28 keil Exp $
-
+/* $Id: tei.c,v 2.17 2000/11/24 17:05:38 kai Exp $
+ *
  * Author       Karsten Keil (keil@isdn4linux.de)
  *              based on the teles driver from Jan den Ouden
  *
@@ -10,75 +10,14 @@
  * Thanks to    Jan den Ouden
  *              Fritz Elfert
  *
- * $Log: tei.c,v $
- * Revision 2.13  1999/07/21 14:46:28  keil
- * changes from EICON certification
- *
- * Revision 2.12  1999/07/01 08:12:11  keil
- * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
- *
- * Revision 2.11  1998/11/15 23:55:24  keil
- * changes from 2.0
- *
- * Revision 2.10  1998/05/25 14:08:10  keil
- * HiSax 3.0
- * fixed X.75 and leased line to work again
- * Point2Point and fixed TEI are runtime options now:
- *    hisaxctrl <id> 7 1  set PTP
- *    hisaxctrl <id> 8 <TEIVALUE *2 >
- *    set fixed TEI to TEIVALUE (0-63)
- *
- * Revision 2.9  1998/05/25 12:58:23  keil
- * HiSax golden code from certification, Don't use !!!
- * No leased lines, no X75, but many changes.
- *
- * Revision 2.8  1998/03/07 22:57:07  tsbogend
- * made HiSax working on Linux/Alpha
- *
- * Revision 2.7  1998/02/12 23:08:11  keil
- * change for 2.1.86 (removing FREE_READ/FREE_WRITE from [dev]_kfree_skb()
- *
- * Revision 2.6  1998/02/02 13:41:42  keil
- * fix MDL_ASSIGN for PtP
- *
- * Revision 2.5  1997/11/06 17:09:12  keil
- * New 2.1 init code
- *
- * Revision 2.4  1997/10/29 19:04:46  keil
- * changes for 2.1
- *
- * Revision 2.3  1997/10/01 09:21:43  fritz
- * Removed old compatibility stuff for 2.0.X kernels.
- * From now on, this code is for 2.1.X ONLY!
- * Old stuff is still in the separate branch.
- *
- * Revision 2.2  1997/07/31 19:24:39  keil
- * fixed a warning
- *
- * Revision 2.1  1997/07/31 11:50:16  keil
- * ONE TEI and FIXED TEI handling
- *
- * Revision 2.0  1997/07/27 21:13:30  keil
- * New TEI managment
- *
- * Revision 1.9  1997/06/26 11:18:02  keil
- * New managment
- *
- * Revision 1.8  1997/04/07 22:59:08  keil
- * GFP_KERNEL --> GFP_ATOMIC
- *
- * Revision 1.7  1997/04/06 22:54:03  keil
- * Using SKB's
- *
- * Old log removed/ KKe
- *
  */
 #define __NO_VERSION__
 #include "hisax.h"
 #include "isdnl2.h"
+#include <linux/init.h>
 #include <linux/random.h>
 
-const char *tei_revision = "$Revision: 2.13 $";
+const char *tei_revision = "$Revision: 2.17 $";
 
 #define ID_REQUEST	1
 #define ID_ASSIGNED	2
@@ -90,9 +29,7 @@
 
 #define TEI_ENTITY_ID	0xf
 
-static
-struct Fsm teifsm =
-{NULL, 0, 0, NULL, NULL};
+static struct Fsm teifsm;
 
 void tei_handler(struct PStack *st, u_char pr, struct sk_buff *skb);
 
@@ -216,7 +153,7 @@
 	if (st->ma.debug)
 		st->ma.tei_m.printdebug(&st->ma.tei_m,
 			"identity assign ri %d tei %d", ri, tei);
-	if ((ost = findtei(st, tei))) {		/* same tei is in use */
+	if ((ost = findtei(st, tei))) {	/* same tei is in use */
 		if (ri != ost->ma.ri) {
 			st->ma.tei_m.printdebug(&st->ma.tei_m,
 				"possible duplicate assignment tei %d", tei);
@@ -243,10 +180,12 @@
 	if (st->ma.debug)
 		st->ma.tei_m.printdebug(&st->ma.tei_m,
 			"foreign identity assign ri %d tei %d", ri, tei);
-	if ((ost = findtei(st, tei))) {		/* same tei is in use */
-		st->ma.tei_m.printdebug(&st->ma.tei_m,
-			"possible duplicate assignment tei %d", tei);
-		FsmEvent(&ost->ma.tei_m, EV_VERIFY, NULL);
+	if ((ost = findtei(st, tei))) {	/* same tei is in use */
+		if (ri != ost->ma.ri) {	/* and it wasn't our request */
+			st->ma.tei_m.printdebug(&st->ma.tei_m,
+				"possible duplicate assignment tei %d", tei);
+			FsmEvent(&ost->ma.tei_m, EV_VERIFY, NULL);
+		}
 	} 
 }
 
@@ -490,7 +429,7 @@
 	}
 }
 
-static struct FsmNode TeiFnList[] HISAX_INITDATA =
+static struct FsmNode TeiFnList[] __initdata =
 {
 	{ST_TEI_NOP, EV_IDREQ, tei_id_request},
 	{ST_TEI_NOP, EV_ASSIGN, tei_id_test_dup},
@@ -507,8 +446,8 @@
 
 #define TEI_FN_COUNT (sizeof(TeiFnList)/sizeof(struct FsmNode))
 
-HISAX_INITFUNC(void
-TeiNew(void))
+void __init
+TeiNew(void)
 {
 	teifsm.state_count = TEI_STATE_COUNT;
 	teifsm.event_count = TEI_EVENT_COUNT;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/teleint.c linux.19p18/drivers/isdn/hisax/teleint.c
--- linux.vanilla/drivers/isdn/hisax/teleint.c	Fri Apr 21 12:46:12 2000
+++ linux.19p18/drivers/isdn/hisax/teleint.c	Mon Feb 12 15:09:50 2001
@@ -1,53 +1,15 @@
-/* $Id: teleint.c,v 1.12 1999/12/19 13:09:42 keil Exp $
-
+/* $Id: teleint.c,v 1.14 2000/11/24 17:05:38 kai Exp $
+ *
  * teleint.c     low level stuff for TeleInt isdn cards
  *
  * Author     Karsten Keil (keil@isdn4linux.de)
  *
- *
- * $Log: teleint.c,v $
- * Revision 1.12  1999/12/19 13:09:42  keil
- * changed TASK_INTERRUPTIBLE into TASK_UNINTERRUPTIBLE for
- * signal proof delays
- *
- * Revision 1.11  1999/09/04 06:20:06  keil
- * Changes from kernel set_current_state()
- *
- * Revision 1.10  1999/08/31 11:20:27  paul
- * various spelling corrections (new checksums may be needed, Karsten!)
- *
- * Revision 1.9  1999/07/12 21:05:30  keil
- * fix race in IRQ handling
- * added watchdog for lost IRQs
- *
- * Revision 1.8  1999/07/01 08:12:12  keil
- * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
- *
- * Revision 1.7  1998/11/15 23:55:26  keil
- * changes from 2.0
- *
- * Revision 1.6  1998/04/15 16:45:31  keil
- * new init code
- *
- * Revision 1.5  1998/02/02 13:40:47  keil
- * fast io
- *
- * Revision 1.4  1997/11/08 21:35:53  keil
- * new l1 init
- *
- * Revision 1.3  1997/11/06 17:09:30  keil
- * New 2.1 init code
- *
- * Revision 1.2  1997/10/29 18:55:53  keil
- * changes for 2.1.60 (irq2dev_map)
- *
- * Revision 1.1  1997/09/11 17:32:32  keil
- * new
- *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hfc_2bs0.h"
@@ -55,7 +17,7 @@
 
 extern const char *CardType[];
 
-const char *TeleInt_revision = "$Revision: 1.12 $";
+const char *TeleInt_revision = "$Revision: 1.14 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -264,11 +226,11 @@
 	byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm);	/* Reset On */
 	save_flags(flags);
 	sti();
-	current->state = TASK_UNINTERRUPTIBLE;
+	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout((30*HZ)/1000);
 	cs->hw.hfc.cirm &= ~HFC_RESET;
 	byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm);	/* Reset Off */
-	current->state = TASK_UNINTERRUPTIBLE;
+	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout((10*HZ)/1000);
 	restore_flags(flags);
 }
@@ -299,8 +261,8 @@
 	return(0);
 }
 
-__initfunc(int
-setup_TeleInt(struct IsdnCard *card))
+int __init
+setup_TeleInt(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/teles0.c linux.19p18/drivers/isdn/hisax/teles0.c
--- linux.vanilla/drivers/isdn/hisax/teles0.c	Fri Apr 21 12:46:12 2000
+++ linux.19p18/drivers/isdn/hisax/teles0.c	Mon Feb 12 15:09:50 2001
@@ -1,5 +1,5 @@
-/* $Id: teles0.c,v 2.11 1999/12/23 15:09:32 keil Exp $
-
+/* $Id: teles0.c,v 2.13 2000/11/24 17:05:38 kai Exp $
+ *
  * teles0.c     low level stuff for Teles Memory IO isdn cards
  *              based on the teles driver from Jan den Ouden
  *
@@ -9,54 +9,11 @@
  *              Fritz Elfert
  *              Beat Doebeli
  *
- * $Log: teles0.c,v $
- * Revision 2.11  1999/12/23 15:09:32  keil
- * change email
- *
- * Revision 2.10  1999/11/14 23:37:03  keil
- * new ISA memory mapped IO
- *
- * Revision 2.9  1999/07/12 21:05:31  keil
- * fix race in IRQ handling
- * added watchdog for lost IRQs
- *
- * Revision 2.8  1998/04/15 16:44:28  keil
- * new init code
- *
- * Revision 2.7  1998/03/07 22:57:08  tsbogend
- * made HiSax working on Linux/Alpha
- *
- * Revision 2.6  1998/02/03 23:27:47  keil
- * IRQ 9
- *
- * Revision 2.5  1998/02/02 13:29:47  keil
- * fast io
- *
- * Revision 2.4  1997/11/08 21:35:54  keil
- * new l1 init
- *
- * Revision 2.3  1997/11/06 17:09:31  keil
- * New 2.1 init code
- *
- * Revision 2.2  1997/10/29 18:55:57  keil
- * changes for 2.1.60 (irq2dev_map)
- *
- * Revision 2.1  1997/07/27 21:47:10  keil
- * new interface structures
- *
- * Revision 2.0  1997/06/26 11:02:43  keil
- * New Layer and card interface
- *
- * Revision 1.8  1997/04/13 19:54:04  keil
- * Change in IRQ check delay for SMP
- *
- * Revision 1.7  1997/04/06 22:54:04  keil
- * Using SKB's
- *
- * removed old log info /KKe
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isdnl1.h"
 #include "isac.h"
@@ -64,7 +21,7 @@
 
 extern const char *CardType[];
 
-const char *teles0_revision = "$Revision: 2.11 $";
+const char *teles0_revision = "$Revision: 2.13 $";
 
 #define TELES_IOMEM_SIZE	0x400
 #define byteout(addr,val) outb(val,addr)
@@ -302,8 +259,8 @@
 	return(0);
 }
 
-__initfunc(int
-setup_teles0(struct IsdnCard *card))
+int __init
+setup_teles0(struct IsdnCard *card)
 {
 	u_char val;
 	struct IsdnCardState *cs = card->cs;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/teles3.c linux.19p18/drivers/isdn/hisax/teles3.c
--- linux.vanilla/drivers/isdn/hisax/teles3.c	Fri Apr 21 12:46:12 2000
+++ linux.19p18/drivers/isdn/hisax/teles3.c	Mon Feb 12 15:09:50 2001
@@ -1,5 +1,5 @@
-/* $Id: teles3.c,v 2.15 2000/02/03 16:40:10 keil Exp $
-
+/* $Id: teles3.c,v 2.17 2000/11/24 17:05:38 kai Exp $
+ *
  * teles3.c     low level stuff for Teles 16.3 & PNP isdn cards
  *
  *              based on the teles driver from Jan den Ouden
@@ -10,91 +10,18 @@
  *              Fritz Elfert
  *              Beat Doebeli
  *
- * $Log: teles3.c,v $
- * Revision 2.15  2000/02/03 16:40:10  keil
- * Fix teles pcmcia
- *
- * Revision 2.14  1999/12/23 15:09:32  keil
- * change email
- *
- * Revision 2.13  1999/08/30 12:01:28  keil
- * HW version v1.3 support
- *
- * Revision 2.12  1999/07/12 21:05:32  keil
- * fix race in IRQ handling
- * added watchdog for lost IRQs
- *
- * Revision 2.11  1999/07/01 08:12:14  keil
- * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
- *
- * Revision 2.10  1999/02/15 14:37:15  cpetig
- * oops, missed something in last commit
- *
- * Revision 2.9  1999/02/15 14:11:02  cpetig
- * fixed a bug with Teles PCMCIA, it doesn't have a config register
- *
- * Revision 2.8  1998/04/15 16:44:30  keil
- * new init code
- *
- * Revision 2.7  1998/02/02 13:29:48  keil
- * fast io
- *
- * Revision 2.6  1997/11/13 16:22:44  keil
- * COMPAQ_ISA reset
- *
- * Revision 2.5  1997/11/12 15:01:25  keil
- * COMPAQ_ISA changes
- *
- * Revision 2.4  1997/11/08 21:35:56  keil
- * new l1 init
- *
- * Revision 2.3  1997/11/06 17:09:33  keil
- * New 2.1 init code
- *
- * Revision 2.2  1997/10/29 18:55:59  keil
- * changes for 2.1.60 (irq2dev_map)
- *
- * Revision 2.1  1997/07/27 21:47:12  keil
- * new interface structures
- *
- * Revision 2.0  1997/06/26 11:02:46  keil
- * New Layer and card interface
- *
- * Revision 1.11  1997/04/13 19:54:05  keil
- * Change in IRQ check delay for SMP
- *
- * Revision 1.10  1997/04/06 22:54:05  keil
- * Using SKB's
- *
- * Revision 1.9  1997/03/22 02:01:07  fritz
- * -Reworked toplevel Makefile. From now on, no different Makefiles
- *  for standalone- and in-kernel-compilation are needed any more.
- * -Added local Rules.make for above reason.
- * -Experimental changes in teles3.c for enhanced IRQ-checking with
- *  2.1.X and SMP kernels.
- * -Removed diffstd-script, same functionality is in stddiff -r.
- * -Enhanced scripts std2kern and stddiff.
- *
- * Revision 1.8  1997/02/23 18:43:55  fritz
- * Added support for Teles-Vision.
- *
- * Revision 1.7  1997/01/28 22:48:33  keil
- * fixes for Teles PCMCIA (Christof Petig)
- *
- * Revision 1.6  1997/01/27 15:52:55  keil
- * SMP proof,cosmetics, PCMCIA added
- *
- * removed old log info /KKe
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 #define __NO_VERSION__
+#include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
 #include "isdnl1.h"
 
 extern const char *CardType[];
-const char *teles3_revision = "$Revision: 2.15 $";
+const char *teles3_revision = "$Revision: 2.17 $";
 
 #define byteout(addr,val) outb(val,addr)
 #define bytein(addr) inb(addr)
@@ -327,8 +254,8 @@
 	return(0);
 }
 
-__initfunc(int
-setup_teles3(struct IsdnCard *card))
+int 
+setup_teles3(struct IsdnCard *card)
 {
 	u_char val;
 	struct IsdnCardState *cs = card->cs;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/telespci.c linux.19p18/drivers/isdn/hisax/telespci.c
--- linux.vanilla/drivers/isdn/hisax/telespci.c	Fri Apr 21 12:46:12 2000
+++ linux.19p18/drivers/isdn/hisax/telespci.c	Tue Feb 13 18:50:48 2001
@@ -1,56 +1,25 @@
-/* $Id: telespci.c,v 2.11 1999/12/23 15:09:32 keil Exp $
-
+/* $Id: telespci.c,v 2.16.6.3 2001/02/13 10:33:58 kai Exp $
+ *
  * telespci.c     low level stuff for Teles PCI isdn cards
  *
  * Author       Ton van Rosmalen 
  *              Karsten Keil (keil@isdn4linux.de)
  *
- *
- * $Log: telespci.c,v $
- * Revision 2.11  1999/12/23 15:09:32  keil
- * change email
- *
- * Revision 2.10  1999/11/15 14:20:05  keil
- * 64Bit compatibility
- *
- * Revision 2.9  1999/08/11 21:01:34  keil
- * new PCI codefix
- *
- * Revision 2.8  1999/08/10 16:02:10  calle
- * struct pci_dev changed in 2.3.13. Made the necessary changes.
- *
- * Revision 2.7  1999/07/12 21:05:34  keil
- * fix race in IRQ handling
- * added watchdog for lost IRQs
- *
- * Revision 2.6  1999/07/01 08:12:15  keil
- * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel
- *
- * Revision 2.5  1998/11/15 23:55:28  keil
- * changes from 2.0
- *
- * Revision 2.4  1998/10/05 09:38:08  keil
- * Fix register addressing
- *
- * Revision 2.3  1998/05/25 12:58:26  keil
- * HiSax golden code from certification, Don't use !!!
- * No leased lines, no X75, but many changes.
- *
- * Revision 2.1  1998/04/15 16:38:23  keil
- * Add S0Box and Teles PCI support
- *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 #define __NO_VERSION__
+#include <linux/init.h>
 #include <linux/config.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
 #include "isdnl1.h"
 #include <linux/pci.h>
+#include <linux/isdn_compat.h>
 
 extern const char *CardType[];
-const char *telespci_revision = "$Revision: 2.11 $";
+const char *telespci_revision = "$Revision: 2.16.6.3 $";
 
 #define ZORAN_PO_RQ_PEN	0x02000000
 #define ZORAN_PO_WR	0x00800000
@@ -307,14 +276,17 @@
 	return(0);
 }
 
-static 	struct pci_dev *dev_tel __initdata = NULL;
+static struct pci_dev *dev_tel __initdata = NULL;
 
-__initfunc(int
-setup_telespci(struct IsdnCard *card))
+int __init
+setup_telespci(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
 
+#ifdef __BIG_ENDIAN
+#error "not running on big endian machines now"
+#endif
 	strcpy(tmp, telespci_revision);
 	printk(KERN_INFO "HiSax: Teles/PCI driver Rev. %s\n", HiSax_getrev(tmp));
 	if (cs->typ != ISDN_CTYPE_TELESPCI)
@@ -324,16 +296,18 @@
 		printk(KERN_ERR "TelesPCI: no PCI bus present\n");
 		return(0);
 	}
-	if ((dev_tel = pci_find_device (0x11DE, 0x6120, dev_tel))) {
+	if ((dev_tel = pci_find_device (PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_tel))) {
+		if (pci_enable_device(dev_tel))
+			return(0);
 		cs->irq = dev_tel->irq;
 		if (!cs->irq) {
 			printk(KERN_WARNING "Teles: No IRQ for PCI card found\n");
 			return(0);
 		}
-		cs->hw.teles0.membase = (u_long) ioremap(dev_tel->base_address[ 0],
+		cs->hw.teles0.membase = (u_long) ioremap(dev_tel->base_address[ 0] & PCI_BASE_ADDRESS_MEM_MASK,
 			PAGE_SIZE);
 		printk(KERN_INFO "Found: Zoran, base-address: 0x%lx, irq: 0x%x\n",
-			dev_tel->base_address[ 0], dev_tel->irq);
+			dev_tel->base_address[ 0] & PCI_BASE_ADDRESS_MEM_MASK, dev_tel->irq);
 	} else {
 		printk(KERN_WARNING "TelesPCI: No PCI card found\n");
 		return(0);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/w6692.c linux.19p18/drivers/isdn/hisax/w6692.c
--- linux.vanilla/drivers/isdn/hisax/w6692.c	Sun Jun 11 21:44:14 2000
+++ linux.19p18/drivers/isdn/hisax/w6692.c	Tue Feb 13 18:50:48 2001
@@ -1,5 +1,5 @@
-/* $Id: w6692.c,v 1.4 2000/03/16 23:24:11 werner Exp $
-
+/* $Id: w6692.c,v 1.12.6.3 2001/02/13 10:33:58 kai Exp $
+ *
  * w6692.c   Winbond W6692 specific routines
  *
  * Author       Petr Novak <petr.novak@i.cz>
@@ -7,39 +7,17 @@
  *
  *              This file is (c) under GNU PUBLIC LICENSE
  *
- * $Log: w6692.c,v $
- * Revision 1.4  2000/03/16 23:24:11  werner
- *
- * Fixed an additional location
- *
- * Revision 1.3  2000/03/16 22:41:36  werner
- *
- * Tried to fix second B-channel problem (still not tested)
- *
- * Revision 1.2  2000/02/26 00:35:13  keil
- * Fix skb freeing in interrupt context
- *
- * Revision 1.1  1999/09/04 06:28:58  keil
- * first revision
- *
- *
- *
  */
 
 #include <linux/config.h>
+#include <linux/init.h>
 #define __NO_VERSION__
 #include "hisax.h"
 #include "w6692.h"
 #include "isdnl1.h"
 #include <linux/interrupt.h>
 #include <linux/pci.h>
-
-#define	PCI_VEND_ASUSCOM	0x675
-#define	PCI_DEV_ASUSCOMPCI1	0x1702
-#ifndef PCI_VENDOR_ID_WINBOND2
-#define PCI_VENDOR_ID_WINBOND2	0x1050
-#endif
-#define	PCI_DEVICE_W6692	0x6692
+#include <linux/isdn_compat.h>
 
 /* table entry in the PCI devices list */
 typedef struct {
@@ -51,18 +29,18 @@
 
 static const PCI_ENTRY id_list[] =
 {
-	{PCI_VEND_ASUSCOM, PCI_DEV_ASUSCOMPCI1, "AsusCom", "TA XXX"},
-	{PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_W6692, "Winbond", "W6692"},
+	{PCI_VENDOR_ID_DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH, "Dynalink/AsusCom", "IS64PH"},
+	{PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692, "Winbond", "W6692"},
 	{0, 0, NULL, NULL}
 };
 
 extern const char *CardType[];
 
-const char *w6692_revision = "$Revision: 1.4 $";
+const char *w6692_revision = "$Revision: 1.12.6.3 $";
 
 #define DBUSY_TIMER_VALUE 80
 
-static char *W6692Ver[] HISAX_INITDATA =
+static char *W6692Ver[] __initdata =
 {"W6692 V00", "W6692 V01", "W6692 V10",
  "W6692 V11"};
 
@@ -256,7 +234,7 @@
 	if (bcs->hw.w6692.rcvidx + count > HSCX_BUFMAX) {
 		if (cs->debug & L1_DEB_WARN)
 			debugl1(cs, "W6692B_empty_fifo: incoming packet too large");
-		cs->BC_Write_Reg(cs, bcs->hw.w6692.bchan, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
+		cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
 		bcs->hw.w6692.rcvidx = 0;
 		return;
 	}
@@ -264,14 +242,14 @@
 	bcs->hw.w6692.rcvidx += count;
 	save_flags(flags);
 	cli();
-	READW6692BFIFO(cs, bcs->hw.w6692.bchan, ptr, count);
-	cs->BC_Write_Reg(cs, bcs->hw.w6692.bchan, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
+	READW6692BFIFO(cs, bcs->channel, ptr, count);
+	cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT);
 	restore_flags(flags);
 	if (cs->debug & L1_DEB_HSCX_FIFO) {
 		char *t = bcs->blog;
 
 		t += sprintf(t, "W6692B_empty_fifo %c cnt %d",
-			     bcs->hw.w6692.bchan ? 'B' : 'A', count);
+			     bcs->channel + '1', count);
 		QuickHex(t, ptr, count);
 		debugl1(cs, bcs->blog);
 	}
@@ -307,14 +285,14 @@
 	skb_pull(bcs->tx_skb, count);
 	bcs->tx_cnt -= count;
 	bcs->hw.w6692.count += count;
-	WRITEW6692BFIFO(cs, bcs->hw.w6692.bchan, ptr, count);
-	cs->BC_Write_Reg(cs, bcs->hw.w6692.bchan, W_B_CMDR, W_B_CMDR_RACT | W_B_CMDR_XMS | (more ? 0 : W_B_CMDR_XME));
+	WRITEW6692BFIFO(cs, bcs->channel, ptr, count);
+	cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACT | W_B_CMDR_XMS | (more ? 0 : W_B_CMDR_XME));
 	restore_flags(flags);
 	if (cs->debug & L1_DEB_HSCX_FIFO) {
 		char *t = bcs->blog;
 
 		t += sprintf(t, "W6692B_fill_fifo %c cnt %d",
-			     bcs->hw.w6692.bchan ? 'B' : 'A', count);
+			     bcs->channel + '1', count);
 		QuickHex(t, ptr, count);
 		debugl1(cs, bcs->blog);
 	}
@@ -325,13 +303,11 @@
 {
 	u_char val;
 	u_char r;
-	struct BCState *bcs = cs->bcs;
+	struct BCState *bcs;
 	struct sk_buff *skb;
 	int count;
 
-	if (bcs->channel != bchan)
-	  bcs++; /* hardware bchan must match ! */
-
+	bcs = (cs->bcs->channel == bchan) ? cs->bcs : (cs->bcs+1);
 	val = cs->BC_Read_Reg(cs, bchan, W_B_EXIR);
 	debugl1(cs, "W6692B chan %d B_EXIR 0x%02X", bchan, val);
 
@@ -418,7 +394,7 @@
 				bcs->tx_cnt += bcs->hw.w6692.count;
 				bcs->hw.w6692.count = 0;
 			}
-			cs->BC_Write_Reg(cs, bcs->hw.w6692.bchan, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT);
+			cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT);
 			if (cs->debug & L1_DEB_WARN)
 				debugl1(cs, "W6692 B EXIR %x Lost TX", val);
 		}
@@ -732,18 +708,16 @@
 }
 
 static void
-W6692Bmode(struct BCState *bcs, int mode, int bc)
+W6692Bmode(struct BCState *bcs, int mode, int bchan)
 {
 	struct IsdnCardState *cs = bcs->cs;
-	int bchan = bc;
-
-	bcs->hw.w6692.bchan = bc;
 
 	if (cs->debug & L1_DEB_HSCX)
 		debugl1(cs, "w6692 %c mode %d ichan %d",
-			'1' + bchan, mode, bc);
+			'1' + bchan, mode, bchan);
 	bcs->mode = mode;
-	bcs->channel = bc;
+	bcs->channel = bchan;
+	bcs->hw.w6692.bchan = bchan;
 
 	switch (mode) {
 		case (L1_MODE_NULL):
@@ -885,7 +859,7 @@
 	return (0);
 }
 
-HISAX_INITFUNC(void initW6692(struct IsdnCardState *cs, int part))
+void __init initW6692(struct IsdnCardState *cs, int part)
 {
 	if (part & 1) {
 		cs->tqueue.routine = (void *) (void *) W6692_bh;
@@ -912,8 +886,6 @@
 		cs->bcs[1].BC_SetStack = setstack_w6692;
 		cs->bcs[0].BC_Close = close_w6692state;
 		cs->bcs[1].BC_Close = close_w6692state;
-		cs->bcs[0].hw.w6692.bchan = 0;
-		cs->bcs[1].hw.w6692.bchan = 1;
 		W6692Bmode(cs->bcs, 0, 0);
 		W6692Bmode(cs->bcs + 1, 0, 0);
 	}
@@ -984,11 +956,12 @@
 	return (0);
 }
 
-static int id_idx = 0;
+static int id_idx ;
 
 static struct pci_dev *dev_w6692 __initdata = NULL;
 
-__initfunc(int setup_w6692(struct IsdnCard *card))
+int __init 
+setup_w6692(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
@@ -996,6 +969,9 @@
 	u_char pci_irq = 0;
 	u_int pci_ioaddr = 0;
 
+#ifdef __BIG_ENDIAN
+#error "not running on big endian machines now"
+#endif
 	strcpy(tmp, w6692_revision);
 	printk(KERN_INFO "HiSax: W6692 driver Rev. %s\n", HiSax_getrev(tmp));
 	if (cs->typ != ISDN_CTYPE_W6692)
@@ -1009,8 +985,11 @@
 		dev_w6692 = pci_find_device(id_list[id_idx].vendor_id,
 					    id_list[id_idx].device_id,
 					    dev_w6692);
-		if (dev_w6692)
+		if (dev_w6692) {
+			if (pci_enable_device(dev_w6692))
+				continue;
 			break;
+		}
 		id_idx++;
 	}
 	if (dev_w6692) {
@@ -1018,7 +997,7 @@
 		pci_irq = dev_w6692->irq;
 		/* I think address 0 is allways the configuration area */
 		/* and address 1 is the real IO space KKe 03.09.99 */
-		pci_ioaddr = dev_w6692->base_address[ 1];
+		pci_ioaddr = dev_w6692->base_address[ 1] & PCI_BASE_ADDRESS_IO_MASK;
 	}
 	if (!found) {
 		printk(KERN_WARNING "W6692: No PCI card found\n");
@@ -1029,7 +1008,6 @@
 		printk(KERN_WARNING "W6692: No IRQ for PCI card found\n");
 		return (0);
 	}
-	pci_ioaddr &= PCI_BASE_ADDRESS_IO_MASK;
 	if (!pci_ioaddr) {
 		printk(KERN_WARNING "W6692: NO I/O Base Address found\n");
 		return (0);
@@ -1069,6 +1047,7 @@
 	cs->BC_Send_Data = &W6692B_fill_fifo;
 	cs->cardmsg = &w6692_card_msg;
 	cs->irq_func = &W6692_interrupt;
+	cs->irq_flags |= SA_SHIRQ;
 	W6692Version(cs, "W6692:");
 	printk(KERN_INFO "W6692 ISTA=0x%X\n", ReadW6692(cs, W_ISTA));
 	printk(KERN_INFO "W6692 IMASK=0x%X\n", ReadW6692(cs, W_IMASK));
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hisax/w6692.h linux.19p18/drivers/isdn/hisax/w6692.h
--- linux.vanilla/drivers/isdn/hisax/w6692.h	Fri Apr 21 12:46:12 2000
+++ linux.19p18/drivers/isdn/hisax/w6692.h	Wed Dec 13 22:08:26 2000
@@ -1,18 +1,10 @@
-/* $Id: w6692.h,v 1.1 1999/09/04 06:28:58 keil Exp $
-
+/* $Id: w6692.h,v 1.2 2000/06/26 08:59:15 keil Exp $
+ *
  * w6692.h   Winbond W6692 specific defines
  *
  * Author       Petr Novak <petr.novak@i.cz>
  *
- *
- * $Log: w6692.h,v $
- * Revision 1.1  1999/09/04 06:28:58  keil
- * first revision
- *
- *
- * Revision 1.0  1999/08/28 21:58:00 pnovak
- * first version
- *
+ * This file is (c) under GNU PUBLIC LICENSE
  *
  */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hysdn/Makefile linux.19p18/drivers/isdn/hysdn/Makefile
--- linux.vanilla/drivers/isdn/hysdn/Makefile	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/hysdn/Makefile	Tue Feb 13 18:49:43 2001
@@ -0,0 +1,29 @@
+# Makefile for the hysdn ISDN device driver
+
+# The target object and module list name.
+
+O_TARGET	:= vmlinux-obj.o
+
+# Multipart objects.
+
+list-multi	:= hysdn.o
+hysdn-objs	:= hysdn_procconf.o hysdn_proclog.o boardergo.o hysdn_boot.o \
+		   hysdn_sched.o hysdn_net.o hysdn_init.o
+
+# Optional parts of multipart objects.
+
+hysdn-objs-$(CONFIG_HYSDN_CAPI) += hycapi.o
+
+hysdn-objs 	+= $(hysdn-objs-y)
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_HYSDN)	+= hysdn.o
+
+include $(TOPDIR)/drivers/isdn/Rules.make
+
+# Link rules for multi-part drivers.
+
+hysdn.o: $(hysdn-objs)
+	$(LD) -r -o $@ $(hysdn-objs)
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hysdn/boardergo.c linux.19p18/drivers/isdn/hysdn/boardergo.c
--- linux.vanilla/drivers/isdn/hysdn/boardergo.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/hysdn/boardergo.c	Tue Feb 13 18:49:43 2001
@@ -0,0 +1,466 @@
+/* $Id: boardergo.c,v 1.5.6.1 2000/12/10 22:01:04 kai Exp $
+
+ * Linux driver for HYSDN cards, specific routines for ergo type boards.
+ *
+ * As all Linux supported cards Champ2, Ergo and Metro2/4 use the same
+ * DPRAM interface and layout with only minor differences all related
+ * stuff is done here, not in separate modules.
+ *
+ * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
+ *
+ * Copyright 1999  by Werner Cornelius (werner@titro.de)
+ *
+ * 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, 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.
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <asm/io.h>
+#include <linux/signal.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+
+#include "hysdn_defs.h"
+#include "boardergo.h"
+
+#define byteout(addr,val) outb(val,addr)
+#define bytein(addr) inb(addr)
+
+/***************************************************/
+/* The cards interrupt handler. Called from system */
+/***************************************************/
+static void
+ergo_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+	hysdn_card *card = dev_id;	/* parameter from irq */
+	tErgDpram *dpr;
+	ulong flags;
+	uchar volatile b;
+
+	if (!card)
+		return;		/* error -> spurious interrupt */
+	if (!card->irq_enabled)
+		return;		/* other device interrupting or irq switched off */
+
+	save_flags(flags);
+	cli();			/* no further irqs allowed */
+
+	if (!(bytein(card->iobase + PCI9050_INTR_REG) & PCI9050_INTR_REG_STAT1)) {
+		restore_flags(flags);	/* restore old state */
+		return;		/* no interrupt requested by E1 */
+	}
+	/* clear any pending ints on the board */
+	dpr = card->dpram;
+	b = dpr->ToPcInt;	/* clear for ergo */
+	b |= dpr->ToPcIntMetro;	/* same for metro */
+	b |= dpr->ToHyInt;	/* and for champ */
+
+	/* start kernel task immediately after leaving all interrupts */
+	if (!card->hw_lock) {
+		queue_task(&card->irq_queue, &tq_immediate);
+		mark_bh(IMMEDIATE_BH);
+	}
+	restore_flags(flags);
+}				/* ergo_interrupt */
+
+/******************************************************************************/
+/* ergo_irq_bh is the function called by the immediate kernel task list after */
+/* being activated with queue_task and no interrupts active. This task is the */
+/* only one handling data transfer from or to the card after booting. The task */
+/* may be queued from everywhere (interrupts included).                       */
+/******************************************************************************/
+static void
+ergo_irq_bh(hysdn_card * card)
+{
+	tErgDpram *dpr;
+	int again;
+	ulong flags;
+
+	if (card->state != CARD_STATE_RUN)
+		return;		/* invalid call */
+
+	dpr = card->dpram;	/* point to DPRAM */
+
+	save_flags(flags);
+	cli();
+	if (card->hw_lock) {
+		restore_flags(flags);	/* hardware currently unavailable */
+		return;
+	}
+	card->hw_lock = 1;	/* we now lock the hardware */
+
+	do {
+		sti();		/* reenable other ints */
+		again = 0;	/* assume loop not to be repeated */
+
+		if (!dpr->ToHyFlag) {
+			/* we are able to send a buffer */
+
+			if (hysdn_sched_tx(card, dpr->ToHyBuf, &dpr->ToHySize, &dpr->ToHyChannel,
+					   ERG_TO_HY_BUF_SIZE)) {
+				dpr->ToHyFlag = 1;	/* enable tx */
+				again = 1;	/* restart loop */
+			}
+		}		/* we are able to send a buffer */
+		if (dpr->ToPcFlag) {
+			/* a message has arrived for us, handle it */
+
+			if (hysdn_sched_rx(card, dpr->ToPcBuf, dpr->ToPcSize, dpr->ToPcChannel)) {
+				dpr->ToPcFlag = 0;	/* we worked the data */
+				again = 1;	/* restart loop */
+			}
+		}		/* a message has arrived for us */
+		cli();		/* no further ints */
+		if (again) {
+			dpr->ToHyInt = 1;
+			dpr->ToPcInt = 1;	/* interrupt to E1 for all cards */
+		} else
+			card->hw_lock = 0;	/* free hardware again */
+	} while (again);	/* until nothing more to do */
+
+	restore_flags(flags);
+}				/* ergo_irq_bh */
+
+
+/*********************************************************/
+/* stop the card (hardware reset) and disable interrupts */
+/*********************************************************/
+static void
+ergo_stopcard(hysdn_card * card)
+{
+	ulong flags;
+	uchar val;
+
+	hysdn_net_release(card);	/* first release the net device if existing */
+#ifdef CONFIG_HYSDN_CAPI
+	hycapi_capi_stop(card);
+#endif /* CONFIG_HYSDN_CAPI */
+	save_flags(flags);
+	cli();
+	val = bytein(card->iobase + PCI9050_INTR_REG);	/* get actual value */
+	val &= ~(PCI9050_INTR_REG_ENPCI | PCI9050_INTR_REG_EN1);	/* mask irq */
+	byteout(card->iobase + PCI9050_INTR_REG, val);
+	card->irq_enabled = 0;
+	byteout(card->iobase + PCI9050_USER_IO, PCI9050_E1_RESET);	/* reset E1 processor */
+	card->state = CARD_STATE_UNUSED;
+	card->err_log_state = ERRLOG_STATE_OFF;		/* currently no log active */
+
+	restore_flags(flags);
+}				/* ergo_stopcard */
+
+/**************************************************************************/
+/* enable or disable the cards error log. The event is queued if possible */
+/**************************************************************************/
+static void
+ergo_set_errlog_state(hysdn_card * card, int on)
+{
+	ulong flags;
+
+	if (card->state != CARD_STATE_RUN) {
+		card->err_log_state = ERRLOG_STATE_OFF;		/* must be off */
+		return;
+	}
+	save_flags(flags);
+	cli();
+
+	if (((card->err_log_state == ERRLOG_STATE_OFF) && !on) ||
+	    ((card->err_log_state == ERRLOG_STATE_ON) && on)) {
+		restore_flags(flags);
+		return;		/* nothing to do */
+	}
+	if (on)
+		card->err_log_state = ERRLOG_STATE_START;	/* request start */
+	else
+		card->err_log_state = ERRLOG_STATE_STOP;	/* request stop */
+
+	restore_flags(flags);
+	queue_task(&card->irq_queue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+}				/* ergo_set_errlog_state */
+
+/******************************************/
+/* test the cards RAM and return 0 if ok. */
+/******************************************/
+static const char TestText[36] = "This Message is filler, why read it";
+
+static int
+ergo_testram(hysdn_card * card)
+{
+	tErgDpram *dpr = card->dpram;
+
+	memset(dpr->TrapTable, 0, sizeof(dpr->TrapTable));	/* clear all Traps */
+	dpr->ToHyInt = 1;	/* E1 INTR state forced */
+
+	memcpy(&dpr->ToHyBuf[ERG_TO_HY_BUF_SIZE - sizeof(TestText)], TestText,
+	       sizeof(TestText));
+	if (memcmp(&dpr->ToHyBuf[ERG_TO_HY_BUF_SIZE - sizeof(TestText)], TestText,
+		   sizeof(TestText)))
+		return (-1);
+
+	memcpy(&dpr->ToPcBuf[ERG_TO_PC_BUF_SIZE - sizeof(TestText)], TestText,
+	       sizeof(TestText));
+	if (memcmp(&dpr->ToPcBuf[ERG_TO_PC_BUF_SIZE - sizeof(TestText)], TestText,
+		   sizeof(TestText)))
+		return (-1);
+
+	return (0);
+}				/* ergo_testram */
+
+/*****************************************************************************/
+/* this function is intended to write stage 1 boot image to the cards buffer */
+/* this is done in two steps. First the 1024 hi-words are written (offs=0),  */
+/* then the 1024 lo-bytes are written. The remaining DPRAM is cleared, the   */
+/* PCI-write-buffers flushed and the card is taken out of reset.             */
+/* The function then waits for a reaction of the E1 processor or a timeout.  */
+/* Negative return values are interpreted as errors.                         */
+/*****************************************************************************/
+static int
+ergo_writebootimg(struct HYSDN_CARD *card, uchar * buf, ulong offs)
+{
+	uchar *dst;
+	tErgDpram *dpram;
+	int cnt = (BOOT_IMG_SIZE >> 2);		/* number of words to move and swap (byte order!) */
+	
+	if (card->debug_flags & LOG_POF_CARD)
+		hysdn_addlog(card, "ERGO: write bootldr offs=0x%lx ", offs);
+
+	dst = card->dpram;	/* pointer to start of DPRAM */
+	dst += (offs + ERG_DPRAM_FILL_SIZE);	/* offset in the DPRAM */
+	while (cnt--) {
+		*dst++ = *(buf + 1);	/* high byte */
+		*dst++ = *buf;	/* low byte */
+		dst += 2;	/* point to next longword */
+		buf += 2;	/* buffer only filled with words */
+	}
+
+	/* if low words (offs = 2) have been written, clear the rest of the DPRAM, */
+	/* flush the PCI-write-buffer and take the E1 out of reset */
+	if (offs) {
+		memset(card->dpram, 0, ERG_DPRAM_FILL_SIZE);	/* fill the DPRAM still not cleared */
+		dpram = card->dpram;	/* get pointer to dpram structure */
+		dpram->ToHyNoDpramErrLog = 0xFF;	/* write a dpram register */
+		while (!dpram->ToHyNoDpramErrLog);	/* reread volatile register to flush PCI */
+
+		byteout(card->iobase + PCI9050_USER_IO, PCI9050_E1_RUN);	/* start E1 processor */
+		/* the interrupts are still masked */
+
+		sti();
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout((20 * HZ) / 1000);	/* Timeout 20ms */
+
+		if (((tDpramBootSpooler *) card->dpram)->Len != DPRAM_SPOOLER_DATA_SIZE) {
+			if (card->debug_flags & LOG_POF_CARD)
+				hysdn_addlog(card, "ERGO: write bootldr no answer");
+			return (-ERR_BOOTIMG_FAIL);
+		}
+	}			/* start_boot_img */
+	return (0);		/* successfull */
+}				/* ergo_writebootimg */
+
+/********************************************************************************/
+/* ergo_writebootseq writes the buffer containing len bytes to the E1 processor */
+/* using the boot spool mechanism. If everything works fine 0 is returned. In   */
+/* case of errors a negative error value is returned.                           */
+/********************************************************************************/
+static int
+ergo_writebootseq(struct HYSDN_CARD *card, uchar * buf, int len)
+{
+	tDpramBootSpooler *sp = (tDpramBootSpooler *) card->dpram;
+	uchar *dst;
+	uchar buflen;
+	int nr_write;
+	uchar tmp_rdptr;
+	uchar wr_mirror;
+	int i;
+
+	if (card->debug_flags & LOG_POF_CARD)
+		hysdn_addlog(card, "ERGO: write boot seq len=%d ", len);
+
+	dst = sp->Data;		/* point to data in spool structure */
+	buflen = sp->Len;	/* maximum len of spooled data */
+	wr_mirror = sp->WrPtr;	/* only once read */
+	sti();
+
+	/* try until all bytes written or error */
+	i = 0x1000;		/* timeout value */
+	while (len) {
+
+		/* first determine the number of bytes that may be buffered */
+		do {
+			tmp_rdptr = sp->RdPtr;	/* first read the pointer */
+			i--;	/* decrement timeout */
+		} while (i && (tmp_rdptr != sp->RdPtr));	/* wait for stable pointer */
+
+		if (!i) {
+			if (card->debug_flags & LOG_POF_CARD)
+				hysdn_addlog(card, "ERGO: write boot seq timeout");
+			return (-ERR_BOOTSEQ_FAIL);	/* value not stable -> timeout */
+		}
+		if ((nr_write = tmp_rdptr - wr_mirror - 1) < 0)
+			nr_write += buflen;	/* now we got number of free bytes - 1 in buffer */
+
+		if (!nr_write)
+			continue;	/* no free bytes in buffer */
+
+		if (nr_write > len)
+			nr_write = len;		/* limit if last few bytes */
+		i = 0x1000;	/* reset timeout value */
+
+		/* now we know how much bytes we may put in the puffer */
+		len -= nr_write;	/* we savely could adjust len before output */
+		while (nr_write--) {
+			*(dst + wr_mirror) = *buf++;	/* output one byte */
+			if (++wr_mirror >= buflen)
+				wr_mirror = 0;
+			sp->WrPtr = wr_mirror;	/* announce the next byte to E1 */
+		}		/* while (nr_write) */
+
+	}			/* while (len) */
+	return (0);
+}				/* ergo_writebootseq */
+
+/***********************************************************************************/
+/* ergo_waitpofready waits for a maximum of 10 seconds for the completition of the */
+/* boot process. If the process has been successfull 0 is returned otherwise a     */
+/* negative error code is returned.                                                */
+/***********************************************************************************/
+static int
+ergo_waitpofready(struct HYSDN_CARD *card)
+{
+	tErgDpram *dpr = card->dpram;	/* pointer to DPRAM structure */
+	int timecnt = 10000 / 50;	/* timeout is 10 secs max. */
+	ulong flags;
+	int msg_size;
+	int i;
+
+	if (card->debug_flags & LOG_POF_CARD)
+		hysdn_addlog(card, "ERGO: waiting for pof ready");
+	while (timecnt--) {
+		/* wait until timeout  */
+
+		if (dpr->ToPcFlag) {
+			/* data has arrived */
+
+			if ((dpr->ToPcChannel != CHAN_SYSTEM) ||
+			    (dpr->ToPcSize < MIN_RDY_MSG_SIZE) ||
+			    (dpr->ToPcSize > MAX_RDY_MSG_SIZE) ||
+			    ((*(ulong *) dpr->ToPcBuf) != RDY_MAGIC))
+				break;	/* an error occured */
+
+			/* Check for additional data delivered during SysReady */
+			msg_size = dpr->ToPcSize - RDY_MAGIC_SIZE;
+			if (msg_size > 0)
+				if (EvalSysrTokData(card, dpr->ToPcBuf + RDY_MAGIC_SIZE, msg_size))
+					break;
+
+			if (card->debug_flags & LOG_POF_RECORD)
+				hysdn_addlog(card, "ERGO: pof boot success");
+			save_flags(flags);
+			cli();
+
+			card->state = CARD_STATE_RUN;	/* now card is running */
+			/* enable the cards interrupt */
+			byteout(card->iobase + PCI9050_INTR_REG,
+				bytein(card->iobase + PCI9050_INTR_REG) |
+			(PCI9050_INTR_REG_ENPCI | PCI9050_INTR_REG_EN1));
+			card->irq_enabled = 1;	/* we are ready to receive interrupts */
+
+			dpr->ToPcFlag = 0;	/* reset data indicator */
+			dpr->ToHyInt = 1;
+			dpr->ToPcInt = 1;	/* interrupt to E1 for all cards */
+
+			restore_flags(flags);
+			if ((i = hysdn_net_create(card))) {
+				ergo_stopcard(card);
+				card->state = CARD_STATE_BOOTERR;
+				return (i);
+			}
+#ifdef CONFIG_HYSDN_CAPI
+			if((i = hycapi_capi_create(card))) {
+				printk(KERN_WARNING "HYSDN: failed to create capi-interface.\n");
+			}
+#endif /* CONFIG_HYSDN_CAPI */
+			return (0);	/* success */
+		}		/* data has arrived */
+		sti();
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout((50 * HZ) / 1000);	/* Timeout 50ms */
+	}			/* wait until timeout */
+
+	if (card->debug_flags & LOG_POF_CARD)
+		hysdn_addlog(card, "ERGO: pof boot ready timeout");
+	return (-ERR_POF_TIMEOUT);
+}				/* ergo_waitpofready */
+
+
+
+/************************************************************************************/
+/* release the cards hardware. Before releasing do a interrupt disable and hardware */
+/* reset. Also unmap dpram.                                                         */
+/* Use only during module release.                                                  */
+/************************************************************************************/
+static void
+ergo_releasehardware(hysdn_card * card)
+{
+	ergo_stopcard(card);	/* first stop the card if not already done */
+	free_irq(card->irq, card);	/* release interrupt */
+	release_region(card->iobase + PCI9050_INTR_REG, 1);	/* release all io ports */
+	release_region(card->iobase + PCI9050_USER_IO, 1);
+	vfree(card->dpram);
+	card->dpram = NULL;	/* release shared mem */
+}				/* ergo_releasehardware */
+
+
+/*********************************************************************************/
+/* acquire the needed hardware ports and map dpram. If an error occurs a nonzero */
+/* value is returned.                                                            */
+/* Use only during module init.                                                  */
+/*********************************************************************************/
+int
+ergo_inithardware(hysdn_card * card)
+{
+	if (check_region(card->iobase + PCI9050_INTR_REG, 1) ||
+	    check_region(card->iobase + PCI9050_USER_IO, 1))
+		return (-1);	/* ports already in use */
+
+	card->memend = card->membase + ERG_DPRAM_PAGE_SIZE - 1;
+	if (!(card->dpram = ioremap(card->membase, ERG_DPRAM_PAGE_SIZE)))
+		return (-1);
+
+	request_region(card->iobase + PCI9050_INTR_REG, 1, "HYSDN");
+	request_region(card->iobase + PCI9050_USER_IO, 1, "HYSDN");
+	ergo_stopcard(card);	/* disable interrupts */
+	if (request_irq(card->irq, ergo_interrupt, SA_SHIRQ, "HYSDN", card)) {
+		ergo_releasehardware(card); /* return the acquired hardware */
+		return (-1);
+	}
+	/* success, now setup the function pointers */
+	card->stopcard = ergo_stopcard;
+	card->releasehardware = ergo_releasehardware;
+	card->testram = ergo_testram;
+	card->writebootimg = ergo_writebootimg;
+	card->writebootseq = ergo_writebootseq;
+	card->waitpofready = ergo_waitpofready;
+	card->set_errlog_state = ergo_set_errlog_state;
+	card->irq_queue.sync = 0;
+	card->irq_queue.data = card;	/* init task queue for interrupt */
+	card->irq_queue.routine = (void *) (void *) ergo_irq_bh;
+
+	return (0);
+}				/* ergo_inithardware */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hysdn/boardergo.h linux.19p18/drivers/isdn/hysdn/boardergo.h
--- linux.vanilla/drivers/isdn/hysdn/boardergo.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/hysdn/boardergo.h	Sat Mar  3 23:00:26 2001
@@ -0,0 +1,112 @@
+/* $Id: boardergo.h,v 1.2 2000/11/13 22:51:47 kai Exp $
+
+ * Linux driver for HYSDN cards, definitions for ergo type boards (buffers..).
+ * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
+ *
+ * Copyright 1999  by Werner Cornelius (werner@titro.de)
+ *
+ * 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, 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.
+ *
+ */
+
+#include <linux/isdn_compat.h>
+
+/************************************************/
+/* defines for the dual port memory of the card */
+/************************************************/
+#define ERG_DPRAM_PAGE_SIZE 0x2000	/* DPRAM occupies a 8K page */
+#define BOOT_IMG_SIZE 4096
+#define ERG_DPRAM_FILL_SIZE (ERG_DPRAM_PAGE_SIZE - BOOT_IMG_SIZE)
+
+#define ERG_TO_HY_BUF_SIZE  0x0E00	/* 3072 bytes buffer size to card */
+#define ERG_TO_PC_BUF_SIZE  0x0E00	/* 3072 bytes to PC, too */
+
+/* following DPRAM layout copied from OS2-driver boarderg.h */
+typedef struct ErgDpram_tag {
+/*0000 */ uchar ToHyBuf[ERG_TO_HY_BUF_SIZE];
+/*0E00 */ uchar ToPcBuf[ERG_TO_PC_BUF_SIZE];
+
+	/*1C00 */ uchar bSoftUart[SIZE_RSV_SOFT_UART];
+	/* size 0x1B0 */
+
+	/*1DB0 *//* tErrLogEntry */ uchar volatile ErrLogMsg[64];
+	/* size 64 bytes */
+	/*1DB0  ulong ulErrType;               */
+	/*1DB4  ulong ulErrSubtype;            */
+	/*1DB8  ulong ucTextSize;              */
+	/*1DB9  ulong ucText[ERRLOG_TEXT_SIZE]; *//* ASCIIZ of len ucTextSize-1 */
+	/*1DF0 */
+
+/*1DF0 */ word volatile ToHyChannel;
+/*1DF2 */ word volatile ToHySize;
+	/*1DF4 */ uchar volatile ToHyFlag;
+	/* !=0: msg for Hy waiting */
+	/*1DF5 */ uchar volatile ToPcFlag;
+	/* !=0: msg for PC waiting */
+/*1DF6 */ word volatile ToPcChannel;
+/*1DF8 */ word volatile ToPcSize;
+	/*1DFA */ uchar bRes1DBA[0x1E00 - 0x1DFA];
+	/* 6 bytes */
+
+/*1E00 */ uchar bRestOfEntryTbl[0x1F00 - 0x1E00];
+/*1F00 */ ulong TrapTable[62];
+	/*1FF8 */ uchar bRes1FF8[0x1FFB - 0x1FF8];
+	/* low part of reset vetor */
+/*1FFB */ uchar ToPcIntMetro;
+	/* notes:
+	 * - metro has 32-bit boot ram - accessing
+	 *   ToPcInt and ToHyInt would be the same;
+	 *   so we moved ToPcInt to 1FFB.
+	 *   Because on the PC side both vars are
+	 *   readonly (reseting on int from E1 to PC),
+	 *   we can read both vars on both cards
+	 *   without destroying anything.
+	 * - 1FFB is the high byte of the reset vector,
+	 *   so E1 side should NOT change this byte
+	 *   when writing!
+	 */
+/*1FFC */ uchar volatile ToHyNoDpramErrLog;
+	/* note: ToHyNoDpramErrLog is used to inform
+	 *       boot loader, not to use DPRAM based
+	 *       ErrLog; when DOS driver is rewritten
+	 *       this becomes obsolete
+	 */
+/*1FFD */ uchar bRes1FFD;
+	/*1FFE */ uchar ToPcInt;
+	/* E1_intclear; on CHAMP2: E1_intset   */
+	/*1FFF */ uchar ToHyInt;
+	/* E1_intset;   on CHAMP2: E1_intclear */
+} tErgDpram;
+
+/**********************************************/
+/* PCI9050 controller local register offsets: */
+/* copied from boarderg.c                     */
+/**********************************************/
+#define PCI9050_INTR_REG    0x4C	/* Interrupt register */
+#define PCI9050_USER_IO     0x51	/* User I/O  register */
+
+				    /* bitmask for PCI9050_INTR_REG: */
+#define PCI9050_INTR_REG_EN1    0x01	/* 1= enable (def.), 0= disable */
+#define PCI9050_INTR_REG_POL1   0x02	/* 1= active high (def.), 0= active low */
+#define PCI9050_INTR_REG_STAT1  0x04	/* 1= intr. active, 0= intr. not active (def.) */
+#define PCI9050_INTR_REG_ENPCI  0x40	/* 1= PCI interrupts enable (def.) */
+
+				    /* bitmask for PCI9050_USER_IO: */
+#define PCI9050_USER_IO_EN3     0x02	/* 1= disable      , 0= enable (def.) */
+#define PCI9050_USER_IO_DIR3    0x04	/* 1= output (def.), 0= input         */
+#define PCI9050_USER_IO_DAT3    0x08	/* 1= high (def.)  , 0= low           */
+
+#define PCI9050_E1_RESET    (                     PCI9050_USER_IO_DIR3)		/* 0x04 */
+#define PCI9050_E1_RUN      (PCI9050_USER_IO_DAT3|PCI9050_USER_IO_DIR3)		/* 0x0C */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hysdn/hycapi.c linux.19p18/drivers/isdn/hysdn/hycapi.c
--- linux.vanilla/drivers/isdn/hysdn/hycapi.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/hysdn/hycapi.c	Tue Feb 13 18:49:43 2001
@@ -0,0 +1,839 @@
+/* $Id: hycapi.c,v 1.8 2000/11/22 17:13:13 kai Exp $
+ *
+ * Linux driver for HYSDN cards, CAPI2.0-Interface.
+ * written by Ulrich Albrecht (u.albrecht@hypercope.de) for Hypercope GmbH
+ *
+ * Copyright 2000 by Hypercope GmbH
+ *
+ * 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, 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.
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/signal.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+
+
+#define	VER_DRIVER	0
+#define	VER_CARDTYPE	1
+#define	VER_HWID	2
+#define	VER_SERIAL	3
+#define	VER_OPTION	4
+#define	VER_PROTO	5
+#define	VER_PROFILE	6
+#define	VER_CAPI	7
+
+#include "hysdn_defs.h"
+#include <linux/kernelcapi.h>
+
+static char hycapi_revision[]="$Revision: 1.8 $";
+
+typedef struct _hycapi_appl {
+	unsigned int ctrl_mask;
+	capi_register_params rp;
+	struct sk_buff *listen_req[CAPI_MAXCONTR];
+} hycapi_appl;
+
+static hycapi_appl hycapi_applications[CAPI_MAXAPPL];
+
+static inline int _hycapi_appCheck(int app_id, int ctrl_no)
+{
+	if((ctrl_no <= 0) || (ctrl_no > CAPI_MAXCONTR) || (app_id <= 0) ||
+	   (app_id > CAPI_MAXAPPL))
+	{
+		printk(KERN_ERR "HYCAPI: Invalid request app_id %d for controller %d", app_id, ctrl_no);
+		return -1;
+	}
+	return ((hycapi_applications[app_id-1].ctrl_mask & (1 << (ctrl_no-1))) != 0);
+}
+
+struct capi_driver_interface *hy_di = NULL;
+
+/******************************
+Kernel-Capi callback reset_ctr
+******************************/     
+
+void 
+hycapi_reset_ctr(struct capi_ctr *ctrl)
+{
+#ifdef HYCAPI_PRINTFNAMES
+	printk(KERN_NOTICE "HYCAPI hycapi_reset_ctr\n");
+#endif
+	ctrl->reseted(ctrl);
+}
+
+/******************************
+Kernel-Capi callback remove_ctr
+******************************/     
+
+void 
+hycapi_remove_ctr(struct capi_ctr *ctrl)
+{
+	int i;
+	hycapictrl_info *cinfo = NULL;
+	hysdn_card *card = NULL;
+#ifdef HYCAPI_PRINTFNAMES
+	printk(KERN_NOTICE "HYCAPI hycapi_remove_ctr\n");
+#endif 
+	if(!hy_di) {
+		printk(KERN_ERR "No capi_driver_interface set!");
+		return;
+	}
+	cinfo = (hycapictrl_info *)(ctrl->driverdata);
+	if(!cinfo) {
+		printk(KERN_ERR "No hycapictrl_info set!");
+		return;
+	}    
+	card = cinfo->card;
+	ctrl->suspend_output(ctrl);
+	for(i=0; i<CAPI_MAXAPPL;i++) {
+		if(hycapi_applications[i].listen_req[ctrl->cnr-1]) {
+			kfree_skb(hycapi_applications[i].listen_req[ctrl->cnr-1]);
+			hycapi_applications[i].listen_req[ctrl->cnr-1] = NULL;
+		}
+	}
+	hy_di->detach_ctr(ctrl);
+	ctrl->driverdata = 0;
+	kfree(card->hyctrlinfo);
+
+		
+	card->hyctrlinfo = NULL;
+}
+
+/***********************************************************
+
+Queue a CAPI-message to the controller.
+
+***********************************************************/
+
+static void
+hycapi_sendmsg_internal(struct capi_ctr *ctrl, struct sk_buff *skb)
+{
+	hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata);
+	hysdn_card *card = cinfo->card;
+
+	spin_lock_irq(&cinfo->lock);
+#ifdef HYCAPI_PRINTFNAMES
+	printk(KERN_NOTICE "hycapi_send_message\n");    
+#endif
+	cinfo->skbs[cinfo->in_idx++] = skb;	/* add to buffer list */
+	if (cinfo->in_idx >= HYSDN_MAX_CAPI_SKB)
+		cinfo->in_idx = 0;	/* wrap around */
+	cinfo->sk_count++;		/* adjust counter */
+	if (cinfo->sk_count >= HYSDN_MAX_CAPI_SKB) {
+		/* inform upper layers we're full */
+		printk(KERN_ERR "HYSDN Card%d: CAPI-buffer overrun!\n",
+		       card->myid);	
+		ctrl->suspend_output(ctrl);
+	}
+	cinfo->tx_skb = skb;
+	spin_unlock_irq(&cinfo->lock);
+	queue_task(&card->irq_queue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+}
+
+/***********************************************************
+hycapi_register_internal
+
+Send down the CAPI_REGISTER-Command to the controller.
+This functions will also be used if the adapter has been rebooted to
+re-register any applications in the private list.
+
+************************************************************/
+
+static void 
+hycapi_register_internal(struct capi_ctr *ctrl, __u16 appl,
+			 capi_register_params *rp)
+{
+	char ExtFeatureDefaults[] = "49  /0/0/0/0,*/1,*/2,*/3,*/4,*/5,*/6,*/7,*/8,*/9,*";
+	hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata);
+	hysdn_card *card = cinfo->card;
+	struct sk_buff *skb;
+	__u16 len;
+	__u8 _command = 0xa0, _subcommand = 0x80;
+	__u16 MessageNumber = 0x0000;
+	__u16 MessageBufferSize = 0;
+	int slen = strlen(ExtFeatureDefaults);
+#ifdef HYCAPI_PRINTFNAMES
+	printk(KERN_NOTICE "hycapi_register_appl\n"); 
+#endif
+	MessageBufferSize = rp->level3cnt * rp->datablkcnt * rp->datablklen; 
+
+	len = CAPI_MSG_BASELEN + 8 + slen + 1;
+	if (!(skb = alloc_skb(len, GFP_ATOMIC))) {
+		printk(KERN_ERR "HYSDN card%d: memory squeeze in hycapi_register_appl\n",
+		       card->myid);
+		return;
+	}
+	memcpy(skb_put(skb,sizeof(__u16)), &len, sizeof(__u16));
+	memcpy(skb_put(skb,sizeof(__u16)), &appl, sizeof(__u16));
+	memcpy(skb_put(skb,sizeof(__u8)), &_command, sizeof(_command));
+	memcpy(skb_put(skb,sizeof(__u8)), &_subcommand, sizeof(_subcommand));
+	memcpy(skb_put(skb,sizeof(__u16)), &MessageNumber, sizeof(__u16));
+	memcpy(skb_put(skb,sizeof(__u16)), &MessageBufferSize, sizeof(__u16)); 
+	memcpy(skb_put(skb,sizeof(__u16)), &(rp->level3cnt), sizeof(__u16));
+	memcpy(skb_put(skb,sizeof(__u16)), &(rp->datablkcnt), sizeof(__u16));
+	memcpy(skb_put(skb,sizeof(__u16)), &(rp->datablklen), sizeof(__u16));
+	memcpy(skb_put(skb,slen), ExtFeatureDefaults, slen);
+	hycapi_applications[appl-1].ctrl_mask |= (1 << (ctrl->cnr-1));    
+	hycapi_send_message(ctrl, skb);    
+}
+
+/************************************************************
+hycapi_restart_internal
+
+After an adapter has been rebootet, re-register all applications and
+send a LISTEN_REQ (if there has been such a thing )
+
+*************************************************************/
+
+static void hycapi_restart_internal(struct capi_ctr *ctrl)
+{
+	int i;
+	struct sk_buff *skb;
+#ifdef HYCAPI_PRINTFNAMES
+	printk(KERN_WARNING "HYSDN: hycapi_restart_internal");
+#endif
+	for(i=0; i<CAPI_MAXAPPL; i++) {
+		if(_hycapi_appCheck(i+1, ctrl->cnr) == 1) {
+			hycapi_register_internal(ctrl, i+1, 
+						 &hycapi_applications[i].rp);
+			if(hycapi_applications[i].listen_req[ctrl->cnr-1]) {
+				skb = skb_copy(hycapi_applications[i].listen_req[ctrl->cnr-1], GFP_ATOMIC);
+				hycapi_sendmsg_internal(ctrl, skb);
+			}
+		}
+	}
+}
+
+/*************************************************************
+Register an application.
+Error-checking is done for CAPI-compliance.
+
+The application is recorded in the internal list.
+*************************************************************/
+
+void 
+hycapi_register_appl(struct capi_ctr *ctrl, __u16 appl, 
+		     capi_register_params *rp)
+{
+	int MaxLogicalConnections = 0, MaxBDataBlocks = 0, MaxBDataLen = 0;
+	hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata);
+	hysdn_card *card = cinfo->card;
+	int chk = _hycapi_appCheck(appl, ctrl->cnr);
+	if(chk < 0) {
+		return;
+	}
+	if(chk == 1) {
+		printk(KERN_INFO "HYSDN: apl %d allready registered\n", appl);
+		return;
+	}
+	MaxBDataBlocks = rp->datablkcnt > CAPI_MAXDATAWINDOW ? CAPI_MAXDATAWINDOW : rp->datablkcnt;
+	rp->datablkcnt = MaxBDataBlocks;
+	MaxBDataLen = rp->datablklen < 1024 ? 1024 : rp->datablklen ;
+	rp->datablklen = MaxBDataLen;
+	
+	MaxLogicalConnections = rp->level3cnt;
+	if (MaxLogicalConnections < 0) {
+		MaxLogicalConnections = card->bchans * -MaxLogicalConnections; 
+	}
+	if (MaxLogicalConnections == 0) {
+		MaxLogicalConnections = card->bchans;
+	}
+	
+	rp->level3cnt = MaxLogicalConnections;
+	memcpy(&hycapi_applications[appl-1].rp, 
+	       rp, sizeof(capi_register_params));
+	
+/*        MOD_INC_USE_COUNT; */
+	ctrl->appl_registered(ctrl, appl);
+}
+
+/*********************************************************************
+
+hycapi_release_internal
+
+Send down a CAPI_RELEASE to the controller.
+*********************************************************************/
+
+static void hycapi_release_internal(struct capi_ctr *ctrl, __u16 appl)
+{
+	hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata);
+	hysdn_card *card = cinfo->card;
+	struct sk_buff *skb;
+	__u16 len;
+	__u8 _command = 0xa1, _subcommand = 0x80;
+	__u16 MessageNumber = 0x0000;
+#ifdef HYCAPI_PRINTFNAMES
+	printk(KERN_NOTICE "hycapi_release_appl\n");
+#endif
+	len = CAPI_MSG_BASELEN;
+	if (!(skb = alloc_skb(len, GFP_ATOMIC))) {
+		printk(KERN_ERR "HYSDN card%d: memory squeeze in hycapi_register_appl\n",
+		       card->myid);
+		return;
+	}
+	memcpy(skb_put(skb,sizeof(__u16)), &len, sizeof(__u16));
+	memcpy(skb_put(skb,sizeof(__u16)), &appl, sizeof(__u16));
+	memcpy(skb_put(skb,sizeof(__u8)), &_command, sizeof(_command));
+	memcpy(skb_put(skb,sizeof(__u8)), &_subcommand, sizeof(_subcommand));
+	memcpy(skb_put(skb,sizeof(__u16)), &MessageNumber, sizeof(__u16));    
+	hycapi_send_message(ctrl, skb);    
+	hycapi_applications[appl-1].ctrl_mask &= ~(1 << (ctrl->cnr-1));    
+}
+
+/******************************************************************
+hycapi_release_appl
+
+Release the application from the internal list an remove it's 
+registration at controller-level
+******************************************************************/
+
+void 
+hycapi_release_appl(struct capi_ctr *ctrl, __u16 appl)
+{
+	int chk;
+
+	chk = _hycapi_appCheck(appl, ctrl->cnr);
+	if(chk<0) {
+		printk(KERN_ERR "HYCAPI: Releasing invalid appl %d on controller %d\n", appl, ctrl->cnr);
+		return;
+	}
+	if(hycapi_applications[appl-1].listen_req[ctrl->cnr-1]) {
+		kfree_skb(hycapi_applications[appl-1].listen_req[ctrl->cnr-1]);
+		hycapi_applications[appl-1].listen_req[ctrl->cnr-1] = NULL;
+	}
+	if(chk == 1)
+	{
+		hycapi_release_internal(ctrl, appl);
+	}
+	ctrl->appl_released(ctrl, appl);
+/*        MOD_DEC_USE_COUNT;  */
+}
+
+
+/**************************************************************
+Kill a single controller.
+**************************************************************/
+
+int hycapi_capi_release(hysdn_card *card)
+{
+	hycapictrl_info *cinfo = card->hyctrlinfo;
+	struct capi_ctr *ctrl;
+#ifdef HYCAPI_PRINTFNAMES
+	printk(KERN_NOTICE "hycapi_capi_release\n");
+#endif
+	if(cinfo) {
+		ctrl = cinfo->capi_ctrl;
+		hycapi_remove_ctr(ctrl);
+	}
+	return 0;
+}
+
+/**************************************************************
+hycapi_capi_stop
+
+Stop CAPI-Output on a card. (e.g. during reboot)
+***************************************************************/
+
+int hycapi_capi_stop(hysdn_card *card)
+{
+	hycapictrl_info *cinfo = card->hyctrlinfo;
+	struct capi_ctr *ctrl;
+#ifdef HYCAPI_PRINTFNAMES
+	printk(KERN_NOTICE "hycapi_capi_stop\n");
+#endif
+	if(cinfo) {
+		if(cinfo->capi_ctrl) {
+			ctrl = cinfo->capi_ctrl;
+/*			ctrl->suspend_output(ctrl); */
+			ctrl->reseted(ctrl);
+
+		} else {
+			printk(KERN_NOTICE "hycapi_capi_stop: cinfo but no capi_ctrl\n");
+		}
+	}
+	return 0;
+}
+
+/***************************************************************
+hycapi_send_message
+
+Send a message to the controller.
+
+Messages are parsed for their Command/Subcommand-type, and appropriate
+action's are performed.
+
+Note that we have to muck around with a 64Bit-DATA_REQ as there are
+firmware-releases that do not check the MsgLen-Indication!
+
+***************************************************************/
+
+void hycapi_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
+{
+	__u16 appl_id;
+	int _len, _len2;
+	__u8 msghead[64];
+	
+	appl_id = CAPIMSG_APPID(skb->data);
+	switch(_hycapi_appCheck(appl_id, ctrl->cnr))
+	{
+		case 0:
+/*			printk(KERN_INFO "Need to register\n"); */
+			hycapi_register_internal(ctrl, 
+						 appl_id,
+						 &(hycapi_applications[appl_id-1].rp));
+			break;
+		case 1:
+			break;
+		default:
+			printk(KERN_ERR "HYCAPI: Controller mixup!\n");
+			return;
+	}
+	switch(CAPIMSG_CMD(skb->data)) {		
+		case CAPI_DISCONNECT_B3_RESP:
+			ctrl->free_ncci(ctrl, appl_id, 
+					CAPIMSG_NCCI(skb->data));
+			break;
+		case CAPI_DATA_B3_REQ:
+			_len = CAPIMSG_LEN(skb->data);
+			if (_len > 22) {
+				_len2 = _len - 22;
+				memcpy(msghead, skb->data, 22);
+				memcpy(skb->data + _len2, msghead, 22);
+				skb_pull(skb, _len2);
+				CAPIMSG_SETLEN(skb->data, 22);
+			}
+			break;
+		case CAPI_LISTEN_REQ:
+			if(hycapi_applications[appl_id-1].listen_req[ctrl->cnr-1])
+			{
+				kfree_skb(hycapi_applications[appl_id-1].listen_req[ctrl->cnr-1]);
+				hycapi_applications[appl_id-1].listen_req[ctrl->cnr-1] = NULL;
+			}
+			if (!(hycapi_applications[appl_id-1].listen_req[ctrl->cnr-1] = skb_copy(skb, GFP_ATOMIC))) 
+			{
+				printk(KERN_ERR "HYSDN: memory squeeze in private_listen\n");
+			} 
+			break;
+		default:
+			break;
+	}
+	hycapi_sendmsg_internal(ctrl, skb);
+}
+
+/*********************************************************************
+hycapi_read_proc
+
+Informations provided in the /proc/capi-entries.
+
+*********************************************************************/
+
+int hycapi_read_proc(char *page, char **start, off_t off,
+		     int count, int *eof, struct capi_ctr *ctrl)
+{
+	hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata);
+	hysdn_card *card = cinfo->card;
+	int len = 0;
+	char *s;
+#ifdef HYCAPI_PRINTFNAMES
+	printk(KERN_NOTICE "hycapi_read_proc\n");    
+#endif
+	len += sprintf(page+len, "%-16s %s\n", "name", cinfo->cardname);
+	len += sprintf(page+len, "%-16s 0x%x\n", "io", card->iobase);
+	len += sprintf(page+len, "%-16s %d\n", "irq", card->irq);
+    
+	switch (card->brdtype) {
+		case BD_PCCARD:  s = "HYSDN Hycard"; break;
+		case BD_ERGO: s = "HYSDN Ergo2"; break;
+		case BD_METRO: s = "HYSDN Metro4"; break;
+		case BD_CHAMP2: s = "HYSDN Champ2";	break;
+		case BD_PLEXUS: s = "HYSDN Plexus30"; break;
+		default: s = "???"; break;
+	}
+	len += sprintf(page+len, "%-16s %s\n", "type", s);
+	if ((s = cinfo->version[VER_DRIVER]) != 0)
+		len += sprintf(page+len, "%-16s %s\n", "ver_driver", s);
+	if ((s = cinfo->version[VER_CARDTYPE]) != 0)
+		len += sprintf(page+len, "%-16s %s\n", "ver_cardtype", s);
+	if ((s = cinfo->version[VER_SERIAL]) != 0)
+		len += sprintf(page+len, "%-16s %s\n", "ver_serial", s);
+    
+	len += sprintf(page+len, "%-16s %s\n", "cardname", cinfo->cardname);
+    
+	if (off+count >= len)
+		*eof = 1;
+	if (len < off)
+		return 0;
+	*start = page + off;
+	return ((count < len-off) ? count : len-off);
+}
+
+/**************************************************************
+hycapi_load_firmware
+
+This does NOT load any firmware, but the callback somehow is needed
+on capi-interface registration.
+
+**************************************************************/
+
+int hycapi_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
+{
+#ifdef HYCAPI_PRINTFNAMES
+	printk(KERN_NOTICE "hycapi_load_firmware\n");    
+#endif
+	return 0;
+}
+
+
+char *hycapi_procinfo(struct capi_ctr *ctrl)
+{
+	hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata);
+#ifdef HYCAPI_PRINTFNAMES
+	printk(KERN_NOTICE "hycapi_proc_info\n");    
+#endif
+	if (!cinfo)
+		return "";
+	sprintf(cinfo->infobuf, "%s %s 0x%x %d %s",
+		cinfo->cardname[0] ? cinfo->cardname : "-",
+		cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-",
+		cinfo->card ? cinfo->card->iobase : 0x0,
+		cinfo->card ? cinfo->card->irq : 0,
+		hycapi_revision
+		);
+	return cinfo->infobuf;
+}
+
+/******************************************************************
+hycapi_rx_capipkt
+
+Recieve a capi-message.
+
+All B3_DATA_IND are converted to 64K-extension compatible format.
+New nccis are created if neccessary.
+*******************************************************************/
+
+void
+hycapi_rx_capipkt(hysdn_card * card, uchar * buf, word len)
+{
+	struct sk_buff *skb;
+	hycapictrl_info *cinfo = card->hyctrlinfo;
+	struct capi_ctr *ctrl;
+	__u16 ApplId;
+	__u16 MsgLen, info;
+	__u16 len2, CapiCmd;
+	__u32 CP64[2] = {0,0};
+#ifdef HYCAPI_PRINTFNAMES
+	printk(KERN_NOTICE "hycapi_rx_capipkt\n");    
+#endif
+	if(!cinfo) {
+		printk(KERN_ERR "HYSDN Card%d: no HYCAPI-controller!\n",
+		       card->myid);
+		return;
+	}
+	ctrl = cinfo->capi_ctrl;
+	if(!ctrl)
+	{
+		printk(KERN_ERR "HYSDN Card%d: no CAPI-controller (1)!\n",
+		       card->myid);
+		return;
+	}
+	if(len < CAPI_MSG_BASELEN) {
+		printk(KERN_ERR "HYSDN Card%d: invalid CAPI-message, lenght %d!\n",
+		       card->myid, len);
+		return;
+	}	
+	MsgLen = CAPIMSG_LEN(buf);
+	ApplId = CAPIMSG_APPID(buf);
+	CapiCmd = CAPIMSG_CMD(buf);
+	
+	if((CapiCmd == CAPI_DATA_B3_IND) && (MsgLen < 30)) {
+		len2 = len + (30 - MsgLen);
+		if (!(skb = alloc_skb(len2, GFP_ATOMIC))) {
+			printk(KERN_ERR "HYSDN Card%d: incoming packet dropped\n",
+			       card->myid);
+			return;
+		}
+		memcpy(skb_put(skb, MsgLen), buf, MsgLen);
+		memcpy(skb_put(skb, 2*sizeof(__u32)), CP64, 2* sizeof(__u32));
+		memcpy(skb_put(skb, len - MsgLen), buf + MsgLen,
+		       len - MsgLen);
+		CAPIMSG_SETLEN(skb->data, 30);
+	} else {
+		if (!(skb = alloc_skb(len, GFP_ATOMIC))) {
+			printk(KERN_ERR "HYSDN Card%d: incoming packet dropped\n",
+			       card->myid);
+			return;
+		}
+		memcpy(skb_put(skb, len), buf, len);
+	}
+	switch(CAPIMSG_CMD(skb->data)) 
+	{
+		case CAPI_CONNECT_B3_CONF:
+/* Check info-field for error-indication: */
+			info = CAPIMSG_U16(skb->data, 12);
+			switch(info)
+			{
+				case 0:
+					ctrl->new_ncci(ctrl, ApplId, CAPIMSG_NCCI(skb->data), 
+						       hycapi_applications[ApplId-1].rp.datablkcnt); 
+					
+					break;
+				case 0x0001:
+					printk(KERN_ERR "HYSDN Card%d: NCPI not supported by current "
+					       "protocol. NCPI ignored.\n", card->myid);
+					break;
+				case 0x2001:
+					printk(KERN_ERR "HYSDN Card%d: Message not supported in"
+					       " current state\n", card->myid);
+					break;
+				case 0x2002:
+					printk(KERN_ERR "HYSDN Card%d: illegal PLCI\n", card->myid);
+					break;		
+				case 0x2004:
+					printk(KERN_ERR "HYSDN Card%d: out of NCCI\n", card->myid);
+					break;				
+				case 0x3008:
+					printk(KERN_ERR "HYSDN Card%d: NCPI not supported\n", 
+					       card->myid);
+					break;	
+				default:
+					printk(KERN_ERR "HYSDN Card%d: Info in CONNECT_B3_CONF: %d\n", 
+					       card->myid, info);
+					break;			
+			}
+			break;
+		case CAPI_CONNECT_B3_IND:
+			ctrl->new_ncci(ctrl, ApplId, 
+				       CAPIMSG_NCCI(skb->data), 
+				       hycapi_applications[ApplId-1].rp.datablkcnt);
+			break;
+		default:
+			break;
+	}
+	ctrl->handle_capimsg(ctrl, ApplId, skb);
+}
+
+/******************************************************************
+hycapi_tx_capiack
+
+Internally acknowledge a msg sent. This will remove the msg from the
+internal queue.
+
+*******************************************************************/
+
+void hycapi_tx_capiack(hysdn_card * card)
+{
+	hycapictrl_info *cinfo = card->hyctrlinfo;
+#ifdef HYCAPI_PRINTFNAMES
+	printk(KERN_NOTICE "hycapi_tx_capiack\n");    
+#endif
+	if(!cinfo) {
+		printk(KERN_ERR "HYSDN Card%d: no CAPI-controller (2)!\n",
+		       card->myid);
+		return;
+	}
+	spin_lock_irq(&cinfo->lock);
+	kfree_skb(cinfo->skbs[cinfo->out_idx]);		/* free skb */
+	cinfo->skbs[cinfo->out_idx++] = NULL;
+	if (cinfo->out_idx >= HYSDN_MAX_CAPI_SKB)
+		cinfo->out_idx = 0;	/* wrap around */
+
+	if (cinfo->sk_count-- == HYSDN_MAX_CAPI_SKB)	/* dec usage count */
+		cinfo->capi_ctrl->resume_output(cinfo->capi_ctrl);
+	spin_unlock_irq(&cinfo->lock);
+}
+
+/***************************************************************
+hycapi_tx_capiget(hysdn_card *card)
+
+This is called when polling for messages to SEND.
+
+****************************************************************/
+
+struct sk_buff *
+hycapi_tx_capiget(hysdn_card *card)
+{
+	hycapictrl_info *cinfo = card->hyctrlinfo;
+	if(!cinfo) {
+		printk(KERN_ERR "HYSDN Card%d: no CAPI-controller! (3)\n",
+		       card->myid);
+		return (struct sk_buff *)NULL;
+	}
+	if (!cinfo->sk_count)
+		return (struct sk_buff *)NULL;	/* nothing available */
+
+	return (cinfo->skbs[cinfo->out_idx]);		/* next packet to send */
+}
+
+
+static struct capi_driver hycapi_driver = {
+	"hysdn",
+	"0.0",
+	hycapi_load_firmware, 
+	hycapi_reset_ctr,
+	hycapi_remove_ctr,
+	hycapi_register_appl,
+	hycapi_release_appl,
+	hycapi_send_message,
+	hycapi_procinfo,
+	hycapi_read_proc,
+	0,	/* use standard driver_read_proc */
+	0, /* no add_card function */
+};
+
+
+/**********************************************************
+int hycapi_init()
+
+attach the capi-driver to the kernel-capi.
+
+***********************************************************/
+
+int hycapi_init()
+{
+	struct capi_driver *driver;
+	int i;
+	if(hy_di) {
+		printk(KERN_NOTICE "HyDI allready set\n");
+		return 0;
+	}
+	driver = &hycapi_driver;
+	printk(KERN_NOTICE "HYSDN: Attaching capi-driver\n");
+	hy_di = attach_capi_driver(driver);
+	if (!hy_di) {
+		printk(KERN_ERR "HYCAPI: failed to attach capi_driver\n");
+		return(-1);
+	}
+	for(i=0;i<CAPI_MAXAPPL;i++) {
+		memset(&(hycapi_applications[i]), 0, sizeof(hycapi_appl));
+	}
+	return(0);
+}
+
+/**************************************************************
+hycapi_cleanup(void)
+
+detach the capi-driver to the kernel-capi. Actually this should
+free some more ressources. Do that later.
+**************************************************************/
+
+void 
+hycapi_cleanup(void)
+{
+	struct capi_driver *driver;
+	driver = &hycapi_driver;
+	if (!hy_di) {
+		printk(KERN_ERR "HYSDN: no capi-driver to detach (???)\n");
+		return;
+	}
+	printk(KERN_NOTICE "HYSDN: Detaching capi-driver\n");
+	detach_capi_driver(driver);
+	hy_di = 0;
+	return;
+}
+
+/********************************************************************
+hycapi_capi_create(hysdn_card *card)
+
+Attach the card with it's capi-ctrl.
+*********************************************************************/
+
+static void hycapi_fill_profile(hysdn_card *card)
+{
+	hycapictrl_info *cinfo = NULL;
+	struct capi_ctr *ctrl = NULL;
+	cinfo = card->hyctrlinfo;
+	if(!cinfo) return;
+	ctrl = cinfo->capi_ctrl;
+	if(!ctrl) return;
+	strcpy(ctrl->manu, "Hypercope");	
+	ctrl->version.majorversion = 2;
+	ctrl->version.minorversion = 0;
+	ctrl->version.majormanuversion = 3;
+	ctrl->version.minormanuversion = 2;
+	ctrl->profile.ncontroller = card->myid;
+	ctrl->profile.nbchannel = card->bchans;
+	ctrl->profile.goptions = GLOBAL_OPTION_INTERNAL_CONTROLLER |
+		GLOBAL_OPTION_B_CHANNEL_OPERATION;
+	ctrl->profile.support1 =  B1_PROT_64KBIT_HDLC |
+		(card->faxchans ? B1_PROT_T30 : 0) |
+		B1_PROT_64KBIT_TRANSPARENT;
+	ctrl->profile.support2 = B2_PROT_ISO7776 |
+		(card->faxchans ? B2_PROT_T30 : 0) |
+		B2_PROT_TRANSPARENT;
+	ctrl->profile.support3 = B3_PROT_TRANSPARENT |
+		B3_PROT_T90NL |
+		(card->faxchans ? B3_PROT_T30 : 0) |
+		(card->faxchans ? B3_PROT_T30EXT : 0) |
+		B3_PROT_ISO8208;
+}	
+
+int 
+hycapi_capi_create(hysdn_card *card)
+{
+	hycapictrl_info *cinfo = NULL;
+	struct capi_ctr *ctrl = NULL;
+#ifdef HYCAPI_PRINTFNAMES
+	printk(KERN_NOTICE "hycapi_capi_create\n");        
+#endif
+	if (!card->hyctrlinfo) {
+		cinfo = (hycapictrl_info *) kmalloc(sizeof(hycapictrl_info), GFP_ATOMIC);
+		if (!cinfo) {
+			printk(KERN_WARNING "HYSDN: no memory for capi-ctrl.\n");
+			return -ENOMEM;
+		}
+		memset(cinfo, 0, sizeof(hycapictrl_info));
+		card->hyctrlinfo = cinfo;
+		cinfo->card = card;
+		spin_lock_init(&cinfo->lock);
+
+		switch (card->brdtype) {
+			case BD_PCCARD:  strcpy(cinfo->cardname,"HYSDN Hycard"); break;
+			case BD_ERGO: strcpy(cinfo->cardname,"HYSDN Ergo2"); break;
+			case BD_METRO: strcpy(cinfo->cardname,"HYSDN Metro4"); break;
+			case BD_CHAMP2: strcpy(cinfo->cardname,"HYSDN Champ2"); break;
+			case BD_PLEXUS: strcpy(cinfo->cardname,"HYSDN Plexus30"); break;
+			default: strcpy(cinfo->cardname,"HYSDN ???"); break;
+		}
+
+		cinfo->capi_ctrl = hy_di->attach_ctr(&hycapi_driver, 
+						     cinfo->cardname, cinfo);
+		ctrl = cinfo->capi_ctrl;
+		if (!ctrl) {
+			printk(KERN_ERR "%s: attach controller failed.\n",
+			       hycapi_driver.name);
+			return -EBUSY;
+		}
+		/* fill in the blanks: */
+		hycapi_fill_profile(card);
+		ctrl->ready(ctrl);
+	} else {
+		/* resume output on stopped ctrl */
+		ctrl = card->hyctrlinfo->capi_ctrl;
+		if(ctrl) {
+			hycapi_fill_profile(card);
+			ctrl->ready(ctrl);
+			hycapi_restart_internal(ctrl); 
+/*			ctrl->resume_output(ctrl); */
+		} else {
+			printk(KERN_WARNING "HYSDN: No ctrl???? How come?\n");
+		}
+	}
+	return 0;
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hysdn/hysdn_boot.c linux.19p18/drivers/isdn/hysdn/hysdn_boot.c
--- linux.vanilla/drivers/isdn/hysdn/hysdn_boot.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/hysdn/hysdn_boot.c	Tue Feb 13 18:49:43 2001
@@ -0,0 +1,413 @@
+/* $Id: hysdn_boot.c,v 1.4.6.1 2001/02/10 14:41:22 kai Exp $
+
+ * Linux driver for HYSDN cards, specific routines for booting and pof handling.
+ *
+ * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
+ *
+ * Copyright 1999  by Werner Cornelius (werner@titro.de)
+ *
+ * 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, 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.
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <asm/uaccess.h>
+
+#include "hysdn_defs.h"
+#include "hysdn_pof.h"
+
+/********************************/
+/* defines for pof read handler */
+/********************************/
+#define POF_READ_FILE_HEAD  0
+#define POF_READ_TAG_HEAD   1
+#define POF_READ_TAG_DATA   2
+
+/************************************************************/
+/* definition of boot specific data area. This data is only */
+/* needed during boot and so allocated dynamically.         */
+/************************************************************/
+struct boot_data {
+	word Cryptor;		/* for use with Decrypt function */
+	word Nrecs;		/* records remaining in file */
+	uchar pof_state;	/* actual state of read handler */
+	uchar is_crypted;	/* card data is crypted */
+	int BufSize;		/* actual number of bytes bufferd */
+	int last_error;		/* last occured error */
+	word pof_recid;		/* actual pof recid */
+	ulong pof_reclen;	/* total length of pof record data */
+	ulong pof_recoffset;	/* actual offset inside pof record */
+	union {
+		uchar BootBuf[BOOT_BUF_SIZE];	/* buffer as byte count */
+		tPofRecHdr PofRecHdr;	/* header for actual record/chunk */
+		tPofFileHdr PofFileHdr;		/* header from POF file */
+		tPofTimeStamp PofTime;	/* time information */
+	} buf;
+};
+
+/*****************************************************/
+/*  start decryption of sucessive POF file chuncks.  */
+/*                                                   */
+/*  to be called at start of POF file reading,       */
+/*  before starting any decryption on any POF record. */
+/*****************************************************/
+void
+StartDecryption(struct boot_data *boot)
+{
+	boot->Cryptor = CRYPT_STARTTERM;
+}				/* StartDecryption */
+
+
+/***************************************************************/
+/* decrypt complete BootBuf                                    */
+/* NOTE: decryption must be applied to all or none boot tags - */
+/*       to HI and LO boot loader and (all) seq tags, because  */
+/*       global Cryptor is started for whole POF.              */
+/***************************************************************/
+void
+DecryptBuf(struct boot_data *boot, int cnt)
+{
+	uchar *bufp = boot->buf.BootBuf;
+
+	while (cnt--) {
+		boot->Cryptor = (boot->Cryptor >> 1) ^ ((boot->Cryptor & 1U) ? CRYPT_FEEDTERM : 0);
+		*bufp++ ^= (uchar) boot->Cryptor;
+	}
+}				/* DecryptBuf */
+
+/********************************************************************************/
+/* pof_handle_data executes the required actions dependant on the active record */
+/* id. If successfull 0 is returned, a negative value shows an error.           */
+/********************************************************************************/
+static int
+pof_handle_data(hysdn_card * card, int datlen)
+{
+	struct boot_data *boot = card->boot;	/* pointer to boot specific data */
+	long l;
+	uchar *imgp;
+	int img_len;
+
+	/* handle the different record types */
+	switch (boot->pof_recid) {
+
+		case TAG_TIMESTMP:
+			if (card->debug_flags & LOG_POF_RECORD)
+				hysdn_addlog(card, "POF created %s", boot->buf.PofTime.DateTimeText);
+			break;
+
+		case TAG_CBOOTDTA:
+			DecryptBuf(boot, datlen);	/* we need to encrypt the buffer */
+		case TAG_BOOTDTA:
+			if (card->debug_flags & LOG_POF_RECORD)
+				hysdn_addlog(card, "POF got %s len=%d offs=0x%lx",
+					     (boot->pof_recid == TAG_CBOOTDTA) ? "CBOOTDATA" : "BOOTDTA",
+					     datlen, boot->pof_recoffset);
+
+			if (boot->pof_reclen != POF_BOOT_LOADER_TOTAL_SIZE) {
+				boot->last_error = EPOF_BAD_IMG_SIZE;	/* invalid length */
+				return (boot->last_error);
+			}
+			imgp = boot->buf.BootBuf;	/* start of buffer */
+			img_len = datlen;	/* maximum length to transfer */
+
+			l = POF_BOOT_LOADER_OFF_IN_PAGE -
+			    (boot->pof_recoffset & (POF_BOOT_LOADER_PAGE_SIZE - 1));
+			if (l > 0) {
+				/* buffer needs to be truncated */
+				imgp += l;	/* advance pointer */
+				img_len -= l;	/* adjust len */
+			}
+			/* at this point no special handling for data wrapping over buffer */
+			/* is necessary, because the boot image always will be adjusted to */
+			/* match a page boundary inside the buffer.                        */
+			/* The buffer for the boot image on the card is filled in 2 cycles */
+			/* first the 1024 hi-words are put in the buffer, then the low 1024 */
+			/* word are handled in the same way with different offset.         */
+
+			if (img_len > 0) {
+				/* data available for copy */
+				if ((boot->last_error =
+				     card->writebootimg(card, imgp,
+							(boot->pof_recoffset > POF_BOOT_LOADER_PAGE_SIZE) ? 2 : 0)) < 0)
+					return (boot->last_error);
+			}
+			break;	/* end of case boot image hi/lo */
+
+		case TAG_CABSDATA:
+			DecryptBuf(boot, datlen);	/* we need to encrypt the buffer */
+		case TAG_ABSDATA:
+			if (card->debug_flags & LOG_POF_RECORD)
+				hysdn_addlog(card, "POF got %s len=%d offs=0x%lx",
+					     (boot->pof_recid == TAG_CABSDATA) ? "CABSDATA" : "ABSDATA",
+					     datlen, boot->pof_recoffset);
+
+			if ((boot->last_error = card->writebootseq(card, boot->buf.BootBuf, datlen) < 0))
+				return (boot->last_error);	/* error writing data */
+
+			if (boot->pof_recoffset + datlen >= boot->pof_reclen)
+				return (card->waitpofready(card));	/* data completely spooled, wait for ready */
+
+			break;	/* end of case boot seq data */
+
+		default:
+			if (card->debug_flags & LOG_POF_RECORD)
+				hysdn_addlog(card, "POF got data(id=0x%lx) len=%d offs=0x%lx", boot->pof_recid,
+					     datlen, boot->pof_recoffset);
+
+			break;	/* simply skip record */
+	}			/* switch boot->pof_recid */
+
+	return (0);
+}				/* pof_handle_data */
+
+
+/******************************************************************************/
+/* pof_write_buffer is called when the buffer has been filled with the needed */
+/* number of data bytes. The number delivered is additionally supplied for    */
+/* verification. The functions handles the data and returns the needed number */
+/* of bytes for the next action. If the returned value is 0 or less an error  */
+/* occured and booting must be aborted.                                       */
+/******************************************************************************/
+int
+pof_write_buffer(hysdn_card * card, int datlen)
+{
+	struct boot_data *boot = card->boot;	/* pointer to boot specific data */
+
+	if (!boot)
+		return (-EFAULT);	/* invalid call */
+	if (boot->last_error < 0)
+		return (boot->last_error);	/* repeated error */
+
+	if (card->debug_flags & LOG_POF_WRITE)
+		hysdn_addlog(card, "POF write: got %d bytes ", datlen);
+
+	switch (boot->pof_state) {
+		case POF_READ_FILE_HEAD:
+			if (card->debug_flags & LOG_POF_WRITE)
+				hysdn_addlog(card, "POF write: checking file header");
+
+			if (datlen != sizeof(tPofFileHdr)) {
+				boot->last_error = -EPOF_INTERNAL;
+				break;
+			}
+			if (boot->buf.PofFileHdr.Magic != TAGFILEMAGIC) {
+				boot->last_error = -EPOF_BAD_MAGIC;
+				break;
+			}
+			/* Setup the new state and vars */
+			boot->Nrecs = (word) (boot->buf.PofFileHdr.N_PofRecs);	/* limited to 65535 */
+			boot->pof_state = POF_READ_TAG_HEAD;	/* now start with single tags */
+			boot->last_error = sizeof(tPofRecHdr);	/* new length */
+			break;
+
+		case POF_READ_TAG_HEAD:
+			if (card->debug_flags & LOG_POF_WRITE)
+				hysdn_addlog(card, "POF write: checking tag header");
+
+			if (datlen != sizeof(tPofRecHdr)) {
+				boot->last_error = -EPOF_INTERNAL;
+				break;
+			}
+			boot->pof_recid = boot->buf.PofRecHdr.PofRecId;		/* actual pof recid */
+			boot->pof_reclen = boot->buf.PofRecHdr.PofRecDataLen;	/* total length */
+			boot->pof_recoffset = 0;	/* no starting offset */
+
+			if (card->debug_flags & LOG_POF_RECORD)
+				hysdn_addlog(card, "POF: got record id=0x%lx length=%ld ",
+				      boot->pof_recid, boot->pof_reclen);
+
+			boot->pof_state = POF_READ_TAG_DATA;	/* now start with tag data */
+			if (boot->pof_reclen < BOOT_BUF_SIZE)
+				boot->last_error = boot->pof_reclen;	/* limit size */
+			else
+				boot->last_error = BOOT_BUF_SIZE;	/* maximum */
+
+			if (!boot->last_error) {	/* no data inside record */
+				boot->pof_state = POF_READ_TAG_HEAD;	/* now start with single tags */
+				boot->last_error = sizeof(tPofRecHdr);	/* new length */
+			}
+			break;
+
+		case POF_READ_TAG_DATA:
+			if (card->debug_flags & LOG_POF_WRITE)
+				hysdn_addlog(card, "POF write: getting tag data");
+
+			if (datlen != boot->last_error) {
+				boot->last_error = -EPOF_INTERNAL;
+				break;
+			}
+			if ((boot->last_error = pof_handle_data(card, datlen)) < 0)
+				return (boot->last_error);	/* an error occured */
+			boot->pof_recoffset += datlen;
+			if (boot->pof_recoffset >= boot->pof_reclen) {
+				boot->pof_state = POF_READ_TAG_HEAD;	/* now start with single tags */
+				boot->last_error = sizeof(tPofRecHdr);	/* new length */
+			} else {
+				if (boot->pof_reclen - boot->pof_recoffset < BOOT_BUF_SIZE)
+					boot->last_error = boot->pof_reclen - boot->pof_recoffset;	/* limit size */
+				else
+					boot->last_error = BOOT_BUF_SIZE;	/* maximum */
+			}
+			break;
+
+		default:
+			boot->last_error = -EPOF_INTERNAL;	/* unknown state */
+			break;
+	}			/* switch (boot->pof_state) */
+
+	return (boot->last_error);
+}				/* pof_write_buffer */
+
+
+/*******************************************************************************/
+/* pof_write_open is called when an open for boot on the cardlog device occurs. */
+/* The function returns the needed number of bytes for the next operation. If  */
+/* the returned number is less or equal 0 an error specified by this code      */
+/* occurred. Additionally the pointer to the buffer data area is set on success */
+/*******************************************************************************/
+int
+pof_write_open(hysdn_card * card, uchar ** bufp)
+{
+	struct boot_data *boot;	/* pointer to boot specific data */
+
+	if (card->boot) {
+		if (card->debug_flags & LOG_POF_OPEN)
+			hysdn_addlog(card, "POF open: already opened for boot");
+		return (-ERR_ALREADY_BOOT);	/* boot already active */
+	}
+	/* error no mem available */
+	if (!(boot = kmalloc(sizeof(struct boot_data), GFP_KERNEL))) {
+		if (card->debug_flags & LOG_MEM_ERR)
+			hysdn_addlog(card, "POF open: unable to allocate mem");
+		return (-EFAULT);
+	}
+	card->boot = boot;
+	card->state = CARD_STATE_BOOTING;
+	memset(boot, 0, sizeof(struct boot_data));
+
+	card->stopcard(card);	/* first stop the card */
+	if (card->testram(card)) {
+		if (card->debug_flags & LOG_POF_OPEN)
+			hysdn_addlog(card, "POF open: DPRAM test failure");
+		boot->last_error = -ERR_BOARD_DPRAM;
+		card->state = CARD_STATE_BOOTERR;	/* show boot error */
+		return (boot->last_error);
+	}
+	boot->BufSize = 0;	/* Buffer is empty */
+	boot->pof_state = POF_READ_FILE_HEAD;	/* read file header */
+	StartDecryption(boot);	/* if POF File should be encrypted */
+
+	if (card->debug_flags & LOG_POF_OPEN)
+		hysdn_addlog(card, "POF open: success");
+
+	*bufp = boot->buf.BootBuf;	/* point to buffer */
+	return (sizeof(tPofFileHdr));
+}				/* pof_write_open */
+
+/********************************************************************************/
+/* pof_write_close is called when an close of boot on the cardlog device occurs. */
+/* The return value must be 0 if everything has happened as desired.            */
+/********************************************************************************/
+int
+pof_write_close(hysdn_card * card)
+{
+	struct boot_data *boot = card->boot;	/* pointer to boot specific data */
+
+	if (!boot)
+		return (-EFAULT);	/* invalid call */
+
+	card->boot = NULL;	/* no boot active */
+	kfree(boot);
+
+	if (card->state == CARD_STATE_RUN)
+		card->set_errlog_state(card, 1);	/* activate error log */
+
+	if (card->debug_flags & LOG_POF_OPEN)
+		hysdn_addlog(card, "POF close: success");
+
+	return (0);
+}				/* pof_write_close */
+
+/*********************************************************************************/
+/* EvalSysrTokData checks additional records delivered with the Sysready Message */
+/* when POF has been booted. A return value of 0 is used if no error occured.    */
+/*********************************************************************************/
+int
+EvalSysrTokData(hysdn_card * card, uchar * cp, int len)
+{
+	u_char *p;
+	u_char crc;
+
+	if (card->debug_flags & LOG_POF_RECORD)
+		hysdn_addlog(card, "SysReady Token data length %d", len);
+
+	if (len < 2) {
+		hysdn_addlog(card, "SysReady Token Data to short");
+		return (1);
+	}
+	for (p = cp, crc = 0; p < (cp + len - 2); p++)
+		if ((crc & 0x80))
+			crc = (((u_char) (crc << 1)) + 1) + *p;
+		else
+			crc = ((u_char) (crc << 1)) + *p;
+	crc = ~crc;
+	if (crc != *(cp + len - 1)) {
+		hysdn_addlog(card, "SysReady Token Data invalid CRC");
+		return (1);
+	}
+	len--;			/* dont check CRC byte */
+	while (len > 0) {
+
+		if (*cp == SYSR_TOK_END)
+			return (0);	/* End of Token stream */
+
+		if (len < (*(cp + 1) + 2)) {
+			hysdn_addlog(card, "token 0x%x invalid length %d", *cp, *(cp + 1));
+			return (1);
+		}
+		switch (*cp) {
+			case SYSR_TOK_B_CHAN:	/* 1 */
+				if (*(cp + 1) != 1)
+					return (1);	/* length invalid */
+				card->bchans = *(cp + 2);
+				break;
+
+			case SYSR_TOK_FAX_CHAN:	/* 2 */
+				if (*(cp + 1) != 1)
+					return (1);	/* length invalid */
+				card->faxchans = *(cp + 2);
+				break;
+
+			case SYSR_TOK_MAC_ADDR:	/* 3 */
+				if (*(cp + 1) != 6)
+					return (1);	/* length invalid */
+				memcpy(card->mac_addr, cp + 2, 6);
+				break;
+
+			default:
+				hysdn_addlog(card, "unknown token 0x%02x length %d", *cp, *(cp + 1));
+				break;
+		}
+		len -= (*(cp + 1) + 2);		/* adjust len */
+		cp += (*(cp + 1) + 2);	/* and pointer */
+	}
+
+	hysdn_addlog(card, "no end token found");
+	return (1);
+}				/* EvalSysrTokData */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hysdn/hysdn_defs.h linux.19p18/drivers/isdn/hysdn/hysdn_defs.h
--- linux.vanilla/drivers/isdn/hysdn/hysdn_defs.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/hysdn/hysdn_defs.h	Sat Mar  3 23:00:25 2001
@@ -0,0 +1,307 @@
+/* $Id: hysdn_defs.h,v 1.5.6.1 2000/11/28 12:02:47 kai Exp $
+
+ * Linux driver for HYSDN cards, global definitions and exported vars and functions.
+ * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
+ *
+ * Copyright 1999  by Werner Cornelius (werner@titro.de)
+ *
+ * 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, 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.
+ *
+ */
+
+#ifndef HYSDN_DEFS_H
+#define HYSDN_DEFS_H
+
+#include <linux/config.h>
+#include <linux/hysdn_if.h>
+#include <linux/interrupt.h>
+#include <linux/tqueue.h>
+#include <linux/skbuff.h>
+#include <linux/isdn_compat.h>
+
+/****************************/
+/* storage type definitions */
+/****************************/
+#define uchar unsigned char
+#define uint unsigned int
+#define ulong unsigned long
+#define word unsigned short
+
+#include "ince1pc.h"
+
+#ifdef CONFIG_HYSDN_CAPI
+#include <linux/capi.h>
+#include "../avmb1/capicmd.h"
+#include "../avmb1/capiutil.h"
+#include "../avmb1/capilli.h"
+
+/***************************/
+/*   CAPI-Profile values.  */
+/***************************/
+
+#define GLOBAL_OPTION_INTERNAL_CONTROLLER 0x0001
+#define GLOBAL_OPTION_EXTERNAL_CONTROLLER 0x0002
+#define GLOBAL_OPTION_HANDSET             0x0004
+#define GLOBAL_OPTION_DTMF                0x0008
+#define GLOBAL_OPTION_SUPPL_SERVICES      0x0010
+#define GLOBAL_OPTION_CHANNEL_ALLOCATION  0x0020
+#define GLOBAL_OPTION_B_CHANNEL_OPERATION 0x0040
+
+#define B1_PROT_64KBIT_HDLC        0x0001
+#define B1_PROT_64KBIT_TRANSPARENT 0x0002
+#define B1_PROT_V110_ASYNCH        0x0004 
+#define B1_PROT_V110_SYNCH         0x0008
+#define B1_PROT_T30                0x0010
+#define B1_PROT_64KBIT_INV_HDLC    0x0020
+#define B1_PROT_56KBIT_TRANSPARENT 0x0040
+
+#define B2_PROT_ISO7776            0x0001
+#define B2_PROT_TRANSPARENT        0x0002
+#define B2_PROT_SDLC               0x0004
+#define B2_PROT_LAPD               0x0008
+#define B2_PROT_T30                0x0010
+#define B2_PROT_PPP                0x0020
+#define B2_PROT_TRANSPARENT_IGNORE_B1_FRAMING_ERRORS 0x0040
+
+#define B3_PROT_TRANSPARENT        0x0001
+#define B3_PROT_T90NL              0x0002
+#define B3_PROT_ISO8208            0x0004
+#define B3_PROT_X25_DCE            0x0008
+#define B3_PROT_T30                0x0010
+#define B3_PROT_T30EXT             0x0020
+
+#define HYSDN_MAXVERSION		8
+
+/* Number of sendbuffers in CAPI-queue */
+#define HYSDN_MAX_CAPI_SKB             20
+
+#endif /* CONFIG_HYSDN_CAPI*/
+
+/************************************************/
+/* constants and bits for debugging/log outputs */
+/************************************************/
+#define LOG_MAX_LINELEN 120
+#define DEB_OUT_SYSLOG  0x80000000	/* output to syslog instead of proc fs */
+#define LOG_MEM_ERR     0x00000001	/* log memory errors like kmalloc failure */
+#define LOG_POF_OPEN    0x00000010	/* log pof open and close activities */
+#define LOG_POF_RECORD  0x00000020	/* log pof record parser */
+#define LOG_POF_WRITE   0x00000040	/* log detailed pof write operation */
+#define LOG_POF_CARD    0x00000080	/* log pof related card functions */
+#define LOG_CNF_LINE    0x00000100	/* all conf lines are put to procfs */
+#define LOG_CNF_DATA    0x00000200	/* non comment conf lines are shown with channel */
+#define LOG_CNF_MISC    0x00000400	/* additional conf line debug outputs */
+#define LOG_SCHED_ASYN  0x00001000	/* debug schedulers async tx routines */
+#define LOG_PROC_OPEN   0x00100000	/* open and close from procfs are logged */
+#define LOG_PROC_ALL    0x00200000	/* all actions from procfs are logged */
+#define LOG_NET_INIT    0x00010000	/* network init and deinit logging */
+
+#define DEF_DEB_FLAGS   0x7fff000f	/* everything is logged to procfs */
+
+/**********************************/
+/* proc filesystem name constants */
+/**********************************/
+#define PROC_SUBDIR_NAME "hysdn"
+#define PROC_CONF_BASENAME "cardconf"
+#define PROC_LOG_BASENAME "cardlog"
+
+/***********************************/
+/* PCI 32 bit parms for IO and MEM */
+/***********************************/
+#define PCI_REG_PLX_MEM_BASE    0
+#define PCI_REG_PLX_IO_BASE     1
+#define PCI_REG_MEMORY_BASE     3
+
+/**************/
+/* card types */
+/**************/
+#define BD_NONE         0U
+#define BD_PERFORMANCE  1U
+#define BD_VALUE        2U
+#define BD_PCCARD       3U
+#define BD_ERGO         4U
+#define BD_METRO        5U
+#define BD_CHAMP2       6U
+#define BD_PLEXUS       7U
+
+/******************************************************/
+/* defined states for cards shown by reading cardconf */
+/******************************************************/
+#define CARD_STATE_UNUSED   0	/* never been used or booted */
+#define CARD_STATE_BOOTING  1	/* booting is in progress */
+#define CARD_STATE_BOOTERR  2	/* a previous boot was aborted */
+#define CARD_STATE_RUN      3	/* card is active */
+
+/*******************************/
+/* defines for error_log_state */
+/*******************************/
+#define ERRLOG_STATE_OFF   0	/* error log is switched off, nothing to do */
+#define ERRLOG_STATE_ON    1	/* error log is switched on, wait for data */
+#define ERRLOG_STATE_START 2	/* start error logging */
+#define ERRLOG_STATE_STOP  3	/* stop error logging */
+
+/*******************************/
+/* data structure for one card */
+/*******************************/
+typedef struct HYSDN_CARD {
+
+	/* general variables for the cards */
+	int myid;		/* own driver card id */
+	uchar bus;		/* pci bus the card is connected to */
+	uchar devfn;		/* slot+function bit encoded */
+	word subsysid;		/* PCI subsystem id */
+	uchar brdtype;		/* type of card */
+	uint bchans;		/* number of available B-channels */
+	uint faxchans;		/* number of available fax-channels */
+	uchar mac_addr[6];	/* MAC Address read from card */
+	uint irq;		/* interrupt number */
+	uint iobase;		/* IO-port base address */
+	ulong plxbase;		/* PLX memory base */
+	ulong membase;		/* DPRAM memory base */
+	ulong memend;		/* DPRAM memory end */
+	void *dpram;		/* mapped dpram */
+	int state;		/* actual state of card -> CARD_STATE_** */
+	struct HYSDN_CARD *next;	/* pointer to next card */
+
+	/* data areas for the /proc file system */
+	void *proclog;		/* pointer to proclog filesystem specific data */
+	void *procconf;		/* pointer to procconf filesystem specific data */
+
+	/* debugging and logging */
+	uchar err_log_state;	/* actual error log state of the card */
+	ulong debug_flags;	/* tells what should be debugged and where */
+	void (*set_errlog_state) (struct HYSDN_CARD *, int);
+
+	/* interrupt handler + interrupt synchronisation */
+	struct tq_struct irq_queue;	/* interrupt task queue */
+	uchar volatile irq_enabled;	/* interrupt enabled if != 0 */
+	uchar volatile hw_lock;	/* hardware is currently locked -> no access */
+
+	/* boot process */
+	void *boot;		/* pointer to boot private data */
+	int (*writebootimg) (struct HYSDN_CARD *, uchar *, ulong);
+	int (*writebootseq) (struct HYSDN_CARD *, uchar *, int);
+	int (*waitpofready) (struct HYSDN_CARD *);
+	int (*testram) (struct HYSDN_CARD *);
+
+	/* scheduler for data transfer (only async parts) */
+	uchar async_data[256];	/* async data to be sent (normally for config) */
+	word volatile async_len;	/* length of data to sent */
+	word volatile async_channel;	/* channel number for async transfer */
+	int volatile async_busy;	/* flag != 0 sending in progress */
+	int volatile net_tx_busy;	/* a network packet tx is in progress */
+
+	/* network interface */
+	void *netif;		/* pointer to network structure */
+
+	/* init and deinit stopcard for booting, too */
+	void (*stopcard) (struct HYSDN_CARD *);
+	void (*releasehardware) (struct HYSDN_CARD *);
+#ifdef CONFIG_HYSDN_CAPI
+	struct hycapictrl_info {
+		char cardname[32];
+		spinlock_t lock;
+		int versionlen;
+		char versionbuf[1024];
+		char *version[HYSDN_MAXVERSION];
+
+		char infobuf[128];	/* for function procinfo */
+		
+		struct HYSDN_CARD  *card;
+		struct capi_ctr *capi_ctrl;
+		struct sk_buff *skbs[HYSDN_MAX_CAPI_SKB];
+		int in_idx, out_idx;	/* indexes to buffer ring */
+		int sk_count;		/* number of buffers currently in ring */
+		struct sk_buff *tx_skb;	/* buffer for tx operation */
+	} *hyctrlinfo;
+#endif /* CONFIG_HYSDN_CAPI */
+} hysdn_card;
+
+#ifdef CONFIG_HYSDN_CAPI
+typedef struct hycapictrl_info hycapictrl_info;
+#endif /* CONFIG_HYSDN_CAPI */
+
+
+/*****************/
+/* exported vars */
+/*****************/
+extern int cardmax;		/* number of found cards */
+extern hysdn_card *card_root;	/* pointer to first card */
+
+
+
+/*************************/
+/* im/exported functions */
+/*************************/
+extern int printk(const char *fmt,...);
+extern char *hysdn_getrev(const char *);
+
+/* hysdn_procconf.c */
+extern int hysdn_procconf_init(void);	/* init proc config filesys */
+extern void hysdn_procconf_release(void);	/* deinit proc config filesys */
+
+/* hysdn_proclog.c */
+extern int hysdn_proclog_init(hysdn_card *);	/* init proc log entry */
+extern void hysdn_proclog_release(hysdn_card *);	/* deinit proc log entry */
+extern void put_log_buffer(hysdn_card *, char *);	/* output log data */
+extern void hysdn_addlog(hysdn_card *, char *,...);	/* output data to log */
+extern void hysdn_card_errlog(hysdn_card *, tErrLogEntry *, int);	/* output card log */
+
+/* boardergo.c */
+extern int ergo_inithardware(hysdn_card * card);	/* get hardware -> module init */
+
+/* hysdn_boot.c */
+extern int pof_write_close(hysdn_card *);	/* close proc file after writing pof */
+extern int pof_write_open(hysdn_card *, uchar **);	/* open proc file for writing pof */
+extern int pof_write_buffer(hysdn_card *, int);		/* write boot data to card */
+extern int EvalSysrTokData(hysdn_card *, uchar *, int);		/* Check Sysready Token Data */
+
+/* hysdn_sched.c */
+extern int hysdn_sched_tx(hysdn_card *, uchar *, word volatile *, word volatile *,
+			  word);
+extern int hysdn_sched_rx(hysdn_card *, uchar *, word, word);
+extern int hysdn_tx_cfgline(hysdn_card *, uchar *, word);	/* send one cfg line */
+
+/* hysdn_net.c */
+extern char *hysdn_net_revision;
+extern int hysdn_net_create(hysdn_card *);	/* create a new net device */
+extern int hysdn_net_release(hysdn_card *);	/* delete the device */
+extern char *hysdn_net_getname(hysdn_card *);	/* get name of net interface */
+extern void hysdn_tx_netack(hysdn_card *);	/* acknowledge a packet tx */
+extern struct sk_buff *hysdn_tx_netget(hysdn_card *);	/* get next network packet */
+extern void hysdn_rx_netpkt(hysdn_card *, uchar *, word);	/* rxed packet from network */
+
+#ifdef CONFIG_HYSDN_CAPI
+extern struct capi_driver_interface *hy_di;
+extern int hycapi_capi_create(hysdn_card *);	/* create a new capi device */
+extern int hycapi_capi_release(hysdn_card *);	/* delete the device */
+extern int hycapi_capi_stop(hysdn_card *card);   /* suspend */
+extern int hycapi_load_firmware(struct capi_ctr *, capiloaddata *);
+extern void hycapi_reset_ctr(struct capi_ctr *);
+extern void hycapi_remove_ctr(struct capi_ctr *);
+extern void hycapi_register_appl(struct capi_ctr *, __u16 appl,
+				 capi_register_params *);
+extern void hycapi_release_appl(struct capi_ctr *, __u16 appl);
+extern void hycapi_send_message(struct capi_ctr *, struct sk_buff *skb);
+extern char *hycapi_procinfo(struct capi_ctr *);
+extern int hycapi_read_proc(char *page, char **start, off_t off,
+			    int count, int *eof, struct capi_ctr *card);
+extern void hycapi_rx_capipkt(hysdn_card * card, uchar * buf, word len);
+extern void hycapi_tx_capiack(hysdn_card * card);
+extern struct sk_buff *hycapi_tx_capiget(hysdn_card *card);
+extern int hycapi_init(void);
+extern void hycapi_cleanup(void);
+#endif /* CONFIG_HYSDN_CAPI */
+
+#endif /* HYSDN_DEFS_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hysdn/hysdn_init.c linux.19p18/drivers/isdn/hysdn/hysdn_init.c
--- linux.vanilla/drivers/isdn/hysdn/hysdn_init.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/hysdn/hysdn_init.c	Tue Feb 13 18:49:43 2001
@@ -0,0 +1,257 @@
+/* $Id: hysdn_init.c,v 1.6.6.4 2001/02/10 14:41:22 kai Exp $
+
+ * Linux driver for HYSDN cards, init functions.
+ * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
+ *
+ * Copyright 1999  by Werner Cornelius (werner@titro.de)
+ *
+ * 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, 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.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/poll.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+
+#include "hysdn_defs.h"
+
+static char *hysdn_init_revision = "$Revision: 1.6.6.4 $";
+int cardmax;			/* number of found cards */
+hysdn_card *card_root = NULL;	/* pointer to first card */
+
+/**********************************************/
+/* table assigning PCI-sub ids to board types */
+/* the last entry contains all 0              */
+/**********************************************/
+static struct {
+	word subid;		/* PCI sub id */
+	uchar cardtyp;		/* card type assigned */
+} pci_subid_map[] = {
+
+	{
+		PCI_SUBDEVICE_ID_HYPERCOPE_METRO, BD_METRO
+	},
+	{
+		PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2, BD_CHAMP2
+	},
+	{
+		PCI_SUBDEVICE_ID_HYPERCOPE_ERGO, BD_ERGO
+	},
+	{
+		PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO, BD_ERGO
+	},
+	{
+		0, 0
+	}			/* terminating entry */
+};
+
+
+/*********************************************************************/
+/* search_cards searches for available cards in the pci config data. */
+/* If a card is found, the card structure is allocated and the cards */
+/* ressources are reserved. cardmax is incremented.                  */
+/*********************************************************************/
+static void
+search_cards(void)
+{
+	struct pci_dev *akt_pcidev = NULL;
+	hysdn_card *card, *card_last;
+	int i;
+
+	card_root = NULL;
+	card_last = NULL;
+	while ((akt_pcidev = pci_find_device(PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
+					     akt_pcidev)) != NULL) {
+		if (pci_enable_device(akt_pcidev))
+			continue;
+
+		if (!(card = kmalloc(sizeof(hysdn_card), GFP_KERNEL))) {
+			printk(KERN_ERR "HYSDN: unable to alloc device mem \n");
+			return;
+		}
+		memset(card, 0, sizeof(hysdn_card));
+		card->myid = cardmax;	/* set own id */
+		card->bus = akt_pcidev->bus->number;
+		card->devfn = akt_pcidev->devfn;	/* slot + function */
+		pci_read_config_word(akt_pcidev, PCI_SUBSYSTEM_ID, &card->subsysid);
+		card->irq = akt_pcidev->irq;
+		card->iobase = akt_pcidev->base_address[ PCI_REG_PLX_IO_BASE] & PCI_BASE_ADDRESS_IO_MASK;
+		card->plxbase = akt_pcidev->base_address[ PCI_REG_PLX_MEM_BASE] & PCI_BASE_ADDRESS_MEM_MASK;
+		card->membase = akt_pcidev->base_address[ PCI_REG_MEMORY_BASE] & PCI_BASE_ADDRESS_MEM_MASK;
+		card->brdtype = BD_NONE;	/* unknown */
+		card->debug_flags = DEF_DEB_FLAGS;	/* set default debug */
+		card->faxchans = 0;	/* default no fax channels */
+		card->bchans = 2;	/* and 2 b-channels */
+		for (i = 0; pci_subid_map[i].subid; i++)
+			if (pci_subid_map[i].subid == card->subsysid) {
+				card->brdtype = pci_subid_map[i].cardtyp;
+				break;
+			}
+		if (card->brdtype != BD_NONE) {
+			if (ergo_inithardware(card)) {
+				printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase);
+				kfree(card);
+				continue;
+			}
+		} else {
+			printk(KERN_WARNING "HYSDN: unknown card id 0x%04x\n", card->subsysid);
+			kfree(card);	/* release mem */
+			continue;
+		}
+		cardmax++;
+		card->next = NULL;	/*end of chain */
+		if (card_last)
+			card_last->next = card;		/* pointer to next card */
+		else
+			card_root = card;
+		card_last = card;	/* new chain end */
+	}			/* device found */
+}				/* search_cards */
+
+/************************************************************************************/
+/* free_resources frees the acquired PCI resources and returns the allocated memory */
+/************************************************************************************/
+static void
+free_resources(void)
+{
+	hysdn_card *card;
+
+	while (card_root) {
+		card = card_root;
+		if (card->releasehardware)
+			card->releasehardware(card);	/* free all hardware resources */
+		card_root = card_root->next;	/* remove card from chain */
+		kfree(card);	/* return mem */
+
+	}			/* while card_root */
+}				/* free_resources */
+
+/**************************************************************************/
+/* stop_cards disables (hardware resets) all cards and disables interrupt */
+/**************************************************************************/
+static void
+stop_cards(void)
+{
+	hysdn_card *card;
+
+	card = card_root;	/* first in chain */
+	while (card) {
+		if (card->stopcard)
+			card->stopcard(card);
+		card = card->next;	/* remove card from chain */
+	}			/* while card */
+}				/* stop_cards */
+
+
+/****************************************************************************/
+/* The module startup and shutdown code. Only compiled when used as module. */
+/* Using the driver as module is always advisable, because the booting      */
+/* image becomes smaller and the driver code is only loaded when needed.    */
+/* Additionally newer versions may be activated without rebooting.          */
+/****************************************************************************/
+
+/******************************************************/
+/* extract revision number from string for log output */
+/******************************************************/
+char *
+hysdn_getrev(const char *revision)
+{
+	char *rev;
+	char *p;
+
+	if ((p = strchr(revision, ':'))) {
+		rev = p + 2;
+		p = strchr(rev, '$');
+		*--p = 0;
+	} else
+		rev = "???";
+	return rev;
+}
+
+
+/****************************************************************************/
+/* init_module is called once when the module is loaded to do all necessary */
+/* things like autodetect...                                                */
+/* If the return value of this function is 0 the init has been successfull  */
+/* and the module is added to the list in /proc/modules, otherwise an error */
+/* is assumed and the module will not be kept in memory.                    */
+/****************************************************************************/
+static int __init
+hysdn_init(void)
+{
+	char tmp[50];
+
+	strcpy(tmp, hysdn_init_revision);
+	printk(KERN_NOTICE "HYSDN: module Rev: %s loaded\n", hysdn_getrev(tmp));
+	strcpy(tmp, hysdn_net_revision);
+	printk(KERN_NOTICE "HYSDN: network interface Rev: %s \n", hysdn_getrev(tmp));
+	if (!pci_present()) {
+		printk(KERN_ERR "HYSDN: no PCI bus present, module not loaded\n");
+		return (-1);
+	}
+	search_cards();
+	printk(KERN_INFO "HYSDN: %d card(s) found.\n", cardmax);
+
+	if (hysdn_procconf_init()) {
+		free_resources();	/* proc file_sys not created */
+		return (-1);
+	}
+#ifdef CONFIG_HYSDN_CAPI
+	if(cardmax > 0) {
+		if(hycapi_init()) {
+			printk(KERN_ERR "HYCAPI: init failed\n");
+			return(-1);
+		}
+	}
+#endif /* CONFIG_HYSDN_CAPI */
+	return (0);		/* no error */
+}				/* init_module */
+
+
+/***********************************************************************/
+/* cleanup_module is called when the module is released by the kernel. */
+/* The routine is only called if init_module has been successfull and  */
+/* the module counter has a value of 0. Otherwise this function will   */
+/* not be called. This function must release all resources still allo- */
+/* cated as after the return from this function the module code will   */
+/* be removed from memory.                                             */
+/***********************************************************************/
+static void 
+hysdn_exit(void)
+{
+#ifdef CONFIG_HYSDN_CAPI
+	hysdn_card *card;
+#endif /* CONFIG_HYSDN_CAPI */
+	stop_cards();
+#ifdef CONFIG_HYSDN_CAPI
+	card = card_root;	/* first in chain */
+	while (card) {
+		hycapi_capi_release(card);
+		card = card->next;	/* remove card from chain */
+	}			/* while card */
+	hycapi_cleanup();
+#endif /* CONFIG_HYSDN_CAPI */
+	hysdn_procconf_release();
+	free_resources();
+	printk(KERN_NOTICE "HYSDN: module unloaded\n");
+}				/* cleanup_module */
+
+module_init(hysdn_init);
+module_exit(hysdn_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hysdn/hysdn_net.c linux.19p18/drivers/isdn/hysdn/hysdn_net.c
--- linux.vanilla/drivers/isdn/hysdn/hysdn_net.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/hysdn/hysdn_net.c	Tue Feb 13 18:49:43 2001
@@ -0,0 +1,336 @@
+/* $Id: hysdn_net.c,v 1.8 2000/11/13 22:51:47 kai Exp $
+
+ * Linux driver for HYSDN cards, net (ethernet type) handling routines.
+ *
+ * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
+ *
+ * Copyright 1999  by Werner Cornelius (werner@titro.de)
+ *
+ * This net module has been inspired by the skeleton driver from
+ * Donald Becker (becker@CESDIS.gsfc.nasa.gov)
+ *
+ * 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, 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.
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/signal.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/inetdevice.h>
+
+#include "hysdn_defs.h"
+
+/* store the actual version for log reporting */
+char *hysdn_net_revision = "$Revision: 1.8 $";
+
+#define MAX_SKB_BUFFERS 20	/* number of buffers for keeping TX-data */
+
+/****************************************************************************/
+/* structure containing the complete network data. The structure is aligned */
+/* in a way that both, the device and statistics are kept inside it.        */
+/* for proper access, the device structure MUST be the first var/struct     */
+/* inside the definition.                                                   */
+/****************************************************************************/
+struct net_local {
+	struct device netdev;	/* the network device */
+	struct net_device_stats stats;
+	/* additional vars may be added here */
+	char dev_name[9];	/* our own device name */
+
+	struct sk_buff *tx_skb;	/* buffer for tx operation */
+
+};				/* net_local */
+
+
+/*****************************************************/
+/* Get the current statistics for this card.         */
+/* This may be called with the card open or closed ! */
+/*****************************************************/
+static struct net_device_stats *
+net_get_stats(struct device *dev)
+{
+	return (&((struct net_local *) dev)->stats);
+}				/* net_device_stats */
+
+/*********************************************************************/
+/* Open/initialize the board. This is called (in the current kernel) */
+/* sometime after booting when the 'ifconfig' program is run.        */
+/* This routine should set everything up anew at each open, even     */
+/* registers that "should" only need to be set once at boot, so that */
+/* there is non-reboot way to recover if something goes wrong.       */
+/*********************************************************************/
+static int
+net_open(struct device *dev)
+{
+	struct in_device *in_dev;
+	hysdn_card *card = dev->priv;
+	int i;
+
+	dev->tbusy = 0;		/* non busy state */
+	dev->interrupt = 0;
+	if (!dev->start)
+		MOD_INC_USE_COUNT;	/* increment only if device is down */
+	dev->start = 1;		/* and started */
+
+	/* Fill in the MAC-level header (if not already set) */
+	if (!card->mac_addr[0]) {
+		for (i = 0; i < ETH_ALEN - sizeof(ulong); i++)
+			dev->dev_addr[i] = 0xfc;
+		if ((in_dev = dev->ip_ptr) != NULL) {
+			struct in_ifaddr *ifa = in_dev->ifa_list;
+			if (ifa != NULL)
+				memcpy(dev->dev_addr + (ETH_ALEN - sizeof(ulong)), &ifa->ifa_local, sizeof(ulong));
+		}
+	} else
+		memcpy(dev->dev_addr, card->mac_addr, ETH_ALEN);
+
+	return (0);
+}				/* net_open */
+
+
+
+/*********************************************************************/
+/* close/decativate the device. The device is not removed, but only  */
+/* deactivated.                                                      */
+/*********************************************************************/
+static int
+net_close(struct device *dev)
+{
+
+	dev->tbusy = 1;		/* we are busy */
+
+	if (dev->start)
+		MOD_DEC_USE_COUNT;	/* dec only if device has been active */
+
+	dev->start = 0;		/* and not started */
+
+	return (0);		/* success */
+}				/* net_close */
+
+/************************************/
+/* send a packet on this interface. */
+/* only for kernel versions < 2.3.33 */
+/************************************/
+static int
+net_send_packet(struct sk_buff *skb, struct device *dev)
+{
+	struct net_local *lp = (struct net_local *) dev;
+
+	if (dev->tbusy) {
+		/*
+		 * If we get here, some higher level has decided we are broken.
+		 * There should really be a "kick me" function call instead.
+		 * As ISDN may have higher timeouts than real ethernet 10s timeout
+		 */
+		int tickssofar = jiffies - dev->trans_start;
+		if (tickssofar < (10000 * HZ) / 1000)
+			return 1;
+		printk(KERN_WARNING "%s: transmit timed out. \n", dev->name);
+		dev->tbusy = 0;
+		dev->trans_start = jiffies;
+	}
+	/*
+	 * Block a timer-based transmit from overlapping. This could better be
+	 * done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
+	 */
+	if (test_and_set_bit(0, (void *) &dev->tbusy) != 0)
+		printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
+
+	else {
+		lp->stats.tx_bytes += skb->len;
+		dev->trans_start = jiffies;
+		lp->tx_skb = skb;	/* remember skb pointer */
+		queue_task(&((hysdn_card *) dev->priv)->irq_queue, &tq_immediate);
+		mark_bh(IMMEDIATE_BH);
+	}
+
+	return (0);		/* success */
+}				/* net_send_packet */
+
+
+
+/***********************************************************************/
+/* acknowlegde a packet send. The network layer will be informed about */
+/* completion                                                          */
+/***********************************************************************/
+void
+hysdn_tx_netack(hysdn_card * card)
+{
+	struct net_local *lp = card->netif;
+
+	if (!lp)
+		return;		/* non existing device */
+
+	if (lp->tx_skb)
+		dev_kfree_skb(lp->tx_skb);	/* free tx pointer */
+	lp->tx_skb = NULL;	/* reset pointer */
+
+	lp->stats.tx_packets++;
+	lp->netdev.tbusy = 0;
+	mark_bh(NET_BH);	/* Inform upper layers. */
+}				/* hysdn_tx_netack */
+
+/*****************************************************/
+/* we got a packet from the network, go and queue it */
+/*****************************************************/
+void
+hysdn_rx_netpkt(hysdn_card * card, uchar * buf, word len)
+{
+	struct net_local *lp = card->netif;
+	struct sk_buff *skb;
+
+	if (!lp)
+		return;		/* non existing device */
+
+	lp->stats.rx_bytes += len;
+
+	skb = dev_alloc_skb(len);
+	if (skb == NULL) {
+		printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
+		       lp->netdev.name);
+		lp->stats.rx_dropped++;
+		return;
+	}
+	skb->dev = &lp->netdev;
+
+	/* copy the data */
+	memcpy(skb_put(skb, len), buf, len);
+
+	/* determine the used protocol */
+	skb->protocol = eth_type_trans(skb, &lp->netdev);
+
+	netif_rx(skb);
+	lp->stats.rx_packets++;	/* adjust packet count */
+
+}				/* hysdn_rx_netpkt */
+
+/*****************************************************/
+/* return the pointer to a network packet to be send */
+/*****************************************************/
+struct sk_buff *
+hysdn_tx_netget(hysdn_card * card)
+{
+	struct net_local *lp = card->netif;
+
+	if (!lp)
+		return (NULL);	/* non existing device */
+
+	return (lp->tx_skb);	/* return packet pointer */
+
+}				/* hysdn_tx_netget */
+
+
+/*******************************************/
+/* init function called by register device */
+/*******************************************/
+static int
+net_init(struct device *dev)
+{
+	/* setup the function table */
+	dev->open = net_open;
+	dev->stop = net_close;
+	dev->hard_start_xmit = net_send_packet;
+	dev->get_stats = net_get_stats;
+
+	/* Fill in the fields of the device structure with ethernet values. */
+	ether_setup(dev);
+
+	return (0);		/* success */
+}				/* net_init */
+
+/*****************************************************************************/
+/* hysdn_net_create creates a new net device for the given card. If a device */
+/* already exists, it will be deleted and created a new one. The return value */
+/* 0 announces success, else a negative error code will be returned.         */
+/*****************************************************************************/
+int
+hysdn_net_create(hysdn_card * card)
+{
+	struct device *dev;
+	int i;
+	if(!card) {
+		printk(KERN_WARNING "No card-pt in hysdn_net_create!\n");
+		return (-ENOMEM);
+	}
+	hysdn_net_release(card);	/* release an existing net device */
+	if ((dev = kmalloc(sizeof(struct net_local), GFP_KERNEL)) == NULL) {
+		printk(KERN_WARNING "HYSDN: unable to allocate mem\n");
+		if (card->debug_flags & LOG_NET_INIT)
+			return (-ENOMEM);
+	}
+	memset(dev, 0, sizeof(struct net_local));	/* clean the structure */
+
+
+	/* initialise necessary or informing fields */
+	dev->base_addr = card->iobase;	/* IO address */
+	dev->irq = card->irq;	/* irq */
+	dev->init = net_init;	/* the init function of the device */
+	dev->name = ((struct net_local *) dev)->dev_name;	/* device name */
+	if ((i = register_netdev(dev))) {
+		printk(KERN_WARNING "HYSDN: unable to create network device\n");
+		kfree(dev);
+		return (i);
+	}
+	dev->priv = card;	/* remember pointer to own data structure */
+	card->netif = dev;	/* setup the local pointer */
+
+	if (card->debug_flags & LOG_NET_INIT)
+		hysdn_addlog(card, "network device created");
+	return (0);		/* and return success */
+}				/* hysdn_net_create */
+
+/***************************************************************************/
+/* hysdn_net_release deletes the net device for the given card. The return */
+/* value 0 announces success, else a negative error code will be returned. */
+/***************************************************************************/
+int
+hysdn_net_release(hysdn_card * card)
+{
+	struct device *dev = card->netif;
+
+	if (!dev)
+		return (0);	/* non existing */
+
+	card->netif = NULL;	/* clear out pointer */
+	dev->stop(dev);		/* close the device */
+
+
+	unregister_netdev(dev);	/* release the device */
+	kfree(dev);		/* release the memory allocated */
+	if (card->debug_flags & LOG_NET_INIT)
+		hysdn_addlog(card, "network device deleted");
+
+	return (0);		/* always successfull */
+}				/* hysdn_net_release */
+
+/*****************************************************************************/
+/* hysdn_net_getname returns a pointer to the name of the network interface. */
+/* if the interface is not existing, a "-" is returned.                      */
+/*****************************************************************************/
+char *
+hysdn_net_getname(hysdn_card * card)
+{
+	struct device *dev = card->netif;
+
+	if (!dev)
+		return ("-");	/* non existing */
+
+	return (dev->name);
+}				/* hysdn_net_getname */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hysdn/hysdn_pof.h linux.19p18/drivers/isdn/hysdn/hysdn_pof.h
--- linux.vanilla/drivers/isdn/hysdn/hysdn_pof.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/hysdn/hysdn_pof.h	Tue Feb 13 18:49:43 2001
@@ -0,0 +1,89 @@
+/* $Id: hysdn_pof.h,v 1.2 2000/11/13 22:51:47 kai Exp $
+
+ * Linux driver for HYSDN cards, definitions used for handling pof-files.
+ * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
+ *
+ * Copyright 1999  by Werner Cornelius (werner@titro.de)
+ *
+ * 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, 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.
+ *
+ */
+
+/************************/
+/* POF specific defines */
+/************************/
+#define BOOT_BUF_SIZE   0x1000	/* =4096, maybe moved to other h file */
+#define CRYPT_FEEDTERM  0x8142
+#define CRYPT_STARTTERM 0x81a5
+				    /*  max. timeout time in seconds
+				     *  from end of booting to POF is ready
+				     */
+#define POF_READY_TIME_OUT_SEC  10
+
+/**********************************/
+/* defines for 1.stage boot image */
+/**********************************/
+
+/*  the POF file record containing the boot loader image
+ *  has 2 pages a 16KB:
+ *  1. page contains the high 16-bit part of the 32-bit E1 words
+ *  2. page contains the low  16-bit part of the 32-bit E1 words
+ *
+ *  In each 16KB page we assume the start of the boot loader code
+ *  in the highest 2KB part (at offset 0x3800);
+ *  the rest (0x0000..0x37FF) is assumed to contain 0 bytes.
+ */
+
+#define POF_BOOT_LOADER_PAGE_SIZE   0x4000	/* =16384U */
+#define POF_BOOT_LOADER_TOTAL_SIZE  (2U*POF_BOOT_LOADER_PAGE_SIZE)
+
+#define POF_BOOT_LOADER_CODE_SIZE   0x0800	/* =2KB =2048U */
+
+		    /* offset in boot page, where loader code may start */
+					    /* =0x3800= 14336U */
+#define POF_BOOT_LOADER_OFF_IN_PAGE (POF_BOOT_LOADER_PAGE_SIZE-POF_BOOT_LOADER_CODE_SIZE)
+
+
+/*--------------------------------------POF file record structs------------*/
+typedef struct PofFileHdr_tag {	/* Pof file header */
+/*00 */ ulong Magic __attribute__((packed));
+/*04 */ ulong N_PofRecs __attribute__((packed));
+/*08 */
+} tPofFileHdr;
+
+typedef struct PofRecHdr_tag {	/* Pof record header */
+/*00 */ word PofRecId __attribute__((packed));
+/*02 */ ulong PofRecDataLen __attribute__((packed));
+/*06 */
+} tPofRecHdr;
+
+typedef struct PofTimeStamp_tag {
+/*00 */ ulong UnixTime __attribute__((packed));
+	/*04 */ uchar DateTimeText[0x28] __attribute__((packed));
+	/* =40 */
+/*2C */
+} tPofTimeStamp;
+
+				    /* tPofFileHdr.Magic value: */
+#define TAGFILEMAGIC 0x464F501AUL
+				    /* tPofRecHdr.PofRecId values: */
+#define TAG_ABSDATA  0x1000	/* abs. data */
+#define TAG_BOOTDTA  0x1001	/* boot data */
+#define TAG_COMMENT  0x0020
+#define TAG_SYSCALL  0x0021
+#define TAG_FLOWCTRL 0x0022
+#define TAG_TIMESTMP 0x0010	/* date/time stamp of version */
+#define TAG_CABSDATA 0x1100	/* crypted abs. data */
+#define TAG_CBOOTDTA 0x1101	/* crypted boot data */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hysdn/hysdn_procconf.c linux.19p18/drivers/isdn/hysdn/hysdn_procconf.c
--- linux.vanilla/drivers/isdn/hysdn/hysdn_procconf.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/hysdn/hysdn_procconf.c	Tue Feb 13 18:49:43 2001
@@ -0,0 +1,467 @@
+/* $Id: hysdn_procconf.c,v 1.8 2000/11/13 22:51:47 kai Exp $
+
+ * Linux driver for HYSDN cards, /proc/net filesystem dir and conf functions.
+ * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
+ *
+ * Copyright 1999  by Werner Cornelius (werner@titro.de)
+ *
+ * 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, 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.
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/pci.h>
+
+#include "hysdn_defs.h"
+
+static char *hysdn_procconf_revision = "$Revision: 1.8 $";
+
+#define INFO_OUT_LEN 80		/* length of info line including lf */
+
+/********************************************************/
+/* defines and data structure for conf write operations */
+/********************************************************/
+#define CONF_STATE_DETECT 0	/* waiting for detect */
+#define CONF_STATE_CONF   1	/* writing config data */
+#define CONF_STATE_POF    2	/* writing pof data */
+#define CONF_LINE_LEN    80	/* 80 chars max */
+
+struct conf_writedata {
+	hysdn_card *card;	/* card the device is connected to */
+	int buf_size;		/* actual number of bytes in the buffer */
+	int needed_size;	/* needed size when reading pof */
+	int state;		/* actual interface states from above constants */
+	uchar conf_line[CONF_LINE_LEN];		/* buffered conf line */
+	word channel;		/* active channel number */
+	uchar *pof_buffer;	/* buffer when writing pof */
+};
+
+/***********************************************************************/
+/* process_line parses one config line and transfers it to the card if */
+/* necessary.                                                          */
+/* if the return value is negative an error occured.                   */
+/***********************************************************************/
+static int
+process_line(struct conf_writedata *cnf)
+{
+	uchar *cp = cnf->conf_line;
+	int i;
+
+	if (cnf->card->debug_flags & LOG_CNF_LINE)
+		hysdn_addlog(cnf->card, "conf line: %s", cp);
+
+	if (*cp == '-') {	/* option */
+		cp++;		/* point to option char */
+
+		if (*cp++ != 'c')
+			return (0);	/* option unknown or used */
+		i = 0;		/* start value for channel */
+		while ((*cp <= '9') && (*cp >= '0'))
+			i = i * 10 + *cp++ - '0';	/* get decimal number */
+		if (i > 65535) {
+			if (cnf->card->debug_flags & LOG_CNF_MISC)
+				hysdn_addlog(cnf->card, "conf channel invalid  %d", i);
+			return (-ERR_INV_CHAN);		/* invalid channel */
+		}
+		cnf->channel = i & 0xFFFF;	/* set new channel number */
+		return (0);	/* success */
+	}			/* option */
+	if (*cp == '*') {	/* line to send */
+		if (cnf->card->debug_flags & LOG_CNF_DATA)
+			hysdn_addlog(cnf->card, "conf chan=%d %s", cnf->channel, cp);
+		return (hysdn_tx_cfgline(cnf->card, cnf->conf_line + 1,
+					 cnf->channel));	/* send the line without * */
+	}			/* line to send */
+	return (0);
+}				/* process_line */
+
+/*************************/
+/* dummy file operations */
+/*************************/
+static loff_t
+hysdn_dummy_lseek(struct file *file, loff_t offset, int orig)
+{
+	return -ESPIPE;
+}				/* hysdn_dummy_lseek */
+
+/***********************************/
+/* conf file operations and tables */
+/***********************************/
+
+/****************************************************/
+/* write conf file -> boot or send cfg line to card */
+/****************************************************/
+static ssize_t
+hysdn_conf_write(struct file *file, const char *buf, size_t count, loff_t * off)
+{
+	struct conf_writedata *cnf;
+	int i;
+	uchar ch, *cp;
+
+	if (&file->f_pos != off)	/* fs error check */
+		return (-ESPIPE);
+	if (!count)
+		return (0);	/* nothing to handle */
+
+	if (!(cnf = file->private_data))
+		return (-EFAULT);	/* should never happen */
+
+	if (cnf->state == CONF_STATE_DETECT) {	/* auto detect cnf or pof data */
+		if (copy_from_user(&ch, buf, 1))	/* get first char for detect */
+			return (-EFAULT);
+
+		if (ch == 0x1A) {
+			/* we detected a pof file */
+			if ((cnf->needed_size = pof_write_open(cnf->card, &cnf->pof_buffer)) <= 0)
+				return (cnf->needed_size);	/* an error occured -> exit */
+			cnf->buf_size = 0;	/* buffer is empty */
+			cnf->state = CONF_STATE_POF;	/* new state */
+		} else {
+			/* conf data has been detected */
+			cnf->buf_size = 0;	/* buffer is empty */
+			cnf->state = CONF_STATE_CONF;	/* requested conf data write */
+			if (cnf->card->state != CARD_STATE_RUN)
+				return (-ERR_NOT_BOOTED);
+			cnf->conf_line[CONF_LINE_LEN - 1] = 0;	/* limit string length */
+			cnf->channel = 4098;	/* default channel for output */
+		}
+	}			/* state was auto detect */
+	if (cnf->state == CONF_STATE_POF) {	/* pof write active */
+		i = cnf->needed_size - cnf->buf_size;	/* bytes still missing for write */
+		if (i <= 0)
+			return (-EINVAL);	/* size error handling pof */
+
+		if (i < count)
+			count = i;	/* limit requested number of bytes */
+		if (copy_from_user(cnf->pof_buffer + cnf->buf_size, buf, count))
+			return (-EFAULT);	/* error while copying */
+		cnf->buf_size += count;
+
+		if (cnf->needed_size == cnf->buf_size) {
+			cnf->needed_size = pof_write_buffer(cnf->card, cnf->buf_size);	/* write data */
+			if (cnf->needed_size <= 0) {
+				cnf->card->state = CARD_STATE_BOOTERR;	/* show boot error */
+				return (cnf->needed_size);	/* an error occured */
+			}
+			cnf->buf_size = 0;	/* buffer is empty again */
+		}
+	}
+	/* pof write active */
+	else {			/* conf write active */
+
+		if (cnf->card->state != CARD_STATE_RUN) {
+			if (cnf->card->debug_flags & LOG_CNF_MISC)
+				hysdn_addlog(cnf->card, "cnf write denied -> not booted");
+			return (-ERR_NOT_BOOTED);
+		}
+		i = (CONF_LINE_LEN - 1) - cnf->buf_size;	/* bytes available in buffer */
+		if (i > 0) {
+			/* copy remaining bytes into buffer */
+
+			if (count > i)
+				count = i;	/* limit transfer */
+			if (copy_from_user(cnf->conf_line + cnf->buf_size, buf, count))
+				return (-EFAULT);	/* error while copying */
+
+			i = count;	/* number of chars in buffer */
+			cp = cnf->conf_line + cnf->buf_size;
+			while (i) {
+				/* search for end of line */
+				if ((*cp < ' ') && (*cp != 9))
+					break;	/* end of line found */
+				cp++;
+				i--;
+			}	/* search for end of line */
+
+			if (i) {
+				/* delimiter found */
+				*cp++ = 0;	/* string termination */
+				count -= (i - 1);	/* subtract remaining bytes from count */
+				while ((i) && (*cp < ' ') && (*cp != 9)) {
+					i--;	/* discard next char */
+					count++;	/* mark as read */
+					cp++;	/* next char */
+				}
+				cnf->buf_size = 0;	/* buffer is empty after transfer */
+				if ((i = process_line(cnf)) < 0)	/* handle the line */
+					count = i;	/* return the error */
+			}
+			/* delimiter found */
+			else {
+				cnf->buf_size += count;		/* add chars to string */
+				if (cnf->buf_size >= CONF_LINE_LEN - 1) {
+					if (cnf->card->debug_flags & LOG_CNF_MISC)
+						hysdn_addlog(cnf->card, "cnf line too long %d chars pos %d", cnf->buf_size, count);
+					return (-ERR_CONF_LONG);
+				}
+			}	/* not delimited */
+
+		}
+		/* copy remaining bytes into buffer */
+		else {
+			if (cnf->card->debug_flags & LOG_CNF_MISC)
+				hysdn_addlog(cnf->card, "cnf line too long");
+			return (-ERR_CONF_LONG);
+		}
+	}			/* conf write active */
+
+	return (count);
+}				/* hysdn_conf_write */
+
+/*******************************************/
+/* read conf file -> output card info data */
+/*******************************************/
+static ssize_t
+hysdn_conf_read(struct file *file, char *buf, size_t count, loff_t * off)
+{
+	char *cp;
+	int i;
+
+	if (off != &file->f_pos)	/* fs error check */
+		return -ESPIPE;
+
+	if (file->f_mode & FMODE_READ) {
+		if (!(cp = file->private_data))
+			return (-EFAULT);	/* should never happen */
+		i = strlen(cp);	/* get total string length */
+		if (*off < i) {
+			/* still bytes to transfer */
+			cp += *off;	/* point to desired data offset */
+			i -= *off;	/* remaining length */
+			if (i > count)
+				i = count;	/* limit length to transfer */
+			if (copy_to_user(buf, cp, i))
+				return (-EFAULT);	/* copy error */
+			*off += i;	/* adjust offset */
+		} else
+			return (0);
+	} else
+		return (-EPERM);	/* no permission to read */
+
+	return (i);
+}				/* hysdn_conf_read */
+
+/******************/
+/* open conf file */
+/******************/
+static int
+hysdn_conf_open(struct inode *ino, struct file *filep)
+{
+	hysdn_card *card;
+	struct proc_dir_entry *pd;
+	struct conf_writedata *cnf;
+	char *cp, *tmp;
+
+	/* now search the addressed card */
+	MOD_INC_USE_COUNT;
+	card = card_root;
+	while (card) {
+		pd = card->procconf;
+		if (pd->low_ino == (ino->i_ino & 0xFFFF))
+			break;
+		card = card->next;	/* search next entry */
+	}
+	if (!card) {
+		MOD_DEC_USE_COUNT;
+		return (-ENODEV);	/* device is unknown/invalid */
+	}
+	if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL))
+		hysdn_addlog(card, "config open for uid=%d gid=%d mode=0x%x",
+			     filep->f_uid, filep->f_gid, filep->f_mode);
+
+	if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
+		/* write only access -> write boot file or conf line */
+
+		if (!(cnf = kmalloc(sizeof(struct conf_writedata), GFP_KERNEL))) {
+			MOD_DEC_USE_COUNT;
+			return (-EFAULT);
+		}
+		cnf->card = card;
+		cnf->buf_size = 0;	/* nothing buffered */
+		cnf->state = CONF_STATE_DETECT;		/* start auto detect */
+		filep->private_data = cnf;
+
+	} else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
+		/* read access -> output card info data */
+
+		if (!(tmp = (char *) kmalloc(INFO_OUT_LEN * 2 + 2, GFP_KERNEL))) {
+			MOD_DEC_USE_COUNT;
+			return (-EFAULT);	/* out of memory */
+		}
+		filep->private_data = tmp;	/* start of string */
+
+		/* first output a headline */
+		sprintf(tmp, "id bus slot type irq iobase dp-mem     b-chans fax-chans state device");
+		cp = tmp;	/* start of string */
+		while (*cp)
+			cp++;
+		while (((cp - tmp) % (INFO_OUT_LEN + 1)) != INFO_OUT_LEN)
+			*cp++ = ' ';
+		*cp++ = '\n';
+
+		/* and now the data */
+		sprintf(cp, "%d  %3d %4d %4d %3d 0x%04x 0x%08lx %7d %9d %3d   %s",
+			card->myid,
+			card->bus,
+			PCI_SLOT(card->devfn),
+			card->brdtype,
+			card->irq,
+			card->iobase,
+			card->membase,
+			card->bchans,
+			card->faxchans,
+			card->state,
+			hysdn_net_getname(card));
+		while (*cp)
+			cp++;
+		while (((cp - tmp) % (INFO_OUT_LEN + 1)) != INFO_OUT_LEN)
+			*cp++ = ' ';
+		*cp++ = '\n';
+		*cp = 0;	/* end of string */
+	} else {		/* simultaneous read/write access forbidden ! */
+		MOD_DEC_USE_COUNT;
+		return (-EPERM);	/* no permission this time */
+	}
+	return (0);
+}				/* hysdn_conf_open */
+
+/***************************/
+/* close a config file.    */
+/***************************/
+static int
+hysdn_conf_close(struct inode *ino, struct file *filep)
+{
+	hysdn_card *card;
+	struct conf_writedata *cnf;
+	int retval = 0;
+	struct proc_dir_entry *pd;
+
+	/* search the addressed card */
+	card = card_root;
+	while (card) {
+		pd = card->procconf;
+		if (pd->low_ino == (ino->i_ino & 0xFFFF))
+			break;
+		card = card->next;	/* search next entry */
+	}
+	if (!card) {
+		return (-ENODEV);	/* device is unknown/invalid */
+	}
+	if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL))
+		hysdn_addlog(card, "config close for uid=%d gid=%d mode=0x%x",
+			     filep->f_uid, filep->f_gid, filep->f_mode);
+
+	if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
+		/* write only access -> write boot file or conf line */
+		if (filep->private_data) {
+			cnf = filep->private_data;
+
+			if (cnf->state == CONF_STATE_POF)
+				retval = pof_write_close(cnf->card);	/* close the pof write */
+			kfree(filep->private_data);	/* free allocated memory for buffer */
+
+		}		/* handle write private data */
+	} else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
+		/* read access -> output card info data */
+
+		if (filep->private_data)
+			kfree(filep->private_data);	/* release memory */
+	}
+	MOD_DEC_USE_COUNT;
+	return (retval);
+}				/* hysdn_conf_close */
+
+/******************************************************/
+/* table for conf filesystem functions defined above. */
+/******************************************************/
+static struct file_operations conf_fops =
+{
+	llseek:         hysdn_dummy_lseek,
+	read:           hysdn_conf_read,
+	write:          hysdn_conf_write,
+	open:           hysdn_conf_open,
+	release:        hysdn_conf_close,                                       
+};
+
+static struct inode_operations conf_inode_operations;
+/*****************************/
+/* hysdn subdir in /proc/net */
+/*****************************/
+struct proc_dir_entry *hysdn_proc_entry = NULL;
+
+/*******************************************************************************/
+/* hysdn_procconf_init is called when the module is loaded and after the cards */
+/* have been detected. The needed proc dir and card config files are created.  */
+/* The log init is called at last.                                             */
+/*******************************************************************************/
+int
+hysdn_procconf_init(void)
+{
+	hysdn_card *card;
+	uchar conf_name[20];
+
+	hysdn_proc_entry = create_proc_entry(PROC_SUBDIR_NAME, S_IFDIR | S_IRUGO | S_IXUGO, proc_net);
+	if (!hysdn_proc_entry) {
+		printk(KERN_ERR "HYSDN: unable to create hysdn subdir\n");
+		return (-1);
+	}
+	card = card_root;	/* point to first card */
+	while (card) {
+
+		sprintf(conf_name, "%s%d", PROC_CONF_BASENAME, card->myid);
+		if ((card->procconf = (void *) create_proc_entry(conf_name,
+					     S_IFREG | S_IRUGO | S_IWUSR,
+					    hysdn_proc_entry)) != NULL) {
+			memset(&conf_inode_operations, 0, sizeof(struct inode_operations));
+			conf_inode_operations.default_file_ops = &conf_fops;
+
+			((struct proc_dir_entry *) card->procconf)->ops = &conf_inode_operations;
+			hysdn_proclog_init(card);	/* init the log file entry */
+		}
+		card = card->next;	/* next entry */
+	}
+
+	printk(KERN_NOTICE "HYSDN: procfs Rev. %s initialised\n", hysdn_getrev(hysdn_procconf_revision));
+	return (0);
+}				/* hysdn_procconf_init */
+
+/*************************************************************************************/
+/* hysdn_procconf_release is called when the module is unloaded and before the cards */
+/* resources are released. The module counter is assumed to be 0 !                   */
+/*************************************************************************************/
+void
+hysdn_procconf_release(void)
+{
+	hysdn_card *card;
+	uchar conf_name[20];
+
+	card = card_root;	/* start with first card */
+	while (card) {
+
+		sprintf(conf_name, "%s%d", PROC_CONF_BASENAME, card->myid);
+		if (card->procconf)
+			remove_proc_entry(conf_name, hysdn_proc_entry);
+
+		hysdn_proclog_release(card);	/* init the log file entry */
+
+		card = card->next;	/* point to next card */
+	}
+
+	remove_proc_entry(PROC_SUBDIR_NAME, proc_net);
+}				/* hysdn_procfs_release */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hysdn/hysdn_proclog.c linux.19p18/drivers/isdn/hysdn/hysdn_proclog.c
--- linux.vanilla/drivers/isdn/hysdn/hysdn_proclog.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/hysdn/hysdn_proclog.c	Tue Feb 13 18:49:43 2001
@@ -0,0 +1,464 @@
+/* $Id: hysdn_proclog.c,v 1.9 2000/11/25 17:01:01 kai Exp $
+
+ * Linux driver for HYSDN cards, /proc/net filesystem log functions.
+ * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
+ *
+ * Copyright 1999  by Werner Cornelius (werner@titro.de)
+ *
+ * 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, 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.
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/poll.h>
+#include <linux/proc_fs.h>
+#include <linux/pci.h>
+
+#include "hysdn_defs.h"
+
+/* the proc subdir for the interface is defined in the procconf module */
+extern struct proc_dir_entry *hysdn_proc_entry;
+
+/*************************************************/
+/* structure keeping ascii log for device output */
+/*************************************************/
+struct log_data {
+	struct log_data *next;
+	ulong usage_cnt;	/* number of files still to work */
+	void *proc_ctrl;	/* pointer to own control procdata structure */
+	char log_start[2];	/* log string start (final len aligned by size) */
+};
+
+/**********************************************/
+/* structure holding proc entrys for one card */
+/**********************************************/
+struct procdata {
+	struct proc_dir_entry *log;	/* log entry */
+	char log_name[15];	/* log filename */
+	struct log_data *log_head, *log_tail;	/* head and tail for queue */
+	int if_used;		/* open count for interface */
+	int volatile del_lock;	/* lock for delete operations */
+	uchar logtmp[LOG_MAX_LINELEN];
+	wait_queue_head_t rd_queue;
+};
+
+
+/**********************************************/
+/* log function for cards error log interface */
+/**********************************************/
+void
+hysdn_card_errlog(hysdn_card * card, tErrLogEntry * logp, int maxsize)
+{
+	char buf[ERRLOG_TEXT_SIZE + 40];
+
+	sprintf(buf, "LOG 0x%08lX 0x%08lX : %s\n", logp->ulErrType, logp->ulErrSubtype, logp->ucText);
+	put_log_buffer(card, buf);	/* output the string */
+}				/* hysdn_card_errlog */
+
+/***************************************************/
+/* Log function using format specifiers for output */
+/***************************************************/
+void
+hysdn_addlog(hysdn_card * card, char *fmt,...)
+{
+	struct procdata *pd = card->proclog;
+	char *cp;
+	va_list args;
+
+	if (!pd)
+		return;		/* log structure non existent */
+
+	cp = pd->logtmp;
+	cp += sprintf(cp, "HYSDN: card %d ", card->myid);
+
+	va_start(args, fmt);
+	cp += vsprintf(cp, fmt, args);
+	va_end(args);
+	*cp++ = '\n';
+	*cp = 0;
+
+	if (card->debug_flags & DEB_OUT_SYSLOG)
+		printk(KERN_INFO "%s", pd->logtmp);
+	else
+		put_log_buffer(card, pd->logtmp);
+
+}				/* hysdn_addlog */
+
+/********************************************/
+/* put an log buffer into the log queue.    */
+/* This buffer will be kept until all files */
+/* opened for read got the contents.        */
+/* Flushes buffers not longer in use.       */
+/********************************************/
+void
+put_log_buffer(hysdn_card * card, char *cp)
+{
+	struct log_data *ib;
+	struct procdata *pd = card->proclog;
+	int i, flags;
+
+	if (!pd)
+		return;
+	if (!cp)
+		return;
+	if (!*cp)
+		return;
+	if (pd->if_used <= 0)
+		return;		/* no open file for read */
+
+	if (!(ib = (struct log_data *) kmalloc(sizeof(struct log_data) + strlen(cp), GFP_ATOMIC)))
+		 return;	/* no memory */
+	strcpy(ib->log_start, cp);	/* set output string */
+	ib->next = NULL;
+	ib->proc_ctrl = pd;	/* point to own control structure */
+	save_flags(flags);
+	cli();
+	ib->usage_cnt = pd->if_used;
+	if (!pd->log_head)
+		pd->log_head = ib;	/* new head */
+	else
+		pd->log_tail->next = ib;	/* follows existing messages */
+	pd->log_tail = ib;	/* new tail */
+	i = pd->del_lock++;	/* get lock state */
+	restore_flags(flags);
+
+	/* delete old entrys */
+	if (!i)
+		while (pd->log_head->next) {
+			if ((pd->log_head->usage_cnt <= 0) &&
+			    (pd->log_head->next->usage_cnt <= 0)) {
+				ib = pd->log_head;
+				pd->log_head = pd->log_head->next;
+				kfree(ib);
+			} else
+				break;
+		}		/* pd->log_head->next */
+	pd->del_lock--;		/* release lock level */
+	wake_up_interruptible(&(pd->rd_queue));		/* announce new entry */
+}				/* put_log_buffer */
+
+
+/*************************/
+/* dummy file operations */
+/*************************/
+static loff_t
+hysdn_dummy_lseek(struct file *file, loff_t offset, int orig)
+{
+	return -ESPIPE;
+}				/* hysdn_dummy_lseek */
+
+/******************************/
+/* file operations and tables */
+/******************************/
+
+/****************************************/
+/* write log file -> set log level bits */
+/****************************************/
+static ssize_t
+hysdn_log_write(struct file *file, const char *buf, size_t count, loff_t * off)
+{
+	ulong u = 0;
+	int found = 0;
+	uchar *cp, valbuf[128];
+	long base = 10;
+	hysdn_card *card = (hysdn_card *) file->private_data;
+
+	if (&file->f_pos != off)	/* fs error check */
+		return (-ESPIPE);
+
+	if (count > (sizeof(valbuf) - 1))
+		count = sizeof(valbuf) - 1;	/* limit length */
+	if (copy_from_user(valbuf, buf, count))
+		return (-EFAULT);	/* copy failed */
+
+	valbuf[count] = 0;	/* terminating 0 */
+	cp = valbuf;
+	if ((count > 2) && (valbuf[0] == '0') && (valbuf[1] == 'x')) {
+		cp += 2;	/* pointer after hex modifier */
+		base = 16;
+	}
+	/* scan the input for debug flags */
+	while (*cp) {
+		if ((*cp >= '0') && (*cp <= '9')) {
+			found = 1;
+			u *= base;	/* adjust to next digit */
+			u += *cp++ - '0';
+			continue;
+		}
+		if (base != 16)
+			break;	/* end of number */
+
+		if ((*cp >= 'a') && (*cp <= 'f')) {
+			found = 1;
+			u *= base;	/* adjust to next digit */
+			u += *cp++ - 'a' + 10;
+			continue;
+		}
+		break;		/* terminated */
+	}
+
+	if (found) {
+		card->debug_flags = u;	/* remember debug flags */
+		hysdn_addlog(card, "debug set to 0x%lx", card->debug_flags);
+	}
+	return (count);
+}				/* hysdn_log_write */
+
+/******************/
+/* read log file */
+/******************/
+static ssize_t
+hysdn_log_read(struct file *file, char *buf, size_t count, loff_t * off)
+{
+	struct log_data *inf;
+	int len;
+	word ino;
+	struct procdata *pd;
+	hysdn_card *card;
+
+	if (!*((struct log_data **) file->private_data)) {
+		if (file->f_flags & O_NONBLOCK)
+			return (-EAGAIN);
+
+		/* sorry, but we need to search the card */
+		ino = file->f_dentry->d_inode->i_ino & 0xFFFF;	/* low-ino */
+		card = card_root;
+		while (card) {
+			pd = card->proclog;
+			if (pd->log->low_ino == ino)
+				break;
+			card = card->next;	/* search next entry */
+		}
+		if (card)
+			interruptible_sleep_on(&(pd->rd_queue));
+		else
+			return (-EAGAIN);
+
+	}
+	if (!(inf = *((struct log_data **) file->private_data)))
+		return (0);
+
+	inf->usage_cnt--;	/* new usage count */
+	(struct log_data **) file->private_data = &inf->next;	/* next structure */
+	if ((len = strlen(inf->log_start)) <= count) {
+		if (copy_to_user(buf, inf->log_start, len))
+			return -EFAULT;
+		file->f_pos += len;
+		return (len);
+	}
+	return (0);
+}				/* hysdn_log_read */
+
+/******************/
+/* open log file */
+/******************/
+static int
+hysdn_log_open(struct inode *ino, struct file *filep)
+{
+	hysdn_card *card;
+	struct procdata *pd;
+	ulong flags;
+
+	MOD_INC_USE_COUNT;
+	card = card_root;
+	while (card) {
+		pd = card->proclog;
+		if (pd->log->low_ino == (ino->i_ino & 0xFFFF))
+			break;
+		card = card->next;	/* search next entry */
+	}
+	if (!card) {
+		MOD_DEC_USE_COUNT;
+		return (-ENODEV);	/* device is unknown/invalid */
+	}
+	filep->private_data = card;	/* remember our own card */
+
+	if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
+		/* write only access -> write log level only */
+	} else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
+
+		/* read access -> log/debug read */
+		save_flags(flags);
+		cli();
+		pd->if_used++;
+		if (pd->log_head)
+			(struct log_data **) filep->private_data = &(pd->log_tail->next);
+		else
+			(struct log_data **) filep->private_data = &(pd->log_head);
+		restore_flags(flags);
+	} else {		/* simultaneous read/write access forbidden ! */
+		MOD_DEC_USE_COUNT;
+		return (-EPERM);	/* no permission this time */
+	}
+	return (0);
+}				/* hysdn_log_open */
+
+/*******************************************************************************/
+/* close a cardlog file. If the file has been opened for exclusive write it is */
+/* assumed as pof data input and the pof loader is noticed about.              */
+/* Otherwise file is handled as log output. In this case the interface usage   */
+/* count is decremented and all buffers are noticed of closing. If this file   */
+/* was the last one to be closed, all buffers are freed.                       */
+/*******************************************************************************/
+static int
+hysdn_log_close(struct inode *ino, struct file *filep)
+{
+	struct log_data *inf;
+	struct procdata *pd;
+	hysdn_card *card;
+	int flags, retval = 0;
+
+
+	if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
+		/* write only access -> write debug level written */
+		retval = 0;	/* success */
+	} else {
+		/* read access -> log/debug read, mark one further file as closed */
+
+		pd = NULL;
+		save_flags(flags);
+		cli();
+		inf = *((struct log_data **) filep->private_data);	/* get first log entry */
+		if (inf)
+			pd = (struct procdata *) inf->proc_ctrl;	/* still entries there */
+		else {
+			/* no info available -> search card */
+			card = card_root;
+			while (card) {
+				pd = card->proclog;
+				if (pd->log->low_ino == (ino->i_ino & 0xFFFF))
+					break;
+				card = card->next;	/* search next entry */
+			}
+			if (card)
+				pd = card->proclog;	/* pointer to procfs log */
+		}
+		if (pd)
+			pd->if_used--;	/* decrement interface usage count by one */
+
+		while (inf) {
+			inf->usage_cnt--;	/* decrement usage count for buffers */
+			inf = inf->next;
+		}
+		restore_flags(flags);
+
+		if (pd)
+			if (pd->if_used <= 0)	/* delete buffers if last file closed */
+				while (pd->log_head) {
+					inf = pd->log_head;
+					pd->log_head = pd->log_head->next;
+					kfree(inf);
+				}
+	}			/* read access */
+	MOD_DEC_USE_COUNT;
+
+	return (retval);
+}				/* hysdn_log_close */
+
+/*************************************************/
+/* select/poll routine to be able using select() */
+/*************************************************/
+static unsigned int
+hysdn_log_poll(struct file *file, poll_table * wait)
+{
+	unsigned int mask = 0;
+	word ino;
+	hysdn_card *card;
+	struct procdata *pd;
+
+	if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE)
+		return (mask);	/* no polling for write supported */
+
+	/* we need to search the card */
+	ino = file->f_dentry->d_inode->i_ino & 0xFFFF;	/* low-ino */
+	card = card_root;
+	while (card) {
+		pd = card->proclog;
+		if (pd->log->low_ino == ino)
+			break;
+		card = card->next;	/* search next entry */
+	}
+	if (!card)
+		return (mask);	/* card not found */
+
+	poll_wait(file, &(pd->rd_queue), wait);
+
+	if (*((struct log_data **) file->private_data))
+		mask |= POLLIN | POLLRDNORM;
+
+	return mask;
+}				/* hysdn_log_poll */
+
+/**************************************************/
+/* table for log filesystem functions defined above. */
+/**************************************************/
+static struct file_operations log_fops =
+{
+	llseek:         hysdn_dummy_lseek,
+	read:           hysdn_log_read,
+	write:          hysdn_log_write,
+	poll:           hysdn_log_poll,
+	open:           hysdn_log_open,
+	release:        hysdn_log_close,                                        
+};
+
+struct inode_operations log_inode_operations;
+
+/***********************************************************************************/
+/* hysdn_proclog_init is called when the module is loaded after creating the cards */
+/* conf files.                                                                     */
+/***********************************************************************************/
+int
+hysdn_proclog_init(hysdn_card * card)
+{
+	struct procdata *pd;
+
+	/* create a cardlog proc entry */
+
+	if ((pd = (struct procdata *) kmalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) {
+		memset(pd, 0, sizeof(struct procdata));
+		memset(&log_inode_operations, 0, sizeof(struct inode_operations));
+		log_inode_operations.default_file_ops = &log_fops;
+		sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid);
+		if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL) {
+			pd->log->ops = &log_inode_operations;	/* set new operations table */
+		}
+
+		init_waitqueue_head(&(pd->rd_queue));
+
+		card->proclog = (void *) pd;	/* remember procfs structure */
+	}
+	return (0);
+}				/* hysdn_proclog_init */
+
+/************************************************************************************/
+/* hysdn_proclog_release is called when the module is unloaded and before the cards */
+/* conf file is released                                                            */
+/* The module counter is assumed to be 0 !                                          */
+/************************************************************************************/
+void
+hysdn_proclog_release(hysdn_card * card)
+{
+	struct procdata *pd;
+
+	if ((pd = (struct procdata *) card->proclog) != NULL) {
+		if (pd->log)
+			remove_proc_entry(pd->log_name, hysdn_proc_entry);
+		kfree(pd);	/* release memory */
+		card->proclog = NULL;
+	}
+}				/* hysdn_proclog_release */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hysdn/hysdn_sched.c linux.19p18/drivers/isdn/hysdn/hysdn_sched.c
--- linux.vanilla/drivers/isdn/hysdn/hysdn_sched.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/hysdn/hysdn_sched.c	Tue Feb 13 18:49:43 2001
@@ -0,0 +1,213 @@
+/* $Id: hysdn_sched.c,v 1.5 2000/11/22 17:13:13 kai Exp $
+
+ * Linux driver for HYSDN cards, scheduler routines for handling exchange card <-> pc.
+ *
+ * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
+ *
+ * Copyright 1999  by Werner Cornelius (werner@titro.de)
+ *
+ * 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, 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.
+ *
+ */
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <asm/io.h>
+#include <linux/signal.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+
+#include "hysdn_defs.h"
+
+/*****************************************************************************/
+/* hysdn_sched_rx is called from the cards handler to announce new data is   */
+/* available from the card. The routine has to handle the data and return    */
+/* with a nonzero code if the data could be worked (or even thrown away), if */
+/* no room to buffer the data is available a zero return tells the card      */
+/* to keep the data until later.                                             */
+/*****************************************************************************/
+int
+hysdn_sched_rx(hysdn_card * card, uchar * buf, word len, word chan)
+{
+
+	switch (chan) {
+		case CHAN_NDIS_DATA:
+			hysdn_rx_netpkt(card, buf, len);	/* give packet to network handler */
+			break;
+
+		case CHAN_ERRLOG:
+			hysdn_card_errlog(card, (tErrLogEntry *) buf, len);
+			if (card->err_log_state == ERRLOG_STATE_ON)
+				card->err_log_state = ERRLOG_STATE_START;	/* start new fetch */
+			break;
+#ifdef CONFIG_HYSDN_CAPI
+         	case CHAN_CAPI:
+/* give packet to CAPI handler */
+			hycapi_rx_capipkt(card, buf, len);
+			break;
+#endif /* CONFIG_HYSDN_CAPI */
+		default:
+			printk(KERN_INFO "irq message channel %d len %d unhandled \n", chan, len);
+			break;
+
+	}			/* switch rx channel */
+
+	return (1);		/* always handled */
+}				/* hysdn_sched_rx */
+
+/*****************************************************************************/
+/* hysdn_sched_tx is called from the cards handler to announce that there is */
+/* room in the tx-buffer to the card and data may be sent if needed.         */
+/* If the routine wants to send data it must fill buf, len and chan with the */
+/* appropriate data and return a nonzero value. With a zero return no new    */
+/* data to send is assumed. maxlen specifies the buffer size available for   */
+/* sending.                                                                  */
+/*****************************************************************************/
+int
+hysdn_sched_tx(hysdn_card * card, uchar * buf, word volatile *len, word volatile *chan, word maxlen)
+{
+	struct sk_buff *skb;
+
+	if (card->net_tx_busy) {
+		card->net_tx_busy = 0;	/* reset flag */
+		hysdn_tx_netack(card);	/* acknowledge packet send */
+	}			/* a network packet has completely been transferred */
+	/* first of all async requests are handled */
+	if (card->async_busy) {
+		if (card->async_len <= maxlen) {
+			memcpy(buf, card->async_data, card->async_len);
+			*len = card->async_len;
+			*chan = card->async_channel;
+			card->async_busy = 0;	/* reset request */
+			return (1);
+		}
+		card->async_busy = 0;	/* in case of length error */
+	}			/* async request */
+	if ((card->err_log_state == ERRLOG_STATE_START) &&
+	    (maxlen >= ERRLOG_CMD_REQ_SIZE)) {
+		strcpy(buf, ERRLOG_CMD_REQ);	/* copy the command */
+		*len = ERRLOG_CMD_REQ_SIZE;	/* buffer length */
+		*chan = CHAN_ERRLOG;	/* and channel */
+		card->err_log_state = ERRLOG_STATE_ON;	/* new state is on */
+		return (1);	/* tell that data should be send */
+	}			/* error log start and able to send */
+	if ((card->err_log_state == ERRLOG_STATE_STOP) &&
+	    (maxlen >= ERRLOG_CMD_STOP_SIZE)) {
+		strcpy(buf, ERRLOG_CMD_STOP);	/* copy the command */
+		*len = ERRLOG_CMD_STOP_SIZE;	/* buffer length */
+		*chan = CHAN_ERRLOG;	/* and channel */
+		card->err_log_state = ERRLOG_STATE_OFF;		/* new state is off */
+		return (1);	/* tell that data should be send */
+	}			/* error log start and able to send */
+	/* now handle network interface packets */
+	if ((skb = hysdn_tx_netget(card)) != NULL) {
+		if (skb->len <= maxlen) {
+			memcpy(buf, skb->data, skb->len);	/* copy the packet to the buffer */
+			*len = skb->len;
+			*chan = CHAN_NDIS_DATA;
+			card->net_tx_busy = 1;	/* we are busy sending network data */
+			return (1);	/* go and send the data */
+		} else
+			hysdn_tx_netack(card);	/* aknowledge packet -> throw away */
+	}			/* send a network packet if available */
+#ifdef CONFIG_HYSDN_CAPI
+	if((skb = hycapi_tx_capiget(card)) != NULL) {
+		if (skb->len <= maxlen) {
+			memcpy(buf, skb->data, skb->len);
+			*len = skb->len;
+			*chan = CHAN_CAPI;
+			hycapi_tx_capiack(card);
+			return (1);	/* go and send the data */
+		}
+	}
+#endif /* CONFIG_HYSDN_CAPI */
+	return (0);		/* nothing to send */
+}				/* hysdn_sched_tx */
+
+
+/*****************************************************************************/
+/* send one config line to the card and return 0 if successfull, otherwise a */
+/* negative error code.                                                      */
+/* The function works with timeouts perhaps not giving the greatest speed    */
+/* sending the line, but this should be meaningless beacuse only some lines  */
+/* are to be sent and this happens very seldom.                              */
+/*****************************************************************************/
+int
+hysdn_tx_cfgline(hysdn_card * card, uchar * line, word chan)
+{
+	int cnt = 50;		/* timeout intervalls */
+	ulong flags;
+
+	if (card->debug_flags & LOG_SCHED_ASYN)
+		hysdn_addlog(card, "async tx-cfg chan=%d len=%d", chan, strlen(line) + 1);
+
+	save_flags(flags);
+	cli();
+	while (card->async_busy) {
+		sti();
+
+		if (card->debug_flags & LOG_SCHED_ASYN)
+			hysdn_addlog(card, "async tx-cfg delayed");
+
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout((20 * HZ) / 1000);	/* Timeout 20ms */
+		if (!--cnt) {
+			restore_flags(flags);
+			return (-ERR_ASYNC_TIME);	/* timed out */
+		}
+		cli();
+	}			/* wait for buffer to become free */
+
+	strcpy(card->async_data, line);
+	card->async_len = strlen(line) + 1;
+	card->async_channel = chan;
+	card->async_busy = 1;	/* request transfer */
+
+	/* now queue the task */
+	queue_task(&card->irq_queue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+	sti();
+
+	if (card->debug_flags & LOG_SCHED_ASYN)
+		hysdn_addlog(card, "async tx-cfg data queued");
+
+	cnt++;			/* short delay */
+	cli();
+
+	while (card->async_busy) {
+		sti();
+
+		if (card->debug_flags & LOG_SCHED_ASYN)
+			hysdn_addlog(card, "async tx-cfg waiting for tx-ready");
+
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout((20 * HZ) / 1000);	/* Timeout 20ms */
+		if (!--cnt) {
+			restore_flags(flags);
+			return (-ERR_ASYNC_TIME);	/* timed out */
+		}
+		cli();
+	}			/* wait for buffer to become free again */
+
+	restore_flags(flags);
+
+	if (card->debug_flags & LOG_SCHED_ASYN)
+		hysdn_addlog(card, "async tx-cfg data send");
+
+	return (0);		/* line send correctly */
+}				/* hysdn_tx_cfgline */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/hysdn/ince1pc.h linux.19p18/drivers/isdn/hysdn/ince1pc.h
--- linux.vanilla/drivers/isdn/hysdn/ince1pc.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/isdn/hysdn/ince1pc.h	Tue Feb 13 18:49:43 2001
@@ -0,0 +1,132 @@
+#ifndef __INCE1PC_H__
+#define __INCE1PC_H__
+
+/****************************************************************************
+
+    FILE:       ince1pc.h
+
+    AUTHOR:     M.Steinkopf
+
+    PURPOSE:    common definitions for both sides of the bus:
+		- conventions both spoolers must know
+		- channel numbers agreed upon
+
+*****************************************************************************/ 
+
+/*  basic scalar definitions have same meanning,
+ *  but their declaration location depends on environment
+ */ 
+
+/*--------------------------------------channel numbers---------------------*/ 
+#define CHAN_SYSTEM     0x0001      /* system channel (spooler to spooler) */
+#define CHAN_ERRLOG     0x0005      /* error logger */
+#define CHAN_CAPI       0x0064      /* CAPI interface */
+#define CHAN_NDIS_DATA  0x1001      /* NDIS data transfer */
+
+/*--------------------------------------POF ready msg-----------------------*/ 
+	    /* NOTE: after booting POF sends system ready message to PC: */ 
+#define RDY_MAGIC       0x52535953UL    /* 'SYSR' reversed */
+#define RDY_MAGIC_SIZE  4               /* size in bytes */
+
+#define MAX_N_TOK_BYTES 255
+
+#define MIN_RDY_MSG_SIZE    RDY_MAGIC_SIZE
+#define MAX_RDY_MSG_SIZE    (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES)
+
+#define SYSR_TOK_END            0
+#define SYSR_TOK_B_CHAN         1   /* nr. of B-Channels;   DataLen=1; def: 2 */
+#define SYSR_TOK_FAX_CHAN       2   /* nr. of FAX Channels; DataLen=1; def: 0 */
+#define SYSR_TOK_MAC_ADDR       3   /* MAC-Address; DataLen=6; def: auto */
+#define SYSR_TOK_ESC            255 /* undefined data size yet */
+			    /* default values, if not corrected by token: */ 
+#define SYSR_TOK_B_CHAN_DEF     2   /* assume 2 B-Channels */
+#define SYSR_TOK_FAX_CHAN_DEF   1   /* assume 1 FAX Channel */
+
+/*  syntax of new SYSR token stream:
+ *  channel: CHAN_SYSTEM
+ *  msgsize: MIN_RDY_MSG_SIZE <= x <= MAX_RDY_MSG_SIZE
+ *           RDY_MAGIC_SIZE   <= x <= (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES)
+ *  msg    : 0 1 2 3 {4 5 6 ..}
+ *           S Y S R  MAX_N_TOK_BYTES bytes of TokenStream
+ *
+ *  TokenStream     :=   empty
+ *                     | {NonEndTokenChunk} EndToken RotlCRC
+ *  NonEndTokenChunk:= NonEndTokenId DataLen [Data]
+ *  NonEndTokenId   := 0x01 .. 0xFE                 1 BYTE
+ *  DataLen         := 0x00 .. 0xFF                 1 BYTE
+ *  Data            := DataLen bytes
+ *  EndToken        := 0x00
+ *  RotlCRC         := special 1 byte CRC over all NonEndTokenChunk bytes
+ *                     s. RotlCRC algorithm
+ *
+ *  RotlCRC algorithm:
+ *      ucSum= 0                        1 uchar
+ *      for all NonEndTokenChunk bytes:
+ *          ROTL(ucSum,1)               rotate left by 1
+ *          ucSum += Char;              add current byte with swap around
+ *      RotlCRC= ~ucSum;                invert all bits for result
+ *
+ *  note:
+ *  - for 16-bit FIFO add padding 0 byte to achieve even token data bytes!
+ */ 
+
+/*--------------------------------------error logger------------------------*/ 
+					    /* note: pof needs final 0 ! */ 
+#define ERRLOG_CMD_REQ          "ERRLOG ON"
+#define ERRLOG_CMD_REQ_SIZE     10              /* with final 0 byte ! */
+#define ERRLOG_CMD_STOP         "ERRLOG OFF"
+#define ERRLOG_CMD_STOP_SIZE    11              /* with final 0 byte ! */
+
+#define ERRLOG_ENTRY_SIZE       64      /* sizeof(tErrLogEntry) */
+					/* remaining text size = 55 */ 
+#define ERRLOG_TEXT_SIZE    (ERRLOG_ENTRY_SIZE-2*4-1)
+
+typedef struct ErrLogEntry_tag {
+	
+/*00 */ ulong ulErrType;
+	
+/*04 */ ulong ulErrSubtype;
+	
+/*08 */ uchar ucTextSize;
+	
+	/*09 */ uchar ucText[ERRLOG_TEXT_SIZE];
+	/* ASCIIZ of len ucTextSize-1 */
+	
+/*40 */ 
+} tErrLogEntry;
+
+
+#if defined(__TURBOC__)
+#if sizeof(tErrLogEntry) != ERRLOG_ENTRY_SIZE
+#error size of tErrLogEntry != ERRLOG_ENTRY_SIZE
+#endif				/*  */
+#endif				/*  */
+
+/*--------------------------------------DPRAM boot spooler------------------*/ 
+				/*  this is the struture used between pc and
+				 *  hyperstone to exchange boot data
+				 */ 
+#define DPRAM_SPOOLER_DATA_SIZE 0x20
+typedef struct DpramBootSpooler_tag {
+	
+/*00 */ uchar Len;
+	
+/*01 */ volatile uchar RdPtr;
+	
+/*02 */ uchar WrPtr;
+	
+/*03 */ uchar Data[DPRAM_SPOOLER_DATA_SIZE];
+	
+/*23 */ 
+} tDpramBootSpooler;
+
+
+#define DPRAM_SPOOLER_MIN_SIZE  5       /* Len+RdPtr+Wrptr+2*data */
+#define DPRAM_SPOOLER_DEF_SIZE  0x23    /* current default size   */
+
+/*--------------------------------------HYCARD/ERGO DPRAM SoftUart----------*/ 
+				    /* at DPRAM offset 0x1C00: */ 
+#define SIZE_RSV_SOFT_UART  0x1B0   /* 432 bytes reserved for SoftUart */
+
+
+#endif	/* __INCE1PC_H__ */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/icn/Makefile linux.19p18/drivers/isdn/icn/Makefile
--- linux.vanilla/drivers/isdn/icn/Makefile	Fri Apr 21 12:46:12 2000
+++ linux.19p18/drivers/isdn/icn/Makefile	Tue Feb 13 18:38:13 2001
@@ -1,8 +1,11 @@
-ifeq ($(CONFIG_ISDN_DRV_ICN),y)
-  O_TARGET := icn_obj.o
-  O_OBJS   := icn.o
-else
-  M_OBJS   := icn.o
-endif
+# Makefile for the act2000 ISDN device driver
 
-include $(TOPDIR)/Rules.make
+# The target object and module list name.
+
+O_TARGET	:= vmlinux-obj.o
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_ISDN_DRV_ICN)	+= icn.o
+
+include $(TOPDIR)/drivers/isdn/Rules.make
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/icn/icn.c linux.19p18/drivers/isdn/icn/icn.c
--- linux.vanilla/drivers/isdn/icn/icn.c	Mon Dec 11 22:12:45 2000
+++ linux.19p18/drivers/isdn/icn/icn.c	Tue Feb 13 18:50:48 2001
@@ -1,4 +1,4 @@
-/* $Id: icn.c,v 1.65 2000/11/13 22:51:48 kai Exp $
+/* $Id: icn.c,v 1.65.6.2 2000/12/17 22:45:13 kai Exp $
 
  * ISDN low-level module for the ICN active ISDN-Card.
  *
@@ -21,6 +21,7 @@
  */
 
 #include "icn.h"
+#include <linux/init.h>
 
 /*
  * Verbose bootcode- and protocol-downloading.
@@ -33,7 +34,7 @@
 #undef MAP_DEBUG
 
 static char
-*revision = "$Revision: 1.65 $";
+*revision = "$Revision: 1.65.6.2 $";
 
 static int icn_addcard(int, char *, char *);
 
@@ -1638,9 +1639,7 @@
 	return 0;
 }
 
-#ifdef MODULE
-#define icn_init init_module
-#else
+#ifndef MODULE
 void
 icn_setup(char *str, int *ints)
 {
@@ -1661,10 +1660,9 @@
 		}
 	}
 }
-#endif /* MODULES */
+#endif /* MODULE */
 
-int
-icn_init(void)
+static int __init icn_init(void)
 {
 	char *p;
 	char rev[10];
@@ -1675,9 +1673,6 @@
 	dev.mcard = NULL;
 	dev.firstload = 1;
 
-	/* No symbols to export, hide all symbols */
-	EXPORT_NO_SYMBOLS;
-
 	if ((p = strchr(revision, ':'))) {
 		strcpy(rev, p + 1);
 		p = strchr(rev, '$');
@@ -1689,9 +1684,7 @@
 	return (icn_addcard(portbase, icn_id, icn_id2));
 }
 
-#ifdef MODULE
-void
-cleanup_module(void)
+static void  icn_exit(void)
 {
 	isdn_ctrl cmd;
 	icn_card *card = cards;
@@ -1725,4 +1718,6 @@
 		release_shmem((ulong) dev.shmem, 0x4000);
 	printk(KERN_NOTICE "ICN-ISDN-driver unloaded\n");
 }
-#endif
+
+module_init(icn_init);
+module_exit(icn_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/icn/icn.h linux.19p18/drivers/isdn/icn/icn.h
--- linux.vanilla/drivers/isdn/icn/icn.h	Mon Dec 11 22:12:45 2000
+++ linux.19p18/drivers/isdn/icn/icn.h	Sun Mar 11 13:13:32 2001
@@ -1,4 +1,4 @@
-/* $Id: icn.h,v 1.30 2000/11/13 22:51:48 kai Exp $
+/* $Id: icn.h,v 1.30.6.1 2001/02/10 14:41:23 kai Exp $
 
  * ISDN lowlevel-module for the ICN active ISDN-Card.
  *
@@ -55,7 +55,7 @@
 #include <asm/io.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
 #include <linux/ioport.h>
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/isdn_bsdcomp.c linux.19p18/drivers/isdn/isdn_bsdcomp.c
--- linux.vanilla/drivers/isdn/isdn_bsdcomp.c	Fri Apr 21 12:46:12 2000
+++ linux.19p18/drivers/isdn/isdn_bsdcomp.c	Tue Feb 13 18:50:48 2001
@@ -47,12 +47,8 @@
  * SUCH DAMAGE.
  */
 
-#ifndef MODULE
-#error This file must be compiled as a module.
-#endif
-
 #include <linux/module.h>
-
+#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/types.h>
@@ -61,7 +57,7 @@
 #include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/tty.h>
 #include <linux/errno.h>
 #include <linux/string.h>	/* used in new tty drivers */
@@ -919,7 +915,7 @@
  * Module support routines
  *************************************************************/
 
-int init_module(void)
+static int __init isdn_bsdcomp_init(void)
 {
 	int answer = isdn_ppp_register_compressor (&ippp_bsd_compress);
 	if (answer == 0)
@@ -927,7 +923,10 @@
 	return answer;
 }
 
-void cleanup_module(void)
+static void  isdn_bsdcomp_exit(void)
 {
 	isdn_ppp_unregister_compressor (&ippp_bsd_compress);
 }
+
+module_init(isdn_bsdcomp_init);
+module_exit(isdn_bsdcomp_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/isdn_cards.c linux.19p18/drivers/isdn/isdn_cards.c
--- linux.vanilla/drivers/isdn/isdn_cards.c	Mon Dec 11 22:12:45 2000
+++ linux.19p18/drivers/isdn/isdn_cards.c	Thu Jan  1 01:00:00 1970
@@ -1,73 +0,0 @@
-/* $Id: isdn_cards.c,v 1.13 2000/10/28 23:03:38 kai Exp $
-
- * Linux ISDN subsystem, initialization for non-modularized drivers.
- *
- * Copyright 1994,95,96 by Fritz Elfert (fritz@isdn4linux.de)
- *
- * 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, 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.
- *
- */
-
-#include <linux/config.h>
-
-#ifdef CONFIG_ISDN_DRV_ICN
-extern void icn_init(void);
-#endif
-
-#ifdef CONFIG_ISDN_DRV_HISAX
-extern void HiSax_init(void);
-#endif
-
-#ifdef CONFIG_ISDN_DRV_PCBIT
-extern void pcbit_init(void);
-#endif
-
-#ifdef CONFIG_ISDN_DRV_EICON
-extern void eicon_init(void);
-#endif
-
-#ifdef CONFIG_ISDN_DRV_AVMB1
-extern void kcapi_init(void);
-extern void capi_init(void);
-extern void capidrv_init(void);
-#endif
-#if CONFIG_ISDN_DRV_ACT2000
-extern void act2000_init(void);
-#endif
-
-void
-isdn_cards_init(void)
-{
-#if CONFIG_ISDN_DRV_ICN
-	icn_init();
-#endif
-#ifdef CONFIG_ISDN_DRV_HISAX
-	HiSax_init();
-#endif
-#if CONFIG_ISDN_DRV_PCBIT
-	pcbit_init();
-#endif
-#ifdef CONFIG_ISDN_DRV_AVMB1
-	kcapi_init();
-	capi_init();
-	capidrv_init();
-#endif
-#if CONFIG_ISDN_DRV_ACT2000
-	act2000_init();
-#endif
-#if CONFIG_ISDN_DRV_EICON
-	eicon_init();
-#endif
-}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/isdn_cards.h linux.19p18/drivers/isdn/isdn_cards.h
--- linux.vanilla/drivers/isdn/isdn_cards.h	Mon Dec 11 22:12:45 2000
+++ linux.19p18/drivers/isdn/isdn_cards.h	Thu Jan  1 01:00:00 1970
@@ -1,23 +0,0 @@
-/* $Id: isdn_cards.h,v 1.4 2000/05/11 22:29:20 kai Exp $
-
- * Linux ISDN subsystem, initialization for non-modularized drivers.
- *
- * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de)
- *
- * 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, 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.
- *
- */
-
-extern void isdn_cards_init(void);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/isdn_common.c linux.19p18/drivers/isdn/isdn_common.c
--- linux.vanilla/drivers/isdn/isdn_common.c	Mon Dec 11 22:12:45 2000
+++ linux.19p18/drivers/isdn/isdn_common.c	Wed Feb 14 14:24:42 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.c,v 1.113 2000/11/01 17:54:00 detabc Exp $
+/* $Id: isdn_common.c,v 1.114.6.7 2001/02/10 14:41:19 kai Exp $
 
  * Linux ISDN subsystem, common used functions (linklevel).
  *
@@ -24,10 +24,12 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/init.h>
 #include <linux/version.h>
 #include <linux/poll.h>
 #include <linux/vmalloc.h>
 #include <linux/isdn.h>
+#include <linux/smp_lock.h>
 #include "isdn_common.h"
 #include "isdn_tty.h"
 #include "isdn_net.h"
@@ -35,18 +37,20 @@
 #ifdef CONFIG_ISDN_AUDIO
 #include "isdn_audio.h"
 #endif
+#ifdef CONFIG_ISDN_DIVERSION_MODULE
+#define CONFIG_ISDN_DIVERSION
+#endif
 #ifdef CONFIG_ISDN_DIVERSION
 #include <linux/isdn_divertif.h>
 #endif CONFIG_ISDN_DIVERSION
 #include "isdn_v110.h"
-#include "isdn_cards.h"
 
 /* Debugflags */
 #undef ISDN_DEBUG_STATCALLB
 
 isdn_dev *dev;
 
-static char *isdn_revision = "$Revision: 1.113 $";
+static char *isdn_revision = "$Revision: 1.114.6.7 $";
 
 extern char *isdn_net_revision;
 extern char *isdn_tty_revision;
@@ -63,7 +67,7 @@
 extern char *isdn_v110_revision;
 
 #ifdef CONFIG_ISDN_DIVERSION
-isdn_divert_if *divert_if; /* interface to diversion module */
+static isdn_divert_if *divert_if; /* = NULL */
 #endif CONFIG_ISDN_DIVERSION
 
 
@@ -72,11 +76,10 @@
 static int isdn_wildmat(char *s, char *p);
 
 void
-isdn_MOD_INC_USE_COUNT(void)
+isdn_lock_drivers(void)
 {
 	int i;
 
-	MOD_INC_USE_COUNT;
 	for (i = 0; i < dev->drivers; i++) {
 		isdn_ctrl cmd;
 
@@ -89,11 +92,17 @@
 }
 
 void
-isdn_MOD_DEC_USE_COUNT(void)
+isdn_MOD_INC_USE_COUNT(void)
+{
+	MOD_INC_USE_COUNT;
+	isdn_lock_drivers();
+}
+
+void
+isdn_unlock_drivers(void)
 {
 	int i;
 
-	MOD_DEC_USE_COUNT;
 	for (i = 0; i < dev->drivers; i++)
 		if (dev->drv[i]->locks > 0) {
 			isdn_ctrl cmd;
@@ -106,6 +115,13 @@
 		}
 }
 
+void
+isdn_MOD_DEC_USE_COUNT(void)
+{
+	MOD_DEC_USE_COUNT;
+	isdn_unlock_drivers();
+}
+
 #if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
 void
 isdn_dumppkt(char *s, u_char * p, int len, int dumplen)
@@ -437,6 +453,7 @@
 	int r;
 	int retval = 0;
 	isdn_ctrl cmd;
+	isdn_net_dev *p;
 
 	di = c->driver;
 	i = isdn_dc2minor(di, c->arg);
@@ -515,9 +532,16 @@
 					cmd.driver = di;
 					cmd.arg = c->arg;
 					cmd.command = ISDN_CMD_ACCEPTD;
-					isdn_command(&cmd);
-					retval = 1;
+					for ( p = dev->netdev; p; p = p->next )
+						if ( p->local->isdn_channel == cmd.arg )
+						{
+							strcpy( cmd.parm.setup.eazmsn, p->local->msn );
+							isdn_command(&cmd);
+							retval = 1;
+							break;
+						}
 					break;
+
 				case 2:	/* For calling back, first reject incoming call ... */
 				case 3:	/* Interface found, but down, reject call actively  */
 					retval = 2;
@@ -719,7 +743,6 @@
 				isdn_free_queue(&dev->drv[di]->rpqueue[i]);
 			kfree(dev->drv[di]->rpqueue);
 			kfree(dev->drv[di]->rcv_waitq);
-			kfree(dev->drv[di]->snd_waitq);
 			kfree(dev->drv[di]);
 			dev->drv[di] = NULL;
 			dev->drvid[di][0] = '\0';
@@ -782,7 +805,7 @@
  * of the mapping (di,ch)<->minor, happen during the sleep? --he 
  */
 int
-isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, struct wait_queue **sleep)
+isdn_readbchan(int di, int channel, u_char * buf, u_char * fp, int len, wait_queue_head_t *sleep)
 {
 	int left;
 	int count;
@@ -966,6 +989,7 @@
 	ulong flags;
 	int drvidx;
 	int chidx;
+	int retval;
 	char *p;
 
 	if (off != &file->f_pos)
@@ -973,47 +997,69 @@
 
 	if (minor == ISDN_MINOR_STATUS) {
 		if (!file->private_data) {
-			if (file->f_flags & O_NONBLOCK)
-				return -EAGAIN;
+			if (file->f_flags & O_NONBLOCK) {
+				retval = -EAGAIN;
+				goto out;
+			}
 			interruptible_sleep_on(&(dev->info_waitq));
 		}
 		p = isdn_statstr();
 		file->private_data = 0;
 		if ((len = strlen(p)) <= count) {
-			if (copy_to_user(buf, p, len))
-				return -EFAULT;
+			if (copy_to_user(buf, p, len)) {
+				retval = -EFAULT;
+				goto out;
+			}
 			*off += len;
-			return len;
+			retval = len;
+			goto out;
 		}
-		return 0;
+		retval = 0;
+		goto out;
+	}
+	if (!dev->drivers) {
+		retval = -ENODEV;
+		goto out;
 	}
-	if (!dev->drivers)
-		return -ENODEV;
 	if (minor < ISDN_MINOR_CTRL) {
+		printk(KERN_WARNING "isdn_read minor %d obsolete!\n", minor);
 		drvidx = isdn_minor2drv(minor);
-		if (drvidx < 0)
-			return -ENODEV;
-		if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
-			return -ENODEV;
+		if (drvidx < 0) {
+			retval = -ENODEV;
+			goto out;
+		}
+		if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) {
+			retval = -ENODEV;
+			goto out;
+		}
 		chidx = isdn_minor2chan(minor);
-		if(  ! (p = kmalloc(count,GFP_KERNEL))  ) return -ENOMEM;
+		if (!(p = kmalloc(count, GFP_KERNEL))) {
+			retval = -ENOMEM;
+			goto out;
+		}
 		save_flags(flags);
 		cli();
 		len = isdn_readbchan(drvidx, chidx, p, 0, count,
 				     &dev->drv[drvidx]->rcv_waitq[chidx]);
 		*off += len;
 		restore_flags(flags);
-		if( copy_to_user(buf,p,len) ) len = -EFAULT;
+		if (copy_to_user(buf,p,len)) 
+			len = -EFAULT;
 		kfree(p);
-		return len;
+		retval = len;
+		goto out;
 	}
 	if (minor <= ISDN_MINOR_CTRLMAX) {
 		drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
-		if (drvidx < 0)
-			return -ENODEV;
+		if (drvidx < 0) {
+			retval = -ENODEV;
+			goto out;
+		}
 		if (!dev->drv[drvidx]->stavail) {
-			if (file->f_flags & O_NONBLOCK)
-				return -EAGAIN;
+			if (file->f_flags & O_NONBLOCK) {
+				retval = -EAGAIN;
+				goto out;
+			}
 			interruptible_sleep_on(&(dev->drv[drvidx]->st_waitq));
 		}
 		if (dev->drv[drvidx]->interface->readstat)
@@ -1030,13 +1076,18 @@
 			dev->drv[drvidx]->stavail = 0;
 		restore_flags(flags);
 		*off += len;
-		return len;
+		retval = len;
+		goto out;
 	}
 #ifdef CONFIG_ISDN_PPP
-	if (minor <= ISDN_MINOR_PPPMAX)
-		return (isdn_ppp_read(minor - ISDN_MINOR_PPP, file, buf, count));
+	if (minor <= ISDN_MINOR_PPPMAX) {
+		retval = isdn_ppp_read(minor - ISDN_MINOR_PPP, file, buf, count);
+		goto out;
+	}
 #endif
-	return -ENODEV;
+	retval = -ENODEV;
+ out:
+	return retval;
 }
 
 static loff_t
@@ -1051,6 +1102,7 @@
 	uint minor = MINOR(file->f_dentry->d_inode->i_rdev);
 	int drvidx;
 	int chidx;
+	int retval;
 
 	if (off != &file->f_pos)
 		return -ESPIPE;
@@ -1059,21 +1111,30 @@
 		return -EPERM;
 	if (!dev->drivers)
 		return -ENODEV;
+
 	if (minor < ISDN_MINOR_CTRL) {
+		printk(KERN_WARNING "isdn_write minor %d obsolete!\n", minor);
 		drvidx = isdn_minor2drv(minor);
-		if (drvidx < 0)
-			return -ENODEV;
-		if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
-			return -ENODEV;
+		if (drvidx < 0) {
+			retval = -ENODEV;
+			goto out;
+		}
+		if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) {
+			retval = -ENODEV;
+			goto out;
+		}
 		chidx = isdn_minor2chan(minor);
 		while (isdn_writebuf_stub(drvidx, chidx, buf, count, 1) != count)
 			interruptible_sleep_on(&dev->drv[drvidx]->snd_waitq[chidx]);
-		return count;
+		retval = count;
+		goto out;
 	}
 	if (minor <= ISDN_MINOR_CTRLMAX) {
 		drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
-		if (drvidx < 0)
-			return -ENODEV;
+		if (drvidx < 0) {
+			retval = -ENODEV;
+			goto out;
+		}
 		/*
 		 * We want to use the isdnctrl device to load the firmware
 		 *
@@ -1081,16 +1142,21 @@
 		 return -ENODEV;
 		 */
 		if (dev->drv[drvidx]->interface->writecmd)
-			return (dev->drv[drvidx]->interface->
-				writecmd(buf, count, 1, drvidx, isdn_minor2chan(minor)));
+			retval = dev->drv[drvidx]->interface->
+				writecmd(buf, count, 1, drvidx, isdn_minor2chan(minor));
 		else
-			return count;
+			retval = count;
+		goto out;
 	}
 #ifdef CONFIG_ISDN_PPP
-	if (minor <= ISDN_MINOR_PPPMAX)
-		return (isdn_ppp_write(minor - ISDN_MINOR_PPP, file, buf, count));
+	if (minor <= ISDN_MINOR_PPPMAX) {
+		retval = isdn_ppp_write(minor - ISDN_MINOR_PPP, file, buf, count);
+		goto out;
+	}
 #endif
-	return -ENODEV;
+	retval = -ENODEV;
+ out:
+	return retval;
 }
 
 static unsigned int
@@ -1106,26 +1172,30 @@
 		if (file->private_data) {
 			mask |= POLLIN | POLLRDNORM;
 		}
-		return mask;
+		goto out;
 	}
 	if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) {
 		if (drvidx < 0) {
 			/* driver deregistered while file open */
-		        return POLLHUP;
+			mask = POLLHUP;
+			goto out;
 		}
 		poll_wait(file, &(dev->drv[drvidx]->st_waitq), wait);
 		mask = POLLOUT | POLLWRNORM;
 		if (dev->drv[drvidx]->stavail) {
 			mask |= POLLIN | POLLRDNORM;
 		}
-		return mask;
+		goto out;
 	}
 #ifdef CONFIG_ISDN_PPP
-	if (minor <= ISDN_MINOR_PPPMAX)
-		return (isdn_ppp_poll(file, wait));
+	if (minor <= ISDN_MINOR_PPPMAX) {
+		mask = isdn_ppp_poll(file, wait);
+		goto out;
+	}
 #endif
-	printk(KERN_ERR "isdn_common: isdn_poll 2 -> what the hell\n");
-	return POLLERR;
+	mask = POLLERR;
+ out:
+	return mask;
 }
 
 
@@ -1432,7 +1502,7 @@
 					int i;
 
 					if ((ret = verify_area(VERIFY_READ, (void *) arg,
-					(ISDN_MODEM_NUMREG + ISDN_MSNLEN)
+					(ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN)
 						   * ISDN_MAX_CHANNELS)))
 						return ret;
 
@@ -1441,6 +1511,9 @@
 						     ISDN_MODEM_NUMREG))
 							return -EFAULT;
 						p += ISDN_MODEM_NUMREG;
+						if (copy_from_user(dev->mdm.info[i].emu.plmsn, p, ISDN_LMSNLEN))
+							return -EFAULT;
+						p += ISDN_LMSNLEN;
 						if (copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN))
 							return -EFAULT;
 						p += ISDN_MSNLEN;
@@ -1576,8 +1649,6 @@
 
 /*
  * Open the device code.
- * MOD_INC_USE_COUNT make sure that the driver memory is not freed
- * while the device is in use.
  */
 static int
 isdn_open(struct inode *ino, struct file *filep)
@@ -1585,51 +1656,62 @@
 	uint minor = MINOR(ino->i_rdev);
 	int drvidx;
 	int chidx;
+	int retval = -ENODEV;
+
+	MOD_INC_USE_COUNT;
 
 	if (minor == ISDN_MINOR_STATUS) {
 		infostruct *p;
 
 		if ((p = (infostruct *) kmalloc(sizeof(infostruct), GFP_KERNEL))) {
-			MOD_INC_USE_COUNT;
 			p->next = (char *) dev->infochain;
 			p->private = (char *) &(filep->private_data);
 			dev->infochain = p;
 			/* At opening we allow a single update */
 			filep->private_data = (char *) 1;
-			return 0;
-		} else
-			return -ENOMEM;
+			retval = 0;
+			goto out;
+		} else {
+			retval = -ENOMEM;
+			goto out;
+		}
 	}
 	if (!dev->channels)
-		return -ENODEV;
+		goto out;
 	if (minor < ISDN_MINOR_CTRL) {
+		printk(KERN_WARNING "isdn_open minor %d obsolete!\n", minor);
 		drvidx = isdn_minor2drv(minor);
 		if (drvidx < 0)
-			return -ENODEV;
+			goto out;
 		chidx = isdn_minor2chan(minor);
 		if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
-			return -ENODEV;
+			goto out;
 		if (!(dev->drv[drvidx]->online & (1 << chidx)))
-			return -ENODEV;
-		isdn_MOD_INC_USE_COUNT();
-		return 0;
+			goto out;
+		isdn_lock_drivers();
+		retval = 0;
+		goto out;
 	}
 	if (minor <= ISDN_MINOR_CTRLMAX) {
 		drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
 		if (drvidx < 0)
-			return -ENODEV;
-		isdn_MOD_INC_USE_COUNT();
-		return 0;
+			goto out;
+		isdn_lock_drivers();
+		retval = 0;
+		goto out;
 	}
 #ifdef CONFIG_ISDN_PPP
 	if (minor <= ISDN_MINOR_PPPMAX) {
-		int ret;
-		if (!(ret = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep)))
-			isdn_MOD_INC_USE_COUNT();
-		return ret;
+		retval = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep);
+		if (retval == 0)
+			isdn_lock_drivers();
+		goto out;
 	}
 #endif
-	return -ENODEV;
+ out:
+	if (retval)
+		MOD_DEC_USE_COUNT;
+	return retval;
 }
 
 static int
@@ -1641,7 +1723,6 @@
 		infostruct *p = dev->infochain;
 		infostruct *q = NULL;
 
-		MOD_DEC_USE_COUNT;
 		while (p) {
 			if (p->private == (char *) &(filep->private_data)) {
 				if (q)
@@ -1649,26 +1730,29 @@
 				else
 					dev->infochain = (infostruct *) (p->next);
 				kfree(p);
-				return 0;
+				goto out;
 			}
 			q = p;
 			p = (infostruct *) (p->next);
 		}
 		printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n");
-		return 0;
+		goto out;
 	}
-	isdn_MOD_DEC_USE_COUNT();
+	isdn_unlock_drivers();
 	if (minor < ISDN_MINOR_CTRL)
-		return 0;
+		goto out;
 	if (minor <= ISDN_MINOR_CTRLMAX) {
 		if (dev->profd == current)
 			dev->profd = NULL;
-		return 0;
+		goto out;
 	}
 #ifdef CONFIG_ISDN_PPP
 	if (minor <= ISDN_MINOR_PPPMAX)
 		isdn_ppp_release(minor - ISDN_MINOR_PPP, filep);
 #endif
+
+ out:
+	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -1911,21 +1995,12 @@
 }
 
 int
-register_isdn_module(isdn_module *m) {
-	return 0;
-}
-
-int
-unregister_isdn_module(isdn_module *m) {
-	return 0;
-}
-
-int
 isdn_add_channels(driver *d, int drvidx, int n, int adding)
 {
 	int j, k, m;
 	ulong flags;
 
+	init_waitqueue_head(&d->st_waitq);
 	if (d->flags & DRV_FLAG_RUNNING)
 		return -1;
        	if (n < 1) return 0;
@@ -1975,8 +2050,9 @@
 
 	if ((adding) && (d->rcv_waitq))
 		kfree(d->rcv_waitq);
-	if (!(d->rcv_waitq = (struct wait_queue **)
-	      kmalloc(sizeof(struct wait_queue *) * m, GFP_KERNEL))) {
+	d->rcv_waitq = (wait_queue_head_t *)
+		kmalloc(sizeof(wait_queue_head_t) * 2 * m, GFP_KERNEL);
+	if (!d->rcv_waitq) {
 		printk(KERN_WARNING "register_isdn: Could not alloc rcv_waitq\n");
 		if (!adding) {
 			kfree(d->rpqueue);
@@ -1985,22 +2061,11 @@
 		}
 		return -1;
 	}
-	memset((char *) d->rcv_waitq, 0, sizeof(struct wait_queue *) * m);
-
-	if ((adding) && (d->snd_waitq))
-		kfree(d->snd_waitq);
-	if (!(d->snd_waitq = (struct wait_queue **)
-	      kmalloc(sizeof(struct wait_queue *) * m, GFP_KERNEL))) {
-		printk(KERN_WARNING "register_isdn: Could not alloc snd_waitq\n");
-		if (!adding) {
-			kfree(d->rcv_waitq);
-			kfree(d->rpqueue);
-			kfree(d->rcvcount);
-			kfree(d->rcverr);
-		}
-		return -1;
+	d->snd_waitq = d->rcv_waitq + m;
+	for (j = 0; j < m; j++) {
+		init_waitqueue_head(&d->rcv_waitq[j]);
+		init_waitqueue_head(&d->snd_waitq[j]);
 	}
-	memset((char *) d->snd_waitq, 0, sizeof(struct wait_queue *) * m);
 
 	dev->channels += n;
 	save_flags(flags);
@@ -2036,7 +2101,6 @@
 }
 
 #ifdef CONFIG_ISDN_DIVERSION
-extern isdn_divert_if *divert_if;
 
 static char *map_drvname(int di)
 {
@@ -2089,8 +2153,6 @@
 
 
 EXPORT_SYMBOL(register_isdn);
-EXPORT_SYMBOL(register_isdn_module);
-EXPORT_SYMBOL(unregister_isdn_module);
 #ifdef CONFIG_ISDN_PPP
 EXPORT_SYMBOL(isdn_ppp_register_compressor);
 EXPORT_SYMBOL(isdn_ppp_unregister_compressor);
@@ -2158,12 +2220,6 @@
  *****************************************************************************
  */
 
-extern int printk(const char *fmt,...);
-
-#ifdef MODULE
-#define isdn_init init_module
-#endif
-
 static char *
 isdn_getrev(const char *revision)
 {
@@ -2183,8 +2239,7 @@
 /*
  * Allocate and initialize all data, register modem-devices
  */
-int
-isdn_init(void)
+static int __init isdn_init(void)
 {
 	int i;
 	char tmprev[50];
@@ -2196,12 +2251,15 @@
 	memset((char *) dev, 0, sizeof(isdn_dev));
 	init_timer(&dev->timer);
 	dev->timer.function = isdn_timer_funct;
-	dev->sem = MUTEX;
+	init_MUTEX(&dev->sem);
+	init_waitqueue_head(&dev->info_waitq);
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
 		dev->drvmap[i] = -1;
 		dev->chanmap[i] = -1;
 		dev->m_idx[i] = -1;
 		strcpy(dev->num[i], "???");
+		init_waitqueue_head(&dev->mdm.info[i].open_wait);
+		init_waitqueue_head(&dev->mdm.info[i].close_wait);
 	}
 	if (register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) {
 		printk(KERN_WARNING "isdn: Could not register control devices\n");
@@ -2248,18 +2306,15 @@
 	printk(" loaded\n");
 #else
 	printk("\n");
-	isdn_cards_init();
 #endif
 	isdn_info_update();
 	return 0;
 }
 
-#ifdef MODULE
 /*
  * Unload module
  */
-void
-cleanup_module(void)
+static void  isdn_exit(void)
 {
 	int flags;
 	int i;
@@ -2293,11 +2348,15 @@
 	}
 	if (unregister_chrdev(ISDN_MAJOR, "isdn") != 0) {
 		printk(KERN_WARNING "isdn: controldevice busy, remove cancelled\n");
+		restore_flags(flags);
 	} else {
 		del_timer(&dev->timer);
+		restore_flags(flags);
+		/* call vfree with interrupts enabled, else it will hang */
 		vfree(dev);
 		printk(KERN_NOTICE "ISDN-subsystem unloaded\n");
 	}
-	restore_flags(flags);
 }
-#endif
+
+module_init(isdn_init);
+module_exit(isdn_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/isdn_common.h linux.19p18/drivers/isdn/isdn_common.h
--- linux.vanilla/drivers/isdn/isdn_common.h	Mon Dec 11 22:12:45 2000
+++ linux.19p18/drivers/isdn/isdn_common.h	Mon Feb 12 15:09:50 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_common.h,v 1.20 2000/06/16 13:00:27 keil Exp $
+/* $Id: isdn_common.h,v 1.21 2000/11/25 17:00:59 kai Exp $
 
  * header for Linux ISDN subsystem, common used functions and debugging-switches (linklevel).
  *
@@ -46,7 +46,7 @@
 extern void isdn_timer_ctrl(int tf, int onoff);
 extern void isdn_unexclusive_channel(int di, int ch);
 extern int isdn_getnum(char **);
-extern int isdn_readbchan(int, int, u_char *, u_char *, int, struct wait_queue**);
+extern int isdn_readbchan(int, int, u_char *, u_char *, int, wait_queue_head_t *);
 extern int isdn_get_free_channel(int, int, int, int, int, char *);
 extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *);
 extern int register_isdn(isdn_if * i);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/isdn_concap.c linux.19p18/drivers/isdn/isdn_concap.c
--- linux.vanilla/drivers/isdn/isdn_concap.c	Mon Dec 11 22:12:45 2000
+++ linux.19p18/drivers/isdn/isdn_concap.c	Wed Dec 13 22:10:15 2000
@@ -52,15 +52,19 @@
 
 int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb)
 {
-	int tmp;
 	struct device *ndev = concap -> net_dev;
-	isdn_net_local *lp = (isdn_net_local *) ndev->priv;
+	isdn_net_dev *nd = ((isdn_net_local *) ndev->priv)->netdev;
+	isdn_net_local *lp = isdn_net_get_locked_lp(nd);
 
 	IX25DEBUG( "isdn_concap_dl_data_req: %s \n", concap->net_dev->name);
+	if (!lp) {
+		IX25DEBUG( "isdn_concap_dl_data_req: %s : isdn_net_send_skb returned %d\n", concap -> net_dev -> name, 1);
+		return 1;
+	}
 	lp->huptimer = 0;
-	tmp=isdn_net_send_skb(ndev, lp, skb);
-	IX25DEBUG( "isdn_concap_dl_data_req: %s : isdn_net_send_skb returned %d\n", concap -> net_dev -> name, tmp);
-	return tmp;
+	isdn_net_writebuf_skb(lp, skb);
+	IX25DEBUG( "isdn_concap_dl_data_req: %s : isdn_net_send_skb returned %d\n", concap -> net_dev -> name, 0);
+	return 0;
 }
 
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/isdn_net.c linux.19p18/drivers/isdn/isdn_net.c
--- linux.vanilla/drivers/isdn/isdn_net.c	Mon Dec 11 22:12:45 2000
+++ linux.19p18/drivers/isdn/isdn_net.c	Wed Feb 14 14:28:52 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_net.c,v 1.137 2000/09/12 19:43:47 kai Exp $
+/* $Id: isdn_net.c,v 1.140.6.3 2001/02/07 11:31:30 kai Exp $
 
  * Linux ISDN subsystem, network interfaces and related functions (linklevel).
  *
@@ -30,6 +30,7 @@
 #include <net/dst.h>
 #include <net/pkt_sched.h>
 #include <linux/inetdevice.h>
+#include <linux/isdn_compat.h>
 #include "isdn_common.h"
 #include "isdn_net.h"
 #ifdef CONFIG_ISDN_PPP
@@ -72,7 +73,7 @@
  * Find out if the netdevice has been ifup-ed yet.
  * For slaves, look at the corresponding master.
  */
-static int __inline__ isdn_net_started(isdn_net_dev *n)
+static __inline__ int isdn_net_device_started(isdn_net_dev *n)
 {
 	isdn_net_local *lp = n->local;
 	struct device *dev;
@@ -88,7 +89,7 @@
  * wake up the network -> net_device queue.
  * For slaves, wake the corresponding master interface.
  */
-static void __inline__ isdn_net_lp_xon(isdn_net_local * lp)
+static __inline__ void isdn_net_device_wake_queue(isdn_net_local *lp)
 {
 	if (lp->master) 
 		netif_wake_queue(lp->master);
@@ -96,6 +97,76 @@
 		netif_wake_queue(&lp->netdev->dev);
 }
 
+/*
+ * stop the network -> net_device queue.
+ * For slaves, stop the corresponding master interface.
+ */
+static __inline__ void isdn_net_device_stop_queue(isdn_net_local *lp)
+{
+	if (lp->master)
+		netif_stop_queue(lp->master);
+	else
+		netif_stop_queue(&lp->netdev->dev);
+}
+
+/*
+ * find out if the net_device which this lp belongs to (lp can be
+ * master or slave) is busy. It's busy iff all (master and slave) 
+ * queues are busy
+ */
+static __inline__ int isdn_net_device_busy(isdn_net_local *lp)
+{
+	isdn_net_local *nlp;
+	isdn_net_dev *nd;
+	unsigned long flags;
+
+	if (!isdn_net_lp_busy(lp))
+		return 0;
+
+	if (lp->master)
+		nd = ((isdn_net_local *) lp->master->priv)->netdev;
+	else
+		nd = lp->netdev;
+	
+	spin_lock_irqsave(&nd->queue_lock, flags);
+	nlp = lp->next;
+	while (nlp != lp) {
+		if (!isdn_net_lp_busy(nlp)) {
+			spin_unlock_irqrestore(&nd->queue_lock, flags);
+			return 0;
+		}
+		nlp = nlp->next;
+	}
+	spin_unlock_irqrestore(&nd->queue_lock, flags);
+	return 1;
+}
+
+static __inline__ void isdn_net_inc_frame_cnt(isdn_net_local *lp)
+{
+	atomic_inc(&lp->frame_cnt);
+	if (isdn_net_device_busy(lp))
+		isdn_net_device_stop_queue(lp);
+}
+
+static __inline__ void isdn_net_dec_frame_cnt(isdn_net_local *lp)
+{
+	atomic_dec(&lp->frame_cnt);
+
+	if (!(isdn_net_device_busy(lp))) {
+		if (!skb_queue_empty(&lp->super_tx_queue)) {
+			queue_task(&lp->tqueue, &tq_immediate);
+			mark_bh(IMMEDIATE_BH);
+		} else {
+			isdn_net_device_wake_queue(lp);
+		}
+       }                                                                      
+}
+
+static __inline__ void isdn_net_zero_frame_cnt(isdn_net_local *lp)
+{
+	atomic_set(&lp->frame_cnt, 0);
+}
+
 /* For 2.2.x we leave the transmitter busy timeout at 2 secs, just 
  * to be safe.
  * For 2.3.x we push it up to 20 secs, because call establishment
@@ -111,9 +182,8 @@
 
 int isdn_net_force_dial_lp(isdn_net_local *);
 static int isdn_net_start_xmit(struct sk_buff *, struct device *);
-static int isdn_net_xmit(struct device *, isdn_net_local *, struct sk_buff *);
 
-char *isdn_net_revision = "$Revision: 1.114 $";
+char *isdn_net_revision = "$Revision: 1.140.6.3 $";
 
  /*
   * Code for raw-networking over ISDN
@@ -122,7 +192,6 @@
 static void
 isdn_net_unreachable(struct device *dev, struct sk_buff *skb, char *reason)
 {
-
 	if(skb) {
 
 		u_short proto = ntohs(skb->protocol);
@@ -225,16 +294,12 @@
 isdn_net_unbind_channel(isdn_net_local * lp)
 {
 	ulong flags;
+	struct sk_buff *skb;
 
 	save_flags(flags);
 	cli();
-	if (lp->first_skb) {
-		dev_kfree_skb(lp->first_skb);
-		lp->first_skb = NULL;
-	}
-	if (lp->sav_skb) {
-		dev_kfree_skb(lp->sav_skb);
-		lp->sav_skb = NULL;
+	while ((skb = skb_dequeue(&lp->super_tx_queue))) {
+		kfree_skb(skb);
 	}
 	if (!lp->master) {	/* reset only master device */
 		/* Moral equivalent of dev_purge_queues():
@@ -331,6 +396,11 @@
 	isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, anymore);
 }
 
+static void isdn_net_lp_disconnected(isdn_net_local *lp)
+{
+	isdn_net_rm_from_bundle(lp);
+}
+
 /*
  * Handle status-messages from ISDN-interfacecard.
  * This function is called from within the main-status-dispatcher
@@ -354,28 +424,9 @@
 				/* A packet has successfully been sent out */
 				if ((lp->flags & ISDN_NET_CONNECTED) &&
 				    (!lp->dialstate)) {
+					isdn_net_dec_frame_cnt(lp);
 					lp->stats.tx_packets++;
 					lp->stats.tx_bytes += c->parm.length;
-					/* some HL drivers deliver 
-					   ISDN_STAT_BSENT from hw interrupt.
-					   Output routines in isdn_ppp are now
-					   called with irq disabled such that
-					   dequeueing the sav_skb while another
-					   frame is sent will not occur.
-					*/
-					if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP && lp->sav_skb) {
-						struct device *mdev;
-						if (lp->master)
-							mdev = lp->master;
-						else
-							mdev = &lp->netdev->dev;
-						if (!isdn_net_send_skb(mdev, lp, lp->sav_skb)) {
-							lp->sav_skb = NULL;
-						} else {
-							return 1;
-						}
-					}
-					isdn_net_lp_xon(lp);
 				}
 				return 1;
 			case ISDN_STAT_DCONN:
@@ -405,8 +456,10 @@
 #endif /* CONFIG_ISDN_X25 */
 				if ((!lp->dialstate) && (lp->flags & ISDN_NET_CONNECTED)) {
 #ifdef CONFIG_ISDN_PPP
-					isdn_ppp_free(lp);
+					if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
+						isdn_ppp_free(lp);
 #endif
+					isdn_net_lp_disconnected(lp);
 					isdn_all_eaz(lp->isdn_device, lp->isdn_channel);
 					printk(KERN_INFO "%s: remote hangup\n", lp->name);
 					printk(KERN_INFO "%s: Chargesum is %d\n", lp->name,
@@ -429,6 +482,7 @@
 #endif /* CONFIG_ISDN_X25 */
 			case ISDN_STAT_BCONN:
 				/* B-Channel is up */
+				isdn_net_zero_frame_cnt(lp);
 				switch (lp->dialstate) {
 					case 5:
 					case 6:
@@ -446,13 +500,17 @@
 						isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 1);
 						if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK)
 							isdn_timer_ctrl(ISDN_TIMER_KEEPALIVE, 1);
+						if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) {
+							if (lp->master) { /* is lp a slave? */
+								isdn_net_dev *nd = ((isdn_net_local *)lp->master->priv)->netdev;
+								isdn_net_add_to_bundle(nd, lp);
+							}
+						}
 						printk(KERN_INFO "isdn_net: %s connected\n", lp->name);
 						/* If first Chargeinfo comes before B-Channel connect,
 						 * we correct the timestamp here.
 						 */
 						lp->chargetime = jiffies;
-						printk(KERN_DEBUG "isdn_net: chargetime of %s now %lu\n",
-						lp->name, lp->chargetime);
 
 						/* reset dial-timeout */
 						lp->dialstarted = 0;
@@ -468,13 +526,9 @@
 							if( pops->connect_ind)
 								pops->connect_ind(cprot);
 #endif /* CONFIG_ISDN_X25 */
-						/* Immediately send first skb to speed up arp */
-						if (lp->first_skb) {
-
-							if (!(isdn_net_xmit(&p->dev, lp, lp->first_skb)))
-								lp->first_skb = NULL;
-						}
-						if(! lp->first_skb) isdn_net_lp_xon(lp);
+						/* ppp needs to do negotiations first */
+						if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
+							isdn_net_device_wake_queue(lp);
 						return 1;
 				}
 				break;
@@ -584,7 +638,7 @@
 						s = "dial suppressed: isdn system stopped";
 					else
 						s = "dial suppressed: dialmode `off'";
-					isdn_net_unreachable(&p->dev, lp->first_skb, s);
+					isdn_net_unreachable(&p->dev, 0, s);
 					isdn_net_hangup(&p->dev);
 					break;
 				}
@@ -617,7 +671,7 @@
 							restore_flags(flags);
 							lp->dialwait_timer = jiffies + lp->dialwait;
 							lp->dialstarted = 0;
-							isdn_net_unreachable(&p->dev, lp->first_skb, "dial: timed out");
+							isdn_net_unreachable(&p->dev, 0, "dial: timed out");
 							isdn_net_hangup(&p->dev);
 							break;
 						}
@@ -635,7 +689,7 @@
 							if (lp->dialtimeout == 0) {
 								lp->dialwait_timer = jiffies + lp->dialwait;
 								lp->dialstarted = 0;
-								isdn_net_unreachable(&p->dev, lp->first_skb, "dial: tried all numbers dialmax times");
+								isdn_net_unreachable(&p->dev, 0, "dial: tried all numbers dialmax times");
 							}
 							isdn_net_hangup(&p->dev);
 							break;
@@ -651,6 +705,7 @@
 					i = isdn_dc2minor(lp->isdn_device, lp->isdn_channel);
 					if (i >= 0) {
 						strcpy(dev->num[i], cmd.parm.setup.phone);
+						dev->usage[i] |= ISDN_USAGE_OUTGOING;
 						isdn_info_update();
 					}
 					printk(KERN_INFO "%s: dialing %d %s...\n", lp->name,
@@ -795,10 +850,21 @@
 #endif
 
 	if (lp->flags & ISDN_NET_CONNECTED) {
+		if (lp->slave != NULL) {
+			isdn_net_local *slp = (isdn_net_local *)lp->slave->priv;
+			if (slp->flags & ISDN_NET_CONNECTED) {
+				printk(KERN_INFO
+					"isdn_net: hang up slave %s before %s\n",
+					slp->name, lp->name);
+				isdn_net_hangup(lp->slave);
+			}
+		}
 		printk(KERN_INFO "isdn_net: local hangup %s\n", lp->name);
 #ifdef CONFIG_ISDN_PPP
-		isdn_ppp_free(lp);
+		if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
+			isdn_ppp_free(lp);
 #endif
+		isdn_net_lp_disconnected(lp);
 #ifdef CONFIG_ISDN_X25
 		/* try if there are generic encap protocol
 		   receiver routines and signal the closure of
@@ -911,31 +977,82 @@
 }
 
 /*
- * Generic routine to send out an skbuf.
- * If lowlevel-device does not support support skbufs, use
- * standard send-routine, else send directly.
- *
- * Return: 0 on success, !0 on failure.
+ * this function is used to send supervisory data, i.e. data which was
+ * not received from the network layer, but e.g. frames from ipppd, CCP
+ * reset frames etc.
+ */
+void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb)
+{
+	if (in_interrupt()) {
+		// we can't grab the lock from irq context, 
+		// so we just queue the packet
+		skb_queue_tail(&lp->super_tx_queue, skb); 
+		queue_task(&lp->tqueue, &tq_immediate);
+ 		mark_bh(IMMEDIATE_BH);
+		return;
+	}
+
+	if (!isdn_net_lp_busy(lp)) {
+		isdn_net_writebuf_skb(lp, skb);
+	} else {
+		skb_queue_tail(&lp->super_tx_queue, skb);
+	}
+}
+
+/*
+ * called from tq_immediate
  */
-int isdn_net_send_skb
-		(struct device *ndev, isdn_net_local * lp,struct sk_buff *skb)
+static void isdn_net_softint(void *private)
+{
+	isdn_net_local *lp = private;
+	struct sk_buff *skb;
+
+	while (!isdn_net_lp_busy(lp)) {
+		skb = skb_dequeue(&lp->super_tx_queue);
+		if (!skb)
+			break;
+		isdn_net_writebuf_skb(lp, skb);                                
+	}
+}
+
+/* 
+ * all frames sent from the (net) LL to a HL driver should go via this function
+ * it's serialized by the caller holding the lp->xmit_lock spinlock
+ */
+void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb)
 {
 	int ret;
 	int len = skb->len;     /* save len */
 
-	ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb);
-	if (ret == len) {
-		lp->transcount += len;
-		return 0;
+	/* before obtaining the lock the caller should have checked that
+	   the lp isn't busy */
+	if (isdn_net_lp_busy(lp)) {
+		printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
+		goto error;
 	}
-	if (ret < 0) {
-		dev_kfree_skb(skb);
-		lp->stats.tx_errors++;
-		return 0;
+
+	if (!(lp->flags & ISDN_NET_CONNECTED)) {
+		printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
+		goto error;
 	}
-	return 1;
+	ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb);
+	if (ret != len) {
+		/* we should never get here */
+		printk(KERN_WARNING "%s: HL driver queue full\n", lp->name);
+		goto error;
+	}
+	
+	lp->transcount += len;
+	isdn_net_inc_frame_cnt(lp);
+	return;
+
+ error:
+	dev_kfree_skb(skb);
+	lp->stats.tx_errors++;
+
 }
 
+
 /*
  *  Helper function for isdn_net_start_xmit.
  *  When called, the connection is already established.
@@ -948,9 +1065,18 @@
  */
 
 static int
-isdn_net_xmit(struct device *ndev, isdn_net_local * lp, struct sk_buff *skb)
+isdn_net_xmit(struct device *ndev, struct sk_buff *skb)
 {
-	int ret;
+	isdn_net_dev *nd;
+	isdn_net_local *slp;
+	isdn_net_local *lp = (isdn_net_local *) ndev->priv;
+	int retv = 0;
+
+	if (((isdn_net_local *) (ndev->priv))->master) {
+		printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
+		dev_kfree_skb(skb);
+		return 0;
+	}
 
 	/* For the other encaps the header has already been built */
 #ifdef CONFIG_ISDN_PPP
@@ -958,31 +1084,24 @@
 		return isdn_ppp_xmit(skb, ndev);
 	}
 #endif
+	nd = ((isdn_net_local *) ndev->priv)->netdev;
+	lp = isdn_net_get_locked_lp(nd);
+	if (!lp) {
+		printk(KERN_WARNING "%s: all channels busy - requeuing!\n", ndev->name);
+		return 1;
+	}
+	/* we have our lp locked from now on */
+
 	/* Reset hangup-timeout */
-	lp->huptimer = 0;
-	if (lp->cps > lp->triggercps) {
-		/* Device overloaded */
+	lp->huptimer = 0; // FIXME?
+	isdn_net_writebuf_skb(lp, skb);
 
-		/*
-		 * Packet-delivery via round-robin over master
-		 * and all connected slaves.
-		 */
-		if (lp->master)
-			/* Slaves always deliver themselves */
-			ret = isdn_net_send_skb(ndev, lp, skb);
-		else {
-			isdn_net_local *slp = (isdn_net_local *) (lp->srobin->priv);
-			/* Master delivers via srobin and maintains srobin */
-			if (lp->srobin == ndev)
-				ret = isdn_net_send_skb(ndev, lp, skb);
-			else
-				ret = isdn_net_start_xmit(skb, lp->srobin);
-			lp->srobin = (slp->slave) ? slp->slave : ndev;
-			slp = (isdn_net_local *) (lp->srobin->priv);
-			if (!((slp->flags & ISDN_NET_CONNECTED) && (slp->dialstate == 0)))
-				lp->srobin = ndev;
-		}
-		/* Slave-startup using delay-variable */
+	/* the following stuff is here for backwards compatibility.
+	 * in future, start-up and hangup of slaves (based on current load)
+	 * should move to userspace and get based on an overall cps
+	 * calculation
+	 */
+	if (lp->cps > lp->triggercps) {
 		if (lp->slave) {
 			if (!lp->sqfull) {
 				/* First time overload: set timestamp only */
@@ -990,17 +1109,24 @@
 				lp->sqfull_stamp = jiffies;
 			} else {
 				/* subsequent overload: if slavedelay exceeded, start dialing */
-				if ((jiffies - lp->sqfull_stamp) > lp->slavedelay)
-					isdn_net_force_dial_lp((isdn_net_local *) lp->slave->priv);
+				if ((jiffies - lp->sqfull_stamp) > lp->slavedelay) {
+					slp = lp->slave->priv;
+					if (!(slp->flags & ISDN_NET_CONNECTED)) {
+						isdn_net_force_dial_lp((isdn_net_local *) lp->slave->priv);
+					}
+				}
 			}
 		}
 	} else {
-		/* Not overloaded, deliver locally */
-		ret = isdn_net_send_skb(ndev, lp, skb);
-		if (lp->sqfull && ((jiffies - lp->sqfull_stamp) > (lp->slavedelay + (10 * HZ))))
+		if (lp->sqfull && ((jiffies - lp->sqfull_stamp) > (lp->slavedelay + (10 * HZ)))) {
 			lp->sqfull = 0;
+		}
+		/* this is a hack to allow auto-hangup for slaves on moderate loads */
+		nd->queue = nd->local;
 	}
-	return ret;
+
+	return retv;
+
 }
 
 static void
@@ -1078,6 +1204,7 @@
 		buf = skb->data;
 		isdn_dumppkt("S:", buf, skb->len, 40);
 #endif
+
 		if (!(lp->flags & ISDN_NET_CONNECTED)) {
 			int chi;
 			/* only do autodial if allowed by config */
@@ -1150,19 +1277,11 @@
 					return 1;	/* let upper layer requeue skb packet */
 				}
 #endif
-				/* remember first skb to speed up arp
-				 * when using encap ETHER
-				 */
-				if (lp->first_skb) {
-					printk(KERN_WARNING "isdn_net_start_xmit: First skb already set!\n");
-					dev_kfree_skb(lp->first_skb);
-					lp->first_skb = NULL;
-				}
-				lp->first_skb = skb;
 				/* Initiate dialing */
 				restore_flags(flags);
 				isdn_net_dial();
-				return 0;
+				isdn_net_device_stop_queue(lp);
+				return 1;
 			} else {
 				isdn_net_unreachable(ndev, skb,
 						     "No phone number");
@@ -1175,14 +1294,7 @@
 			if (!lp->dialstate) {
 				/* ISDN connection is established, try sending */
 				int ret;
-				if (lp->first_skb) {
-					if (isdn_net_xmit(ndev, lp, lp->first_skb)){
-						netif_stop_queue(ndev);
-						return 1;
-}
-					lp->first_skb = NULL;
-				}
-				ret = (isdn_net_xmit(ndev, lp, skb));
+				ret = (isdn_net_xmit(ndev, skb));
 				if(ret) netif_stop_queue(ndev);
 				return ret;
 			} else
@@ -1231,7 +1343,7 @@
 /*
  * Get statistics
  */
-static struct enet_statistics *
+static struct net_device_stats *
 isdn_net_get_stats(struct device *dev)
 {
 	isdn_net_local *lp = (isdn_net_local *) dev->priv;
@@ -1297,7 +1409,6 @@
 	unsigned short hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
 	struct sk_buff *skb = alloc_skb(hl + sizeof(cisco_hdr) + sizeof(cisco_slarp), GFP_ATOMIC);
 	unsigned long t = (jiffies / HZ * 1000000);
-	int len;
 	cisco_hdr *ch;
 	cisco_slarp *s;
 
@@ -1325,9 +1436,7 @@
 	s->rel = 0xffff;
 	s->t1 = t >> 16;
 	s->t0 = t & 0xffff;
-	len = skb->len;
-	if (isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 0, skb) != len)
-		dev_kfree_skb(skb);
+	isdn_net_write_super(lp, skb);
 }
 
 static void
@@ -1411,7 +1520,6 @@
 		lp->stats.rx_packets++;
 		lp->stats.rx_bytes += skb->len;
 	}
-
 	skb->dev = ndev;
 	skb->pkt_type = PACKET_HOST;
 	skb->mac.raw = skb->data;
@@ -1494,6 +1602,7 @@
 			isdn_ppp_receive(lp->netdev, olp, skb);
 			return;
 #endif
+
 		default:
 #ifdef CONFIG_ISDN_X25
 		  /* try if there are generic sync_device receiver routines */
@@ -1960,7 +2069,7 @@
 				 * Is the interface up?
 				 * If not, reject the call actively.
 				 */
-				if (!isdn_net_started(p)) {
+				if (!isdn_net_device_started(p)) {
 					restore_flags(flags);
 					printk(KERN_INFO "%s: incoming call, interface down -> rejected\n",
 					       lp->name);
@@ -2051,6 +2160,7 @@
 						if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP)
 							isdn_ppp_free(lp);
 #endif
+						isdn_net_lp_disconnected(lp);
 						isdn_free_channel(lp->isdn_device, lp->isdn_channel,
 							 ISDN_USAGE_NET);
 					}
@@ -2205,6 +2315,7 @@
 	memset(netdev, 0, sizeof(isdn_net_dev));
 	if (!(netdev->local = (isdn_net_local *) kmalloc(sizeof(isdn_net_local), GFP_KERNEL))) {
 		printk(KERN_WARNING "isdn_net: Could not allocate device locals\n");
+		kfree(netdev);
 		return NULL;
 	}
 	memset(netdev->local, 0, sizeof(isdn_net_local));
@@ -2240,10 +2351,17 @@
 	netdev->local->magic = ISDN_NET_MAGIC;
 
 	netdev->queue = netdev->local;
+	spin_lock_init(&netdev->queue_lock);
+
 	netdev->local->last = netdev->local;
 	netdev->local->netdev = netdev;
 	netdev->local->next = netdev->local;
 
+	netdev->local->tqueue.sync = 0;
+	netdev->local->tqueue.routine = isdn_net_softint;
+	netdev->local->tqueue.data = netdev->local;
+	spin_lock_init(&netdev->local->xmit_lock);
+
 	netdev->local->isdn_device = -1;
 	netdev->local->isdn_channel = -1;
 	netdev->local->pre_device = -1;
@@ -2251,13 +2369,11 @@
 	netdev->local->exclusive = -1;
 	netdev->local->ppp_slot = -1;
 	netdev->local->pppbind = -1;
-	netdev->local->sav_skb = NULL;
-	netdev->local->first_skb = NULL;
+	skb_queue_head_init(&netdev->local->super_tx_queue);
 	netdev->local->l2_proto = ISDN_PROTO_L2_X75I;
 	netdev->local->l3_proto = ISDN_PROTO_L3_TRANS;
 	netdev->local->triggercps = 6000;
 	netdev->local->slavedelay = 10 * HZ;
-	netdev->local->srobin = &netdev->dev;
 	netdev->local->hupflags = ISDN_INHUP;	/* Do hangup even on incoming calls */
 	netdev->local->onhtime = 10;	/* Default hangup-time for saving costs
 	   of those who forget configuring this */
@@ -2295,7 +2411,7 @@
 		if (n->local->master)
 			return NULL;
 		/* Master must not be started yet */
-		if (isdn_net_started(n)) 
+		if (isdn_net_device_started(n)) 
 			return NULL;
 		return (isdn_net_new(newname, &(n->dev)));
 	}
@@ -2338,7 +2454,7 @@
 #ifdef CONFIG_ISDN_X25
 			struct concap_proto * cprot = p -> cprot;
 #endif
-			if (isdn_net_started(p)) {
+			if (isdn_net_device_started(p)) {
 				printk(KERN_WARNING "%s: cannot change encap when if is up\n",
 				       lp->name);
 				return -EBUSY;
@@ -2771,8 +2887,7 @@
 
 	save_flags(flags);
 	cli();
-
-	if (isdn_net_started(p)) {
+	if (isdn_net_device_started(p)) {
 		restore_flags(flags);
 		return -EBUSY;
 	}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/isdn_net.h linux.19p18/drivers/isdn/isdn_net.h
--- linux.vanilla/drivers/isdn/isdn_net.h	Mon Dec 11 22:12:45 2000
+++ linux.19p18/drivers/isdn/isdn_net.h	Wed Dec 13 22:10:21 2000
@@ -82,8 +82,87 @@
 extern int isdn_net_force_hangup(char *);
 extern int isdn_net_force_dial(char *);
 extern isdn_net_dev *isdn_net_findif(char *);
-extern int isdn_net_send_skb(struct device *, isdn_net_local *,
-			     struct sk_buff *);
 extern int isdn_net_rcv_skb(int, struct sk_buff *);
 extern void isdn_net_slarp_out(void);
 extern int isdn_net_dial_req(isdn_net_local *);
+extern void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb);
+extern void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb);
+
+#define ISDN_NET_MAX_QUEUE_LENGTH 2
+
+/*
+ * is this particular channel busy?
+ */
+static __inline__ int isdn_net_lp_busy(isdn_net_local *lp)
+{
+	if (atomic_read(&lp->frame_cnt) < ISDN_NET_MAX_QUEUE_LENGTH)
+		return 0;
+	else 
+		return 1;
+}
+
+/*
+ * For the given net device, this will get a non-busy channel out of the
+ * corresponding bundle. The returned channel is locked.
+ */
+static __inline__ isdn_net_local * isdn_net_get_locked_lp(isdn_net_dev *nd)
+{
+	unsigned long flags;
+	isdn_net_local *lp;
+
+	spin_lock_irqsave(&nd->queue_lock, flags);
+	lp = nd->queue;         /* get lp on top of queue */
+	while (isdn_net_lp_busy(nd->queue)) {
+		nd->queue = nd->queue->next;
+		if (nd->queue == lp) { /* not found -- should never happen */
+			lp = NULL;
+			goto errout;
+		}
+	}
+	lp = nd->queue;
+	nd->queue = nd->queue->next;
+errout:
+	spin_unlock_irqrestore(&nd->queue_lock, flags);
+	return lp;
+}
+
+/*
+ * add a channel to a bundle
+ */
+static __inline__ void isdn_net_add_to_bundle(isdn_net_dev *nd, isdn_net_local *nlp)
+{
+	isdn_net_local *lp;
+	unsigned long flags;
+
+	spin_lock_irqsave(&nd->queue_lock, flags);
+
+	lp = nd->queue;
+	nlp->last = lp->last;
+	lp->last->next = nlp;
+	lp->last = nlp;
+	nlp->next = lp;
+	nd->queue = nlp;
+
+	spin_unlock_irqrestore(&nd->queue_lock, flags);
+}
+/*
+ * remove a channel from the bundle it belongs to
+ */
+static __inline__ void isdn_net_rm_from_bundle(isdn_net_local *lp)
+{
+	isdn_net_local *master_lp = lp;
+	unsigned long flags;
+
+	if (lp->master)
+		master_lp = (isdn_net_local *) lp->master->priv;
+
+	spin_lock_irqsave(&master_lp->netdev->queue_lock, flags);
+	lp->last->next = lp->next;
+	lp->next->last = lp->last;
+	if (master_lp->netdev->queue == lp)
+		master_lp->netdev->queue = lp->next;
+	lp->next = lp->last = lp;	/* (re)set own pointers */
+	spin_unlock_irqrestore(&master_lp->netdev->queue_lock, flags);
+}
+
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/isdn_ppp.c linux.19p18/drivers/isdn/isdn_ppp.c
--- linux.vanilla/drivers/isdn/isdn_ppp.c	Mon Dec 11 22:12:45 2000
+++ linux.19p18/drivers/isdn/isdn_ppp.c	Wed Feb 14 14:28:52 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_ppp.c,v 1.63 2000/03/16 15:46:37 kai Exp $
+/* $Id: isdn_ppp.c,v 1.85.6.2 2001/01/23 17:45:02 kai Exp $
  *
  * Linux ISDN subsystem, functions for synchronous PPP (linklevel).
  *
@@ -20,8 +20,6 @@
  *
  */
 
-#define CONFIG_ISDN_CCP 1
-
 #include <linux/config.h>
 #define __NO_VERSION__
 #include <linux/module.h>
@@ -29,6 +27,7 @@
 #include <linux/poll.h>
 #include <linux/isdn.h>
 #include <linux/ppp-comp.h>
+#include <linux/isdn_compat.h>
 
 #include "isdn_common.h"
 #include "isdn_ppp.h"
@@ -38,8 +37,6 @@
 #define PPP_IPX 0x002b
 #endif
 
-/* set this if you use dynamic addressing */
-
 /* Prototypes */
 static int isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot);
 static int isdn_ppp_closewait(int slot);
@@ -48,7 +45,7 @@
 static int isdn_ppp_if_get_unit(char *namebuf);
 static int isdn_ppp_set_compressor(struct ippp_struct *is,struct isdn_ppp_comp_data *);
 static struct sk_buff *isdn_ppp_decompress(struct sk_buff *,
-				struct ippp_struct *,struct ippp_struct *,int proto);
+				struct ippp_struct *,struct ippp_struct *,int *proto);
 static void isdn_ppp_receive_ccp(isdn_net_dev * net_dev, isdn_net_local * lp,
 				struct sk_buff *skb,int proto);
 static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in,int *proto,
@@ -85,11 +82,9 @@
 static void isdn_ppp_mp_cleanup( isdn_net_local * lp );
 
 static int isdn_ppp_bundle(struct ippp_struct *, int unit);
-  
-#define MP_UNLOCK(b)	up(&(b)->lock)
 #endif	/* CONFIG_ISDN_MPP */
   
-char *isdn_ppp_revision = "$Revision: 1.63 $";
+char *isdn_ppp_revision = "$Revision: 1.85.6.2 $";
 
 static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS];
 
@@ -124,55 +119,28 @@
 int
 isdn_ppp_free(isdn_net_local * lp)
 {
-#ifdef CONFIG_ISDN_MPP
-	isdn_net_local *master_lp = NULL;
-#endif
 	unsigned long flags;
 	struct ippp_struct *is;
-	isdn_net_local * nlp;
 
 	if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS)
 		return 0;
 
-	is = ippp_table[lp->ppp_slot];
-
 	save_flags(flags);
 	cli();
-#ifdef CONFIG_ISDN_MPP
-    	spin_lock(&lp->netdev->pb->lock); // irq_save not necessary
-
-	if (lp->master)
-		master_lp = (isdn_net_local *) lp->master->priv;
-
-
-	/* make sure none of the queue pointers will point to the 
-	 * interface being removed */
-	for (nlp=lp->next; nlp != lp; nlp=nlp->next)
-		if (nlp->netdev->queue == lp )
-			nlp->netdev->queue = lp->next;
 
-	lp->last->next = lp->next;
-	lp->next->last = lp->last;
-	
-	if (master_lp && master_lp->netdev->queue == lp)
-		master_lp->netdev->queue = lp->next;
-/*	
-	if (lp->next->netdev->queue == lp)
-		lp->next->netdev->queue = lp->next;
-	if (lp->last->netdev->queue == lp)
-		lp->last->netdev->queue = lp->last;
-*/
+#ifdef CONFIG_ISDN_MPP
+	spin_lock(&lp->netdev->pb->lock);
+#endif
+	isdn_net_rm_from_bundle(lp);
+#ifdef CONFIG_ISDN_MPP
 	if (lp->netdev->pb->ref_ct == 1)	/* last link in queue? */
-			isdn_ppp_mp_cleanup(lp);
-	
-	lp->next = lp->last = lp;	/* (re)set own pointers */
-	lp->netdev->queue = lp;
-	
-	spin_unlock(&lp->netdev->pb->lock);
+		isdn_ppp_mp_cleanup(lp);
+
 	lp->netdev->pb->ref_ct--;
-	
+	spin_unlock(&lp->netdev->pb->lock);
 #endif /* CONFIG_ISDN_MPP */
 
+	is = ippp_table[lp->ppp_slot];
 	if ((is->state & IPPP_CONNECT))
 		isdn_ppp_closewait(lp->ppp_slot);	/* force wakeup on ippp device */
 	else if (is->state & IPPP_ASSIGNED)
@@ -183,8 +151,8 @@
 
 	is->lp = NULL;          /* link is down .. set lp to NULL */
 	lp->ppp_slot = -1;      /* is this OK ?? */
-	restore_flags(flags);
 
+	restore_flags(flags);
 	return 0;
 }
 
@@ -199,12 +167,8 @@
 	long flags;
 	struct ippp_struct *is;
 
-	if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP)
-		return -1;
-
 	save_flags(flags);
 	cli();
-
 	if (lp->pppbind < 0) {  /* device bounded to ippp device ? */
 		isdn_net_dev *net_dev = dev->netdev;
 		char exclusive[ISDN_MAX_CHANNELS];	/* exclusive flags */
@@ -243,7 +207,6 @@
 	}
 	
 	lp->ppp_slot = i;
-
 	is = ippp_table[i];
 	is->lp = lp;
 	is->unit = unit;
@@ -270,8 +233,7 @@
 		return;
 
 	ippp_table[lp->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK;
-	
-	if (ippp_table[lp->ppp_slot]->wq)
+
 		wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq);
 }
 
@@ -289,7 +251,7 @@
 		return 0;
 	is = ippp_table[slot];
 
-	if (is->state && is->wq)
+	if (is->state)
 		wake_up_interruptible(&is->wq);
 
 	is->state = IPPP_CLOSEWAIT;
@@ -350,7 +312,7 @@
 	is->mru = 1524;         /* MRU, default 1524 */
 	is->maxcid = 16;        /* VJ: maxcid */
 	is->tk = current;
-	is->wq = NULL;          /* read() wait queue */
+	init_waitqueue_head(&is->wq);
 	is->first = is->rq + NUM_RCV_BUFFS - 1;	/* receive queue */
 	is->last = is->rq;
 	is->minor = min;
@@ -714,7 +676,6 @@
 	is->last = bl->next;
 	restore_flags(flags);
 
-	if (is->wq)
 		wake_up_interruptible(&is->wq);
 
 	return len;
@@ -805,8 +766,6 @@
 			lp->dialstate == 0 &&
 		    (lp->flags & ISDN_NET_CONNECTED)) {
 			unsigned short hl;
-			unsigned long flags;
-			int cnt;
 			struct sk_buff *skb;
 			/*
 			 * we need to reserve enought space in front of
@@ -829,17 +788,7 @@
 
 			isdn_ppp_send_ccp(lp->netdev,lp,skb); /* keeps CCP/compression states in sync */
 
-			save_flags(flags);
-			cli();
-			if ((cnt = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb)) != count) {
-				if (lp->sav_skb) {
-					dev_kfree_skb(lp->sav_skb);
-					printk(KERN_INFO "isdn_ppp_write: freeing sav_skb (%d,%d)!\n", cnt, count);
-				} else
-					printk(KERN_INFO "isdn_ppp_write: Can't write PPP frame to LL (%d,%d)!\n", cnt, count);
-				lp->sav_skb = skb;
-			}
-			restore_flags(flags);
+			isdn_net_write_super(lp, skb);
 		}
 	}
 	return count;
@@ -899,15 +848,49 @@
 }
 
 /*
+ * check for address/control field and skip if allowed
+ * retval != 0 -> discard packet silently
+ */
+static int isdn_ppp_skip_ac(struct ippp_struct *is, struct sk_buff *skb) 
+{
+	if (skb->len < 1)
+		return -1;
+
+	if (skb->data[0] == 0xff) {
+		if (skb->len < 2)
+			return -1;
+
+		if (skb->data[1] != 0x03)
+			return -1;
+
+		// skip address/control (AC) field
+		skb_pull(skb, 2);
+	} else { 
+		if (is->pppcfg & SC_REJ_COMP_AC)
+			// if AC compression was not negotiated, but used, discard packet
+			return -1;
+	}
+	return 0;
+}
+
+/*
  * get the PPP protocol header and pull skb
+ * retval < 0 -> discard packet silently
  */
 static int isdn_ppp_strip_proto(struct sk_buff *skb) 
 {
 	int proto;
+	
+	if (skb->len < 1)
+		return -1;
+
 	if (skb->data[0] & 0x1) {
+		// protocol field is compressed
 		proto = skb->data[0];
-		skb_pull(skb, 1);   /* protocol ID is only 8 bit */
+		skb_pull(skb, 1);
 	} else {
+		if (skb->len < 2)
+			return -1;
 		proto = ((int) skb->data[0] << 8) + skb->data[1];
 		skb_pull(skb, 2);
 	}
@@ -924,6 +907,9 @@
 	int slot;
 	int proto;
 
+	if (net_dev->local->master)
+		BUG(); // we're called with the master device always
+
 	slot = lp->ppp_slot;
 	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
 		printk(KERN_ERR "isdn_ppp_receive: lp->ppp_slot %d\n", lp->ppp_slot);
@@ -937,135 +923,95 @@
 		       (long)is,(long)lp,lp->ppp_slot,is->unit,(int) skb->len);
 		isdn_ppp_frame_log("receive", skb->data, skb->len, 32,is->unit,lp->ppp_slot);
 	}
-	if (net_dev->local->master) {
-		printk(KERN_WARNING "isdn_ppp_receive: net_dev != master\n");
-		net_dev = ((isdn_net_local *) net_dev->local->master->priv)->netdev;
-	}
-	if (skb->data[0] == 0xff && skb->data[1] == 0x03)
-		skb_pull(skb, 2);
-	else if (is->pppcfg & SC_REJ_COMP_AC) {
-		dev_kfree_skb(skb);
-		return;         /* discard it silently */
-	}
-
-	proto = isdn_ppp_strip_proto(skb);
 
+ 	if (isdn_ppp_skip_ac(is, skb) < 0) {
+ 		kfree_skb(skb);
+ 		return;
+ 	}
+  	proto = isdn_ppp_strip_proto(skb);
+ 	if (proto < 0) {
+ 		kfree_skb(skb);
+ 		return;
+ 	}
+  
 #ifdef CONFIG_ISDN_MPP
-	if (!(is->mpppcfg & SC_REJ_MP_PROT)) {
-
-		if(is->compflags & SC_LINK_DECOMP_ON) {	
-			if(proto == PPP_LINK_COMP) {
-				if(is->debug & 0x10)
-					printk(KERN_DEBUG "received single link compressed frame\n");
-				skb = isdn_ppp_decompress(skb,is,NULL,proto);
-				if(!skb) {
-					printk(KERN_DEBUG "ippp: dropping LINK_COMP frame!\n");
-					return;
-				}
-				proto = isdn_ppp_strip_proto(skb);
-			} else {
-				skb = isdn_ppp_decompress(skb,is,NULL,proto);
-				if(!skb) {
-					printk(KERN_DEBUG "ippp: dropping uncompressed frame!\n");
-					return;
-				}
-			}
-		}
-
-		if (proto == PPP_MP) {
-			isdn_ppp_mp_receive(net_dev, lp, skb);
-		} 
-		else
-			isdn_ppp_push_higher(net_dev, lp, skb, proto);
-	} else
-#endif /* CONFIG_ISDN_MPP */
-		isdn_ppp_push_higher(net_dev, lp, skb, proto);
+ 	if (is->compflags & SC_LINK_DECOMP_ON) {
+ 		skb = isdn_ppp_decompress(skb, is, NULL, &proto);
+ 		if (!skb) // decompression error
+ 			return;
+ 	}
+	
+ 	if (!(is->mpppcfg & SC_REJ_MP_PROT)) { // we agreed to receive MPPP
+  		if (proto == PPP_MP) {
+  			isdn_ppp_mp_receive(net_dev, lp, skb);
+ 			return;
+ 		}
+ 	} 
+#endif
+ 	isdn_ppp_push_higher(net_dev, lp, skb, proto);
 }
 
 /*
- * push frame to higher layers
+ * we receive a reassembled frame, MPPP has been taken care of before.
+ * address/control and protocol have been stripped from the skb
  * note: net_dev has to be master net_dev
  */
 static void
 isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb, int proto)
 {
 	struct device *dev = &net_dev->dev;
-	struct ippp_struct *is;
+ 	struct ippp_struct *is, *mis;
 	int slot;
 
 	slot = lp->ppp_slot;
 	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
 		printk(KERN_ERR "isdn_ppp_push_higher: lp->ppp_slot %d\n", lp->ppp_slot);
-		kfree_skb(skb);
-		return;
+		goto drop_packet;
 	}
 	is = ippp_table[slot];
+ 	
+ 	if (lp->master) { // FIXME?
+ 		slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot;
+ 		if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+ 			printk(KERN_ERR "isdn_ppp_push_higher: master->ppp_slot %d\n", lp->ppp_slot);
+			goto drop_packet;
+ 		}
+ 	}
+ 	mis = ippp_table[slot];
 
 	if (is->debug & 0x10) {
 		printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto);
 		isdn_ppp_frame_log("rpush", skb->data, skb->len, 32,is->unit,lp->ppp_slot);
 	}
-
-	if(proto == PPP_COMP) {
-		if(!lp->master) {
-			skb = isdn_ppp_decompress(skb,is,is,proto);
-		} else {
-			skb = isdn_ppp_decompress(skb,is,ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot],proto);
-		}
-		if(!skb) {
-			printk(KERN_DEBUG "ippp: compressed frame discarded!\n");
-			return;
-		}
-
-		proto = isdn_ppp_strip_proto(skb);
-		if (is->debug & 0x10) {
-			printk(KERN_DEBUG "RPostDecomp, skb %d %04x\n", (int) skb->len, proto);
-			isdn_ppp_frame_log("R-Decomp", skb->data, skb->len, 32,is->unit,lp->ppp_slot);
-		}
-	}
-	else if (is->compflags & SC_DECOMP_ON)  { /* If decomp is ON */
-		if(!lp->master) {
-			skb = isdn_ppp_decompress(skb,is,is,proto);
-		} else {
-			skb = isdn_ppp_decompress(skb,is,ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot],proto);
-		}
-
-		if(!skb) {
-			printk(KERN_DEBUG "ippp: compressed frame discarded!\n");
-			return;
-		}
-	}
-
+	if (is->compflags & SC_DECOMP_ON) {
+		skb = isdn_ppp_decompress(skb, is, mis, &proto);
+		if (!skb) // decompression error
+  			return;
+  	}
 	switch (proto) {
 		case PPP_IPX:  /* untested */
 			if (is->debug & 0x20)
 				printk(KERN_DEBUG "isdn_ppp: IPX\n");
-			skb->dev = dev;
-			skb->mac.raw = skb->data;
 			skb->protocol = htons(ETH_P_IPX);
 			break;
+		case PPP_IP:
+			if (is->debug & 0x20)
+				printk(KERN_DEBUG "isdn_ppp: IP\n");
+			skb->protocol = htons(ETH_P_IP);
+			break;
 #ifdef CONFIG_ISDN_PPP_VJ
 		case PPP_VJC_UNCOMP:
 			if (is->debug & 0x20)
 				printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
 			if (slhc_remember(ippp_table[net_dev->local->ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
 				printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n");
-				net_dev->local->stats.rx_dropped++;
-				dev_kfree_skb(skb);
-				return;
+				goto drop_packet;
 			}
-#endif
-		case PPP_IP:
-			if (is->debug & 0x20)
-				printk(KERN_DEBUG "isdn_ppp: IP\n");
-			skb->dev = dev;
-			skb->mac.raw = skb->data;
 			skb->protocol = htons(ETH_P_IP);
 			break;
 		case PPP_VJC_COMP:
 			if (is->debug & 0x20)
 				printk(KERN_DEBUG "isdn_ppp: VJC_COMP\n");
-#ifdef CONFIG_ISDN_PPP_VJ
 			{
 				struct sk_buff *skb_old = skb;
 				int pkt_len;
@@ -1073,34 +1019,24 @@
 
 				if (!skb) {
 					printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
-					net_dev->local->stats.rx_dropped++;
-					dev_kfree_skb(skb_old);
-					return;
+					skb = skb_old;
+					goto drop_packet;
 				}
-				skb->dev = dev;
 				skb_put(skb, skb_old->len + 128);
 				memcpy(skb->data, skb_old->data, skb_old->len);
-				skb->mac.raw = skb->data;
 				pkt_len = slhc_uncompress(ippp_table[net_dev->local->ppp_slot]->slcomp,
 						skb->data, skb_old->len);
-				dev_kfree_skb(skb_old);
-				if (pkt_len < 0) {
-					dev_kfree_skb(skb);
-					lp->stats.rx_dropped++;
-					return;
-				}
+				kfree_skb(skb_old);
+				if (pkt_len < 0)
+					goto drop_packet;
+
 				skb_trim(skb, pkt_len);
 				skb->protocol = htons(ETH_P_IP);
 			}
-#else
-			printk(KERN_INFO "isdn: Ooopsa .. VJ-Compression support not compiled into isdn driver.\n");
-			lp->stats.rx_dropped++;
-			dev_kfree_skb(skb);
-			return;
-#endif
 			break;
+#endif
 		case PPP_CCP:
-		case PPP_LINK_CCP:
+		case PPP_CCPFRAG:
 			isdn_ppp_receive_ccp(net_dev,lp,skb,proto);
 			/* Dont pop up ResetReq/Ack stuff to the daemon any
 			   longer - the job is done already */
@@ -1110,21 +1046,27 @@
 			/* fall through */
 		default:
 			isdn_ppp_fill_rq(skb->data, skb->len, proto, lp->ppp_slot);	/* push data to pppd device */
-			dev_kfree_skb(skb);
+			kfree_skb(skb);
 			return;
 	}
 
  	/* Reset hangup-timer */
  	lp->huptimer = 0;
-	netif_rx(skb);
-	/* net_dev->local->stats.rx_packets++; *//* done in isdn_net.c */
 
+	skb->dev = dev;
+	skb->mac.raw = skb->data;
+	netif_rx(skb);
+	/* net_dev->local->stats.rx_packets++; done in isdn_net.c */
 	return;
+
+ drop_packet:
+	net_dev->local->stats.rx_dropped++;
+	kfree_skb(skb);
 }
 
 /*
  * isdn_ppp_skb_push ..
- * checks whether we have enough space at the beginning of the SKB
+ * checks whether we have enough space at the beginning of the skb
  * and allocs a new SKB if necessary
  */
 static unsigned char *isdn_ppp_skb_push(struct sk_buff **skb_p,int len)
@@ -1159,20 +1101,13 @@
 int
 isdn_ppp_xmit(struct sk_buff *skb, struct device *netdev)
 {
-	struct device *mdev = ((isdn_net_local *) (netdev->priv))->master;	/* get master (for redundancy) */
 	isdn_net_local *lp,*mlp;
 	isdn_net_dev *nd;
 	unsigned int proto = PPP_IP;     /* 0x21 */
 	struct ippp_struct *ipt,*ipts;
-	unsigned long flags;
 	int slot;
 
-	if (mdev)
-		mlp = (isdn_net_local *) (mdev->priv);
-	else {
-		mdev = netdev;
-		mlp = (isdn_net_local *) (netdev->priv);
-	}
+	mlp = (isdn_net_local *) (netdev->priv);
 	nd = mlp->netdev;       /* get master lp */
 
 	slot = mlp->ppp_slot;
@@ -1197,22 +1132,19 @@
 			proto = PPP_IPX;	/* untested */
 			break;
 		default:
+			printk(KERN_ERR "isdn_ppp: skipped unsupported protocol: %#x.\n", 
+			       skb->protocol);
 			dev_kfree_skb(skb);
-			printk(KERN_ERR "isdn_ppp: skipped frame with unsupported protocol: %#x.\n", skb->protocol);
 			return 0;
 	}
 
-	lp = nd->queue;         /* get lp on top of queue */
-
-	if (lp->sav_skb) {      /* find a non-busy device */
-		isdn_net_local *nlp = lp->next;
-		while (nlp->sav_skb) {
-			if (lp == nlp)
-				return 1;
-			nlp = nd->queue = nd->queue->next;
-		}
-		lp = nlp;
+	lp = isdn_net_get_locked_lp(nd);
+	if (!lp) {
+		printk(KERN_WARNING "%s: all channels busy - requeuing!\n", netdev->name);
+		return 1;
 	}
+	/* we have our lp locked from now on */
+
 	slot = lp->ppp_slot;
 	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
 		printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot %d\n", lp->ppp_slot);
@@ -1227,8 +1159,8 @@
 	 */
 
 	/* Pull off the fake header we stuck on earlier to keep
-     * the fragemntation code happy.
-     */
+	 * the fragmentation code happy.
+	 */
 	skb_pull(skb,IPPP_MAX_HEADER);
 
 	if (ipt->debug & 0x4)
@@ -1301,11 +1233,10 @@
 		/* we get mp_seqno from static isdn_net_local */
 		long mp_seqno = ipts->mp_seqno;
 		ipts->mp_seqno++;
-		nd->queue = nd->queue->next;
 		if (ipt->mpppcfg & SC_OUT_SHORT_SEQ) {
 			unsigned char *data = isdn_ppp_skb_push(&skb, 3);
 			if(!data)
-				return 0;
+				goto unlock;
 			mp_seqno &= 0xfff;
 			data[0] = MP_BEGIN_FRAG | MP_END_FRAG | ((mp_seqno >> 8) & 0xf);	/* (B)egin & (E)ndbit .. */
 			data[1] = mp_seqno & 0xff;
@@ -1313,7 +1244,7 @@
 		} else {
 			unsigned char *data = isdn_ppp_skb_push(&skb, 5);
 			if(!data)
-				return 0;
+				goto unlock;
 			data[0] = MP_BEGIN_FRAG | MP_END_FRAG;	/* (B)egin & (E)ndbit .. */
 			data[1] = (mp_seqno >> 16) & 0xff;	/* sequence number: 24bit */
 			data[2] = (mp_seqno >> 8) & 0xff;
@@ -1333,20 +1264,20 @@
 	if( (ipt->pppcfg & SC_COMP_PROT) && (proto <= 0xff) ) {
 		unsigned char *data = isdn_ppp_skb_push(&skb,1);
 		if(!data)
-			return 0;
+			goto unlock;
 		data[0] = proto & 0xff;
 	}
 	else {
 		unsigned char *data = isdn_ppp_skb_push(&skb,2);
 		if(!data)
-			return 0;
+			goto unlock;
 		data[0] = (proto >> 8) & 0xff;
 		data[1] = proto & 0xff;
 	}
 	if(!(ipt->pppcfg & SC_COMP_AC)) {
 		unsigned char *data = isdn_ppp_skb_push(&skb,2);
 		if(!data)
-			return 0;
+			goto unlock;
 		data[0] = 0xff;    /* All Stations */
 		data[1] = 0x03;    /* Unnumbered information */
 	}
@@ -1357,16 +1288,10 @@
 		printk(KERN_DEBUG "skb xmit: len: %d\n", (int) skb->len);
 		isdn_ppp_frame_log("xmit", skb->data, skb->len, 32,ipt->unit,lp->ppp_slot);
 	}
-	save_flags(flags);
-	cli();
-	if (isdn_net_send_skb(netdev, lp, skb)) {
-		if (lp->sav_skb) {	/* should never happen as sav_skb are sent with disabled IRQs) */
-			printk(KERN_ERR "%s: whoops .. there is another stored skb!\n", netdev->name);
-			dev_kfree_skb(skb);
-		} else
-			lp->sav_skb = skb;
-	}
-	restore_flags(flags);
+	
+	isdn_net_writebuf_skb(lp, skb);
+
+ unlock:
 	return 0;
 }
 
@@ -1397,8 +1322,8 @@
 
 static int isdn_ppp_mp_bundle_array_init(void)
 {
-   int i;
-   int sz = ISDN_MAX_CHANNELS*sizeof(ippp_bundle);
+	int i;
+	int sz = ISDN_MAX_CHANNELS*sizeof(ippp_bundle);
 	if( (isdn_ppp_bundle_arr = (ippp_bundle*)kmalloc(sz, 
 							GFP_KERNEL)) == NULL )
 		return -ENOMEM;
@@ -1410,7 +1335,7 @@
 
 static ippp_bundle * isdn_ppp_mp_bundle_alloc(void)
 {
-    int i;
+	int i;
 	for( i = 0; i < ISDN_MAX_CHANNELS; i++ )
 		if (isdn_ppp_bundle_arr[i].ref_ct <= 0)
 			return (isdn_ppp_bundle_arr + i);
@@ -1419,7 +1344,7 @@
 
 static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to )
 {
-   struct ippp_struct * is = ippp_table[lp->ppp_slot];
+	struct ippp_struct * is = ippp_table[lp->ppp_slot];
    
 	if (add_to) {
 		if( lp->netdev->pb )
@@ -1442,9 +1367,9 @@
 
 static u32 isdn_ppp_mp_get_seq( int short_seq, 
 					struct sk_buff * skb, u32 last_seq );
-struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp,
+static struct sk_buff * isdn_ppp_mp_discard( ippp_bundle * mp,
 			struct sk_buff * from, struct sk_buff * to );
-void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp,
+static void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp,
 				struct sk_buff * from, struct sk_buff * to );
 static void isdn_ppp_mp_free_skb( ippp_bundle * mp, struct sk_buff * skb );
 static void isdn_ppp_mp_print_recv_pkt( int slot, struct sk_buff * skb );
@@ -1452,18 +1377,27 @@
 static void isdn_ppp_mp_receive(isdn_net_dev * net_dev, isdn_net_local * lp, 
 							struct sk_buff *skb)
 {
-	struct ippp_struct *is = ippp_table[lp->ppp_slot];
+	struct ippp_struct *is;
 	isdn_net_local * lpq;
 	ippp_bundle * mp;
 	isdn_mppp_stats * stats;
 	struct sk_buff * newfrag, * frag, * start, *nextf;
 	u32 newseq, minseq, thisseq;
 	unsigned long flags;
-    
-    	spin_lock_irqsave(&net_dev->pb->lock, flags);
+	int slot;
+
+	spin_lock_irqsave(&net_dev->pb->lock, flags);
     	mp = net_dev->pb;
         stats = &mp->stats;
-	
+	slot = lp->ppp_slot;
+	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR "isdn_ppp_mp_receive: lp->ppp_slot %d\n", lp->ppp_slot);
+		stats->frame_drops++;
+		dev_kfree_skb(skb);
+		spin_unlock_irqrestore(&mp->lock, flags);
+		return;
+	}
+	is = ippp_table[slot];
     	if( ++mp->frames > stats->max_queue_len )
 		stats->max_queue_len = mp->frames;
 	
@@ -1491,9 +1425,14 @@
 	/* find the minimum received sequence number over all links */
 	is->last_link_seqno = minseq = newseq;
 	for (lpq = net_dev->queue;;) {
-	   u32 lls = ippp_table[lpq->ppp_slot]->last_link_seqno;
-		if (MP_LT(lls, minseq))
-			minseq = lls;
+		slot = lpq->ppp_slot;
+		if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+			printk(KERN_ERR "isdn_ppp_mp_receive: lpq->ppp_slot %d\n", lpq->ppp_slot);
+		} else {
+			u32 lls = ippp_table[slot]->last_link_seqno;
+			if (MP_LT(lls, minseq))
+				minseq = lls;
+		}
 		if ((lpq = lpq->next) == net_dev->queue)
 			break;
 	}
@@ -1645,20 +1584,19 @@
 	 * queue overflow */
 	if (mp->frames > MP_MAX_QUEUE_LEN) {
 		stats->overflows++;
-		while (mp->frames < MP_MAX_QUEUE_LEN) {
+		while (mp->frames > MP_MAX_QUEUE_LEN) {
 			frag = mp->frags->next;
 			isdn_ppp_mp_free_skb(mp, mp->frags);
 			mp->frags = frag;
 		}
 	}
-	
 	spin_unlock_irqrestore(&mp->lock, flags);
 }
 
 static void isdn_ppp_mp_cleanup( isdn_net_local * lp )
 {
-    struct sk_buff * frag = lp->netdev->pb->frags;
-    struct sk_buff * nextfrag;
+	struct sk_buff * frag = lp->netdev->pb->frags;
+	struct sk_buff * nextfrag;
     	while( frag ) {
 		nextfrag = frag->next;
 		isdn_ppp_mp_free_skb(lp->netdev->pb, frag);
@@ -1670,8 +1608,8 @@
 static u32 isdn_ppp_mp_get_seq( int short_seq, 
 					struct sk_buff * skb, u32 last_seq )
 {
-   u32 seq;
-   int flags = skb->data[0] & (MP_BEGIN_FRAG | MP_END_FRAG);
+	u32 seq;
+	int flags = skb->data[0] & (MP_BEGIN_FRAG | MP_END_FRAG);
    
    	if( !short_seq )
 	{
@@ -1716,46 +1654,40 @@
 void isdn_ppp_mp_reassembly( isdn_net_dev * net_dev, isdn_net_local * lp,
 				struct sk_buff * from, struct sk_buff * to )
 {
-   ippp_bundle * mp = net_dev->pb;
-   int proto;
-   struct sk_buff * skb;
-   unsigned int tot_len;
-   
-   	if( MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG) )
-	{
+	ippp_bundle * mp = net_dev->pb;
+	int proto;
+	struct sk_buff * skb;
+	unsigned int tot_len;
+
+	if( MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG) ) {
 		if( ippp_table[lp->ppp_slot]->debug & 0x40 )
 			printk(KERN_DEBUG"isdn_mppp: reassembly: frame %d, "
 					"len %d\n", MP_SEQ(from), from->len );
 		skb = from;
 		skb_pull(skb, MP_HEADER_LEN);
 		mp->frames--;	
-	}
-	else
-	{
-	    struct sk_buff * frag;
-	    int n;
-	    
-		for( tot_len=0, frag=from, n = 0; frag != to; 
-							frag=frag->next, n++ )
+	} else {
+		struct sk_buff * frag;
+		int n;
+
+		for(tot_len=n=0, frag=from; frag != to; frag=frag->next, n++)
 			tot_len += frag->len - MP_HEADER_LEN;
-		
+
 		if( ippp_table[lp->ppp_slot]->debug & 0x40 )
 			printk(KERN_DEBUG"isdn_mppp: reassembling frames %d "
 				"to %d, len %d\n", MP_SEQ(from), 
 				(MP_SEQ(from)+n-1) & MP_LONGSEQ_MASK, tot_len );
-		
-		if( (skb = dev_alloc_skb(tot_len)) == NULL )
-		{
-			printk(KERN_ERR"isdn_mppp: cannot allocate sk buff "
+		if( (skb = dev_alloc_skb(tot_len)) == NULL ) {
+			printk(KERN_ERR "isdn_mppp: cannot allocate sk buff "
 					"of size %d\n", tot_len);
 			isdn_ppp_mp_discard(mp, from, to);
 			return;
 		}
-		
-		while( from != to )
-		{
-		   unsigned int len = from->len - MP_HEADER_LEN;
-		   	memcpy(skb_put(skb,len), from->data+MP_HEADER_LEN, len);
+
+		while( from != to ) {
+			unsigned int len = from->len - MP_HEADER_LEN;
+
+			memcpy(skb_put(skb,len), from->data+MP_HEADER_LEN, len);
 			frag = from->next;
 			isdn_ppp_mp_free_skb(mp, from);
 			from = frag; 
@@ -1784,15 +1716,13 @@
 {
 	char ifn[IFNAMSIZ + 1];
 	isdn_net_dev *p;
-	isdn_net_local *lp,
-	*nlp;
+	isdn_net_local *lp, *nlp;
 	int rc;
 	unsigned long flags;
 
 	sprintf(ifn, "ippp%d", unit);
 	p = isdn_net_findif(ifn);
-	if (!p)
-	{
+	if (!p) {
 		printk(KERN_ERR "ippp_bundle: cannot find %s\n", ifn);
 		return -EINVAL;
 	}
@@ -1800,38 +1730,29 @@
     	spin_lock_irqsave(&p->pb->lock, flags);
 
 	nlp = is->lp;
-
 	lp = p->queue;
-	
 	if( nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ||
-		lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS )
-	{
-		spin_unlock_irqrestore(&p->pb->lock, flags);
+		lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS ) {
 		printk(KERN_ERR "ippp_bundle: binding to invalid slot %d\n",
-		   nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ? 
-		   				nlp->ppp_slot : lp->ppp_slot );
-		return -EINVAL;
-	}
-	
-	nlp->last = lp->last;
-	lp->last->next = nlp;
-	lp->last = nlp;
-	nlp->next = lp;
-	p->queue = nlp;
+			nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ? 
+			nlp->ppp_slot : lp->ppp_slot );
+		rc = -EINVAL;
+		goto out;
+ 	}
+
+	isdn_net_add_to_bundle(p, nlp);
 
 	ippp_table[nlp->ppp_slot]->unit = ippp_table[lp->ppp_slot]->unit;
-/* maybe also SC_CCP stuff */
-	ippp_table[nlp->ppp_slot]->pppcfg |= ippp_table[lp->ppp_slot]->pppcfg &
-	    (SC_ENABLE_IP | SC_NO_TCP_CCID | SC_REJ_COMP_TCP);
 
+	/* maybe also SC_CCP stuff */
+	ippp_table[nlp->ppp_slot]->pppcfg |= ippp_table[lp->ppp_slot]->pppcfg &
+		(SC_ENABLE_IP | SC_NO_TCP_CCID | SC_REJ_COMP_TCP);
 	ippp_table[nlp->ppp_slot]->mpppcfg |= ippp_table[lp->ppp_slot]->mpppcfg &
-	    (SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ);
-
- 	rc = isdn_ppp_mp_init(nlp, p->pb);
-  
+		(SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ);
+	rc = isdn_ppp_mp_init(nlp, p->pb);
+out:
 	spin_unlock_irqrestore(&p->pb->lock, flags);
-  
- 	return rc;
+	return rc;
 }
   
 #endif /* CONFIG_ISDN_MPP */
@@ -2051,8 +1972,7 @@
 {
 	struct sk_buff *skb;
 	unsigned char *p;
-	int count, hl;
-	unsigned long flags;
+	int hl;
 	int cnt = 0;
 	isdn_net_local *lp = is->lp;
 
@@ -2093,26 +2013,7 @@
 	printk(KERN_DEBUG "Sending CCP Frame:\n");
 	isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,lp->ppp_slot);
 
-	/* Just ripped from isdn_ppp_write. Dunno whether it makes sense,
-	   especially dunno what the sav_skb stuff is good for. */
-
-	count = skb->len;
-	save_flags(flags);
-	cli();
-	if ((cnt = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel,
-					  1, skb)) != count) {
-		if (lp->sav_skb) {
-			dev_kfree_skb(lp->sav_skb);
-			printk(KERN_INFO
-			       "isdn_ppp_write: freeing sav_skb (%d,%d)!\n",
-			       cnt, count);
-		} else
-			printk(KERN_INFO
-			       "isdn_ppp_write: Can't write PPP frame to LL (%d,%d)!\n",
-			       cnt, count);
-		lp->sav_skb = skb;
-	}
-	restore_flags(flags);
+	isdn_net_write_super(lp, skb);
 }
 
 /* Allocate the reset state vector */
@@ -2359,17 +2260,21 @@
 	is->reset->lastid++;
 }
 
+/* 
+ * decompress packet
+ *
+ * if master = 0, we're trying to uncompress an per-link compressed packet,
+ * as opposed to an compressed reconstructed-from-MPPP packet.
+ * proto is updated to protocol field of uncompressed packet.
+ *
+ * retval: decompressed packet,
+ *         same packet if uncompressed,
+ *	   NULL if decompression error
+ */
+
 static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb,struct ippp_struct *is,struct ippp_struct *master,
-	int proto)
+	int *proto)
 {
-#ifndef CONFIG_ISDN_CCP
-	if(proto == PPP_COMP || proto == PPP_LINK_COMP) {
-		printk(KERN_ERR "isdn_ppp: Ouch! Compression not included!\n");
-		dev_kfree_skb(skb);
-		return NULL;
-	}
-	return skb;
-#else
 	void *stat = NULL;
 	struct isdn_ppp_compressor *ipc = NULL;
 	struct sk_buff *skb_out;
@@ -2379,83 +2284,65 @@
 	unsigned char rsdata[IPPP_RESET_MAXDATABYTES];
 
 	if(!master) {
-		/* 
-		 * single link decompression 
-		 */
-		if(!is->link_decompressor) {
-			printk(KERN_DEBUG "ippp: no link decompressor defined!\n");
-			return skb;
-		}
-		if(!is->link_decomp_stat) {
-			printk(KERN_DEBUG "ippp: no link decompressor data allocated\n");
-			return skb;
-		}
+		// per-link decompression 
 		stat = is->link_decomp_stat;
 		ipc = is->link_decompressor;
 		ri = is;
-	}
-	else {
-		/*
-		 * 'normal' or bundle-compression 
-		 */
-		if(!master->decompressor) {
-			printk(KERN_DEBUG "ippp: no decompressor defined!\n");
-			return skb;
-		}
-		if(!master->decomp_stat) {
-			printk(KERN_DEBUG "ippp: no decompressor data allocated\n");
-			return skb;
-		}
+	} else {
 		stat = master->decomp_stat;
 		ipc = master->decompressor;
 		ri = master;
 	}
 
-	/*
-	printk(KERN_DEBUG "ippp: Decompress valid!\n");
-	*/
+	if (!ipc) {
+		// no decompressor -> we can't decompress.
+		printk(KERN_DEBUG "ippp: no decompressor defined!\n");
+		return skb;
+	}
+	if (!stat) // if we have a compressor, stat has been set as well
+		BUG();
 
-	if((master && proto == PPP_COMP) || (!master && proto == PPP_LINK_COMP) ) {
-		/* Set up reset params for the decompressor */
-		memset(&rsparm, 0, sizeof(rsparm));
-		rsparm.data = rsdata;
-		rsparm.maxdlen = IPPP_RESET_MAXDATABYTES;
+	if((master && *proto == PPP_COMP) || (!master && *proto == PPP_COMPFRAG) ) {
+		// compressed packets are compressed by their protocol type
 
-/* !!!HACK,HACK,HACK!!! 2048 is only assumed */
-		skb_out = dev_alloc_skb(2048);
-		len = ipc->decompress(stat,skb,skb_out, &rsparm);
-		dev_kfree_skb(skb);
-		if(len <= 0) {
-		  /* Ok, some error */
-		  switch(len) {
-		  case DECOMP_ERROR:
-		    ri->pppcfg |= SC_DC_ERROR;
-		    printk(KERN_INFO "ippp: decomp wants reset %s params\n",
-			   rsparm.valid ? "with" : "without");
-
-		    isdn_ppp_ccp_reset_trans(ri, &rsparm);
-
-		    break;
-		  case DECOMP_FATALERROR:
-		    ri->pppcfg |= SC_DC_FERROR;
-		    /* Kick ipppd to recognize the error */
-		    isdn_ppp_ccp_kickup(ri);
-		    break;
-		  }
-		  /* Did I see a leak here ? */
-		  dev_kfree_skb(skb_out);
-		  return NULL;
+		// Set up reset params for the decompressor
+  		memset(&rsparm, 0, sizeof(rsparm));
+  		rsparm.data = rsdata;
+  		rsparm.maxdlen = IPPP_RESET_MAXDATABYTES;
+  
+  		skb_out = dev_alloc_skb(is->mru + PPP_HDRLEN);
+		len = ipc->decompress(stat, skb, skb_out, &rsparm);
+		kfree_skb(skb);
+		if (len <= 0) {
+			switch(len) {
+			case DECOMP_ERROR:
+				ri->pppcfg |= SC_DC_ERROR;
+				printk(KERN_INFO "ippp: decomp wants reset %s params\n",
+				       rsparm.valid ? "with" : "without");
+				
+				isdn_ppp_ccp_reset_trans(ri, &rsparm);
+				break;
+			case DECOMP_FATALERROR:
+				ri->pppcfg |= SC_DC_FERROR;
+				/* Kick ipppd to recognize the error */
+				isdn_ppp_ccp_kickup(ri);
+				break;
+			}
+			kfree_skb(skb_out);
+			return NULL;
+		}
+		*proto = isdn_ppp_strip_proto(skb_out);
+		if (*proto < 0) {
+			kfree_skb(skb_out);
+			return NULL;
 		}
 		return skb_out;
-	}
-	else {
-		/*
-		printk(KERN_DEBUG "isdn_ppp: [%d] Calling incomp with this frame!\n",is->unit);
-		*/
-		ipc->incomp(stat,skb,proto);
+	} else { 
+		// uncompressed packets are fed through the decompressor to
+		// update the decompressor state
+		ipc->incomp(stat, skb, *proto);
 		return skb;
 	}
-#endif
 }
 
 /*
@@ -2474,13 +2361,9 @@
     void *stat;
     struct sk_buff *skb_out;
 
-#ifdef CONFIG_ISDN_CCP
 	/* we do not compress control protocols */
     if(*proto < 0 || *proto > 0x3fff) {
-#else
-    {
-#endif
-      return skb_in;
+	    return skb_in;
     }
 
 	if(type) { /* type=1 => Link compression */
@@ -2681,7 +2564,7 @@
 	}
 
 	proto = ((int)data[0]<<8)+data[1];
-	if(proto != PPP_CCP && proto != PPP_LINK_CCP)
+	if(proto != PPP_CCP && proto != PPP_CCPFRAG)
 		return;
 
 	printk(KERN_DEBUG "Received CCP frame from daemon:\n");
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/isdn_tty.c linux.19p18/drivers/isdn/isdn_tty.c
--- linux.vanilla/drivers/isdn/isdn_tty.c	Mon Dec 11 22:12:45 2000
+++ linux.19p18/drivers/isdn/isdn_tty.c	Mon Feb 12 15:09:50 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_tty.c,v 1.93 2000/08/05 09:58:26 armin Exp $
+/* $Id: isdn_tty.c,v 1.94 2000/11/25 17:00:59 kai Exp $
 
  * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel).
  *
@@ -53,14 +53,20 @@
 #define MODEM_PARANOIA_CHECK
 #define MODEM_DO_RESTART
 
+#ifdef CONFIG_DEVFS_FS
+static char *isdn_ttyname_ttyI = "isdn/ttyI%d";
+static char *isdn_ttyname_cui = "isdn/cui%d";
+#else
 static char *isdn_ttyname_ttyI = "ttyI";
 static char *isdn_ttyname_cui = "cui";
+#endif
+
 static int bit2si[8] =
 {1, 5, 7, 7, 7, 7, 7, 7};
 static int si2bit[8] =
 {4, 1, 4, 4, 4, 4, 4, 4};
 
-char *isdn_tty_revision = "$Revision: 1.84 $";
+char *isdn_tty_revision = "$Revision: 1.94 $";
 
 
 /* isdn_tty_try_read() is called from within isdn_tty_rcv_skb()
@@ -1177,6 +1183,7 @@
 	int c;
 	int total = 0;
 	modem_info *info = (modem_info *) tty->driver_data;
+	atemu *m = &info->emu;
 
 	if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_write"))
 		return 0;
@@ -1197,8 +1204,6 @@
 		    || (info->vonline & 3)
 #endif
 			) {
-			atemu *m = &info->emu;
-
 #ifdef CONFIG_ISDN_AUDIO
 			if (!info->vonline)
 #endif
@@ -1256,7 +1261,9 @@
 					isdn_command(&c);
 				}
 				info->vonline = 0;
-				printk(KERN_DEBUG "fax dle cc/c %d/%d\n", cc,c);
+#ifdef ISDN_DEBUG_MODEM_VOICE
+				printk(KERN_DEBUG "fax dle cc/c %d/%d\n", cc, c);
+#endif
 				info->xmit_count += cc;
 			} else
 #endif
@@ -1278,9 +1285,14 @@
 		count -= c;
 		total += c;
 	}
-	if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue)))
-		isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);
 	atomic_dec(&info->xmit_lock);
+	if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue))) {
+		if (m->mdmreg[REG_DXMT] & BIT_DXMT) {
+			isdn_tty_senddown(info);
+			isdn_tty_tint(info);
+		}
+		isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);
+	}
 	if (from_user)
 		up(&info->write_sem);
 	return total;
@@ -1621,8 +1633,7 @@
 static int
 isdn_tty_block_til_ready(struct tty_struct *tty, struct file *filp, modem_info * info)
 {
-	struct wait_queue wait =
-	{current, NULL};
+	DECLARE_WAITQUEUE(wait, NULL);
 	int do_clocal = 0;
 	unsigned long flags;
 	int retval;
@@ -1700,7 +1711,7 @@
 	restore_flags(flags);
 	info->blocked_open++;
 	while (1) {
-		current->state = TASK_INTERRUPTIBLE;
+		set_current_state(TASK_INTERRUPTIBLE);
 		if (tty_hung_up_p(filp) ||
 		    !(info->flags & ISDN_ASYNC_INITIALIZED)) {
 #ifdef MODEM_DO_RESTART
@@ -1873,7 +1884,7 @@
 		 */
 		timeout = jiffies + HZ;
 		while (!(info->lsr & UART_LSR_TEMT)) {
-			current->state = TASK_INTERRUPTIBLE;
+			set_current_state(TASK_INTERRUPTIBLE);
 			schedule_timeout(20);
 			if (time_after(jiffies,timeout))
 				break;
@@ -1889,7 +1900,7 @@
 	info->ncarrier = 0;
 	tty->closing = 0;
 	if (info->blocked_open) {
-		current->state = TASK_INTERRUPTIBLE;
+		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout(50);
 		wake_up_interruptible(&info->open_wait);
 	}
@@ -2091,7 +2102,7 @@
 			return -3;
 		}
 #endif
-		info->write_sem = MUTEX;
+		init_MUTEX(&info->write_sem);
 		sprintf(info->last_cause, "0000");
 		sprintf(info->last_num, "none");
 		info->last_dir = 0;
@@ -2108,8 +2119,8 @@
 		info->blocked_open = 0;
 		info->callout_termios = m->cua_modem.init_termios;
 		info->normal_termios = m->tty_modem.init_termios;
-		info->open_wait = 0;
-		info->close_wait = 0;
+		init_waitqueue_head(&info->open_wait);
+		init_waitqueue_head(&info->close_wait);
 		info->isdn_driver = -1;
 		info->isdn_channel = -1;
 		info->drv_index = -1;
@@ -2364,11 +2375,21 @@
 #ifdef ISDN_TTY_STAT_DEBUG
 				printk(KERN_DEBUG "tty_STAT_BCONN ttyI%d\n", info->line);
 #endif
+				/* Wake up any processes waiting
+				 * for incoming call of this device when
+				 * DCD follow the state of incoming carrier
+				 */
+				if (info->blocked_open &&
+				   (info->emu.mdmreg[REG_DCD] & BIT_DCD)) {
+					wake_up_interruptible(&info->open_wait);
+				}
+
 				/* Schedule CONNECT-Message to any tty
 				 * waiting for it and
 				 * set DCD-bit of its modem-status.
 				 */
-				if (TTY_IS_ACTIVE(info)) {
+				if (TTY_IS_ACTIVE(info) ||
+				    (info->blocked_open && (info->emu.mdmreg[REG_DCD] & BIT_DCD))) {
 					info->msr |= UART_MSR_DCD;
 					info->emu.charge = 0;
 					if (info->dialing & 0xf)
@@ -2609,7 +2630,7 @@
 				if ((jiffies - *lastplus) < PLUSWAIT2)
 					*pluscount = 0;
 			}
-			if ((*pluscount == 3) && (count = 1))
+			if ((*pluscount == 3) && (count == 1))
 				isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, 1);
 			if (*pluscount > 3)
 				*pluscount = 1;
@@ -2822,8 +2843,8 @@
 	int limit = ISDN_MSNLEN - 1;
 
 	while (((*p[0] >= '0' && *p[0] <= '9') ||
-	       /* Why a comma ??? */
-	       (*p[0] == ',')) &&
+		/* Why a comma ??? */
+		(*p[0] == ',') || (*p[0] == ':')) &&
 		(limit--))
 		*n++ = *p[0]++;
 	*n = '\0';
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/isdn_tty.h linux.19p18/drivers/isdn/isdn_tty.h
--- linux.vanilla/drivers/isdn/isdn_tty.h	Mon Dec 11 22:12:45 2000
+++ linux.19p18/drivers/isdn/isdn_tty.h	Wed Dec 13 22:11:20 2000
@@ -57,6 +57,8 @@
 #define REG_CPPP     12
 #define BIT_CPPP    128
 
+#define REG_DXMT     13
+#define BIT_DXMT      1
 #define REG_T70      13
 #define BIT_T70       2
 #define BIT_T70_EXT  32
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/isdn_v110.c linux.19p18/drivers/isdn/isdn_v110.c
--- linux.vanilla/drivers/isdn/isdn_v110.c	Mon Dec 11 22:12:45 2000
+++ linux.19p18/drivers/isdn/isdn_v110.c	Tue Feb 13 18:50:53 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn_v110.c,v 1.5 2000/05/11 22:29:21 kai Exp $
+/* $Id: isdn_v110.c,v 1.5.6.2 2001/02/10 14:41:19 kai Exp $
 
  * Linux ISDN subsystem, V.110 related functions (linklevel).
  *
@@ -22,7 +22,7 @@
 
 #include <linux/string.h>
 #include <linux/kernel.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/mm.h>
 
 #include <linux/isdn.h>
@@ -30,7 +30,7 @@
 
 #undef ISDN_V110_DEBUG
 
-char *isdn_v110_revision = "$Revision: 1.5 $";
+char *isdn_v110_revision = "$Revision: 1.5.6.2 $";
 
 #define V110_38400 255
 #define V110_19200  15
@@ -102,7 +102,7 @@
 	int i;
 	isdn_v110_stream *v;
 
-	if ((v = kmalloc(sizeof(isdn_v110_stream), GFP_KERNEL)) == NULL)
+	if ((v = kmalloc(sizeof(isdn_v110_stream), GFP_ATOMIC)) == NULL)
 		return NULL;
 	memset(v, 0, sizeof(isdn_v110_stream));
 	v->key = key;
@@ -134,7 +134,7 @@
 	v->b = 0;
 	v->skbres = hdrlen;
 	v->maxsize = maxsize - hdrlen;
-	if ((v->encodebuf = kmalloc(maxsize, GFP_KERNEL)) == NULL) {
+	if ((v->encodebuf = kmalloc(maxsize, GFP_ATOMIC)) == NULL) {
 		kfree(v);
 		return NULL;
 	}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/isdnloop/Makefile linux.19p18/drivers/isdn/isdnloop/Makefile
--- linux.vanilla/drivers/isdn/isdnloop/Makefile	Fri Apr 21 12:46:12 2000
+++ linux.19p18/drivers/isdn/isdnloop/Makefile	Tue Feb 13 18:38:13 2001
@@ -1,11 +1,14 @@
-L_OBJS :=
-M_OBJS :=
+#
+# Makefile for the isdnloop ISDN device driver
+#
 
-ifeq ($(CONFIG_ISDN_DRV_LOOP),y)
-  L_OBJS += isdnloop.o
-else
-  M_OBJS += isdnloop.o
-endif
+# The target object and module list name.
 
-include $(TOPDIR)/Rules.make
+O_TARGET	:= vmlinux-obj.o
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_ISDN_DRV_LOOP)	+= isdnloop.o
+
+include $(TOPDIR)/drivers/isdn/Rules.make
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/isdnloop/isdnloop.c linux.19p18/drivers/isdn/isdnloop/isdnloop.c
--- linux.vanilla/drivers/isdn/isdnloop/isdnloop.c	Mon Dec 11 22:12:46 2000
+++ linux.19p18/drivers/isdn/isdnloop/isdnloop.c	Tue Feb 13 18:50:53 2001
@@ -1,4 +1,4 @@
-/* $Id: isdnloop.c,v 1.11 2000/11/13 22:51:50 kai Exp $
+/* $Id: isdnloop.c,v 1.11.6.1 2000/12/17 16:47:18 kai Exp $
 
  * ISDN low-level module implementing a dummy loop driver.
  *
@@ -21,10 +21,12 @@
  */
 
 #include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
 #include "isdnloop.h"
 
 static char
-*revision = "$Revision: 1.11 $";
+*revision = "$Revision: 1.11.6.1 $";
 
 static int isdnloop_addcard(char *);
 
@@ -1534,22 +1536,7 @@
 	return 0;
 }
 
-#ifdef MODULE
-#define isdnloop_init init_module
-#else
-void
-isdnloop_setup(char *str, int *ints)
-{
-	static char sid[20];
-
-	if (strlen(str)) {
-		strcpy(sid, str);
-		isdnloop_id = sid;
-	}
-}
-#endif
-
-int
+static int __init
 isdnloop_init(void)
 {
 	char *p;
@@ -1568,9 +1555,8 @@
 	return (isdnloop_addcard(isdnloop_id));
 }
 
-#ifdef MODULE
-void
-cleanup_module(void)
+static void 
+isdnloop_exit(void)
 {
 	isdn_ctrl cmd;
 	isdnloop_card *card = cards;
@@ -1598,4 +1584,6 @@
 	}
 	printk(KERN_NOTICE "isdnloop-ISDN-driver unloaded\n");
 }
-#endif
+
+module_init(isdnloop_init);
+module_exit(isdnloop_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/isdnloop/isdnloop.h linux.19p18/drivers/isdn/isdnloop/isdnloop.h
--- linux.vanilla/drivers/isdn/isdnloop/isdnloop.h	Mon Dec 11 22:12:46 2000
+++ linux.19p18/drivers/isdn/isdnloop/isdnloop.h	Sun Mar 11 13:13:35 2001
@@ -1,4 +1,4 @@
-/* $Id: isdnloop.h,v 1.5 2000/11/13 22:51:50 kai Exp $
+/* $Id: isdnloop.h,v 1.5.6.1 2001/02/10 14:41:23 kai Exp $
 
  * Loopback lowlevel module for testing of linklevel.
  *
@@ -53,7 +53,7 @@
 #include <asm/io.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
 #include <linux/ioport.h>
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/pcbit/Makefile linux.19p18/drivers/isdn/pcbit/Makefile
--- linux.vanilla/drivers/isdn/pcbit/Makefile	Fri Apr 21 12:46:12 2000
+++ linux.19p18/drivers/isdn/pcbit/Makefile	Tue Feb 13 18:38:13 2001
@@ -1,15 +1,21 @@
-L_OBJS :=
-M_OBJS :=
-O_OBJS := module.o edss1.o drv.o layer2.o capi.o callbacks.o 
-
-O_TARGET :=
-ifeq ($(CONFIG_ISDN_DRV_PCBIT),y)
-  O_TARGET += pcbit.o
-else
-  ifeq ($(CONFIG_ISDN_DRV_PCBIT),m)
-    O_TARGET += pcbit.o
-    M_OBJS += pcbit.o
-  endif
-endif
+# Makefile for the pcbit ISDN device driver
 
-include $(TOPDIR)/Rules.make
+# The target object and module list name.
+
+O_TARGET	:= vmlinux-obj.o
+
+# Multipart objects.
+
+list-multi	:= pcbit.o
+pcbit-objs	:= module.o edss1.o drv.o layer2.o capi.o callbacks.o
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_ISDN_DRV_PCBIT)	+= pcbit.o
+
+include $(TOPDIR)/drivers/isdn/Rules.make
+
+# Link rules for multi-part drivers.
+
+pcbit.o: $(pcbit-objs)
+	$(LD) -r -o $@ $(pcbit-objs)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/pcbit/callbacks.c linux.19p18/drivers/isdn/pcbit/callbacks.c
--- linux.vanilla/drivers/isdn/pcbit/callbacks.c	Fri Apr 21 12:46:12 2000
+++ linux.19p18/drivers/isdn/pcbit/callbacks.c	Tue Feb 13 18:50:53 2001
@@ -27,7 +27,7 @@
 #include <linux/kernel.h>
 
 #include <linux/types.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/tqueue.h>
 #include <linux/skbuff.h>
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/pcbit/capi.c linux.19p18/drivers/isdn/pcbit/capi.c
--- linux.vanilla/drivers/isdn/pcbit/capi.c	Fri Apr 21 12:46:12 2000
+++ linux.19p18/drivers/isdn/pcbit/capi.c	Tue Feb 13 18:50:53 2001
@@ -37,7 +37,7 @@
 #include <linux/kernel.h>
 
 #include <linux/types.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/mm.h>
 
 #include <linux/tqueue.h>
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/pcbit/drv.c linux.19p18/drivers/isdn/pcbit/drv.c
--- linux.vanilla/drivers/isdn/pcbit/drv.c	Fri Apr 21 12:46:12 2000
+++ linux.19p18/drivers/isdn/pcbit/drv.c	Tue Feb 13 18:50:53 2001
@@ -28,7 +28,7 @@
 #include <linux/kernel.h>
 
 #include <linux/types.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <linux/string.h>
@@ -86,6 +86,7 @@
 
 	dev_pcbit[board] = dev;
 	memset(dev, 0, sizeof(struct pcbit_dev));
+	init_waitqueue_head(&dev->set_running_wq);
 
 	if (mem_base >= 0xA0000 && mem_base <= 0xFFFFF ) {
 		dev->ph_mem = mem_base;
@@ -118,8 +119,6 @@
 	memset(dev->b2, 0, sizeof(struct pcbit_chan));
 	dev->b2->id = 1;
 
-
-	dev->qdelivery.next = NULL;
 	dev->qdelivery.sync = 0;
 	dev->qdelivery.routine = pcbit_deliver;
 	dev->qdelivery.data = dev;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/pcbit/edss1.c linux.19p18/drivers/isdn/pcbit/edss1.c
--- linux.vanilla/drivers/isdn/pcbit/edss1.c	Fri Apr 21 12:46:12 2000
+++ linux.19p18/drivers/isdn/pcbit/edss1.c	Tue Feb 13 18:50:53 2001
@@ -26,7 +26,7 @@
 #include <linux/kernel.h>
 
 #include <linux/types.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/tqueue.h>
 #include <linux/skbuff.h>
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/pcbit/layer2.c linux.19p18/drivers/isdn/pcbit/layer2.c
--- linux.vanilla/drivers/isdn/pcbit/layer2.c	Fri Apr 21 12:46:12 2000
+++ linux.19p18/drivers/isdn/pcbit/layer2.c	Tue Feb 13 18:50:53 2001
@@ -40,7 +40,7 @@
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/tqueue.h>
 #include <linux/mm.h>
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/pcbit/module.c linux.19p18/drivers/isdn/pcbit/module.c
--- linux.vanilla/drivers/isdn/pcbit/module.c	Fri Apr 21 12:46:12 2000
+++ linux.19p18/drivers/isdn/pcbit/module.c	Tue Feb 13 18:50:53 2001
@@ -12,7 +12,7 @@
  */
 
 #include <linux/module.h>
-
+#include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
@@ -26,21 +26,12 @@
 static int irq[MAX_PCBIT_CARDS] = {0, };
 
 static int num_boards;
-struct pcbit_dev * dev_pcbit[MAX_PCBIT_CARDS] = {0, 0, 0, 0};
-
-int init_module(void);
-void cleanup_module(void);
+struct pcbit_dev * dev_pcbit[MAX_PCBIT_CARDS] = {0, };
 
 extern void pcbit_terminate(int board);
 extern int pcbit_init_dev(int board, int mem_base, int irq);
 
-#ifdef MODULE
-MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_PCBIT_CARDS) "i");
-MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_PCBIT_CARDS) "i");
-#define pcbit_init init_module
-#endif
-
-int pcbit_init(void)
+static int __init pcbit_init(void)
 {
 	int board;
 
@@ -83,15 +74,10 @@
 		else
 			return -EIO;
 	}
-
-	/* No symbols to export, hide all symbols */
-	EXPORT_NO_SYMBOLS;
-
 	return 0;
 }
 
-#ifdef MODULE
-void cleanup_module(void)
+static void  pcbit_exit(void)
 {
 	int board;
 
@@ -101,7 +87,7 @@
 	       "PCBIT-D module unloaded\n");
 }
 
-#else
+#ifndef MODULE
 void pcbit_setup(char *str, int *ints)
 {
 	int i, j, argc;
@@ -126,5 +112,9 @@
 }
 #endif
 
+MODULE_PARM(mem, "1-" __MODULE_STRING(MAX_PCBIT_CARDS) "i");
+MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_PCBIT_CARDS) "i");
 
+module_init(pcbit_init);
+module_exit(pcbit_exit);
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/pcbit/pcbit.h linux.19p18/drivers/isdn/pcbit/pcbit.h
--- linux.vanilla/drivers/isdn/pcbit/pcbit.h	Fri Apr 21 12:46:12 2000
+++ linux.19p18/drivers/isdn/pcbit/pcbit.h	Tue Feb 13 18:50:53 2001
@@ -69,7 +69,7 @@
 	struct frame_buf *write_queue;
 
 	/* Protocol start */
-	struct wait_queue *set_running_wq;
+	wait_queue_head_t set_running_wq;
 	struct timer_list set_running_timer;
 
 	struct timer_list error_recover_timer;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/sc/Makefile linux.19p18/drivers/isdn/sc/Makefile
--- linux.vanilla/drivers/isdn/sc/Makefile	Fri Apr 21 12:46:14 2000
+++ linux.19p18/drivers/isdn/sc/Makefile	Tue Feb 13 18:38:13 2001
@@ -1,44 +1,22 @@
-#
-#  $Id: Makefile,v 1.1 1997/03/22 02:01:22 fritz Exp $
-#  Copyright (C) 1996  SpellCaster Telecommunications Inc.
-#
-#  This program is free software; you can redistribute it and/or modify
-#  it under the terms of the GNU General Public License as published by
-#  the Free Software Foundation; either version 2 of the License, or
-#  (at your option) any later version.
-#
-#  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.
-#
-#  For more information, please contact gpl-info@spellcast.com or write:
-#
-#     SpellCaster Telecommunications Inc.
-#     5621 Finch Avenue East, Unit #3
-#     Scarborough, Ontario  Canada
-#     M1B 2T9
-#     +1 (416) 297-8565
-#     +1 (416) 297-6433 Facsimile
-#
-
-L_OBJS :=
-M_OBJS :=
-O_OBJS := shmem.o init.o debug.o packet.o command.o event.o \
-	ioctl.o interrupt.o message.o timer.o
-
-O_TARGET :=
-ifeq ($(CONFIG_ISDN_DRV_SC),y)
-	O_TARGET += sc.o
-else
-  ifeq ($(CONFIG_ISDN_DRV_SC),m)
-    O_TARGET += sc.o
-    M_OBJS += sc.o
-  endif
-endif
+# Makefile for the sc ISDN device driver
 
-include $(TOPDIR)/Rules.make
+# The target object and module list name.
+
+O_TARGET	:= vmlinux-obj.o
+
+# Multipart objects.
+
+list-multi	:= sc.o
+sc-objs		:= shmem.o init.o debug.o packet.o command.o event.o \
+		   ioctl.o interrupt.o message.o timer.o	
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_ISDN_DRV_SC)	+= sc.o
+
+include $(TOPDIR)/drivers/isdn/Rules.make
+
+# Link rules for multi-part drivers.
+
+sc.o: $(sc-objs)
+	$(LD) -r -o $@ $(sc-objs)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/sc/debug.c linux.19p18/drivers/isdn/sc/debug.c
--- linux.vanilla/drivers/isdn/sc/debug.c	Fri Apr 21 12:46:13 2000
+++ linux.19p18/drivers/isdn/sc/debug.c	Wed Dec 13 22:10:59 2000
@@ -1,5 +1,5 @@
 /*
- *  $Id: debug.c,v 1.3 1997/10/01 09:22:20 fritz Exp $
+ *  $Id: debug.c,v 1.5 2000/11/12 15:29:37 kai Exp $
  *  Copyright (C) 1996  SpellCaster Telecommunications Inc.
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -27,11 +27,6 @@
  */
 #include <linux/kernel.h>
 
-#define NULL	0x0
-
-#define REQUEST_IRQ(a,b,c,d,e) request_irq(a,b,c,d,e)
-#define FREE_IRQ(a,b) free_irq(a,b)
-
 inline char *strcpy(char *, const char *);
 
 int dbg_level = 0;
@@ -61,7 +56,7 @@
 		*i = *j;
 		i++; j++;
 	}
-	*(++i) = NULL;
+	*(++i) = 0;
 	return dest;
 }
 
@@ -70,6 +65,6 @@
 	int i = 0;
 
 	while(dn[i] != ',')
-		str[i] = dn[i++];
+		str[i] = dn[i], i++;
 	str[i] = 0x0;
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/sc/debug.h linux.19p18/drivers/isdn/sc/debug.h
--- linux.vanilla/drivers/isdn/sc/debug.h	Fri Apr 21 12:46:13 2000
+++ linux.19p18/drivers/isdn/sc/debug.h	Wed Dec 13 22:11:07 2000
@@ -1,5 +1,5 @@
 /*
- *  $Id: debug.h,v 1.1 1996/11/07 13:07:42 fritz Exp $
+ *  $Id: debug.h,v 1.2 2000/02/26 01:00:53 keil Exp $
  *  Copyright (C) 1996  SpellCaster Telecommunications Inc.
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -26,10 +26,5 @@
  *     +1 (416) 297-6433 Facsimile
  */
 
-#if LINUX_VERSION_CODE < 131072
-	#error You cant use this driver on kernels older than 2.0
-#else
-	#define REQUEST_IRQ(a,b,c,d,e) request_irq(a,b,c,d,e)
-	#define FREE_IRQ(a,b) free_irq(a,b)
-#endif
-
+#define REQUEST_IRQ(a,b,c,d,e) request_irq(a,b,c,d,e)
+#define FREE_IRQ(a,b) free_irq(a,b)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/sc/includes.h linux.19p18/drivers/isdn/sc/includes.h
--- linux.vanilla/drivers/isdn/sc/includes.h	Fri Apr 21 12:46:13 2000
+++ linux.19p18/drivers/isdn/sc/includes.h	Sun Mar 11 13:13:42 2001
@@ -5,7 +5,7 @@
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/kernel.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/ioport.h>
 #include <linux/timer.h>
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/sc/init.c linux.19p18/drivers/isdn/sc/init.c
--- linux.vanilla/drivers/isdn/sc/init.c	Fri Apr 21 12:46:13 2000
+++ linux.19p18/drivers/isdn/sc/init.c	Tue Feb 13 18:50:53 2001
@@ -1,3 +1,5 @@
+#include <linux/module.h>
+#include <linux/init.h>
 #include "includes.h"
 #include "hardware.h"
 #include "card.h"
@@ -37,23 +39,12 @@
 	return 0;
 }
 
-#ifdef MODULE
 MODULE_PARM(io, "1-4i");
 MODULE_PARM(irq, "1-4i");
 MODULE_PARM(ram, "1-4i");
 MODULE_PARM(do_reset, "i");
-#define init_sc init_module
-#else
-/*
-Initialization code for non-module version to be included
 
-void sc_setup(char *str, int *ints)
-{
-}
-*/
-#endif
-
-int init_sc(void)
+static int __init sc_init(void)
 {
 	int b = -1;
 	int i, j;
@@ -164,7 +155,7 @@
 		if(do_reset) {
 			pr_debug("Doing a SAFE probe reset\n");
 			outb(0xFF, io[b] + RESET_OFFSET);
-			current->state = TASK_INTERRUPTIBLE;
+			set_current_state(TASK_INTERRUPTIBLE);
 			schedule_timeout(milliseconds(10000));
 		}
 		pr_debug("RAM Base for board %d is 0x%x, %s probe\n", b, ram[b],
@@ -302,7 +293,7 @@
 			/*
 			 * No interrupt could be used
 			 */
-			pr_debug("Failed to aquire an IRQ line\n");
+			pr_debug("Failed to acquire an IRQ line\n");
 			continue;
 		}
 
@@ -410,8 +401,7 @@
 	return status;
 }
 
-#ifdef MODULE
-void cleanup_module(void)
+static void  sc_exit(void)
 {
 	int i, j;
 
@@ -463,7 +453,6 @@
 	}
 	pr_info("SpellCaster ISA ISDN Adapter Driver Unloaded.\n");
 }
-#endif
 
 int identify_board(unsigned long rambase, unsigned int iobase) 
 {
@@ -512,7 +501,7 @@
 	 * Try to identify a PRI card
 	 */
 	outb(PRI_BASEPG_VAL, pgport);
-	current->state = TASK_INTERRUPTIBLE;
+	set_current_state(TASK_INTERRUPTIBLE);
 	schedule_timeout(HZ);
 	sig = readl(rambase + SIG_OFFSET);
 	pr_debug("Looking for a signature, got 0x%x\n", sig);
@@ -523,7 +512,7 @@
 	 * Try to identify a PRI card
 	 */
 	outb(BRI_BASEPG_VAL, pgport);
-	current->state = TASK_INTERRUPTIBLE;
+	set_current_state(TASK_INTERRUPTIBLE);
 	schedule_timeout(HZ);
 	sig = readl(rambase + SIG_OFFSET);
 	pr_debug("Looking for a signature, got 0x%x\n", sig);
@@ -555,7 +544,7 @@
 	 */
 	x = 0;
 	while((inb(iobase + FIFOSTAT_OFFSET) & RF_HAS_DATA) && x < 100) {
-		current->state = TASK_INTERRUPTIBLE;
+		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout(1);
 		x++;
 	}
@@ -579,3 +568,6 @@
 		
 	return -1;
 }
+
+module_init(sc_init);
+module_exit(sc_exit);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/sc/message.c linux.19p18/drivers/isdn/sc/message.c
--- linux.vanilla/drivers/isdn/sc/message.c	Fri Apr 21 12:46:14 2000
+++ linux.19p18/drivers/isdn/sc/message.c	Wed Dec 13 22:11:13 2000
@@ -266,7 +266,7 @@
 	tries = 0;
 	/* wait for the response */
 	while (tries < timeout) {
-		current->state = TASK_INTERRUPTIBLE;
+		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout(1);
 		
 		pr_debug("SAR waiting..\n");
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/isdn/sc/timer.c linux.19p18/drivers/isdn/sc/timer.c
--- linux.vanilla/drivers/isdn/sc/timer.c	Fri Apr 21 12:46:14 2000
+++ linux.19p18/drivers/isdn/sc/timer.c	Wed Dec 13 22:11:13 2000
@@ -1,5 +1,5 @@
 /*
- *  $Id: timer.c,v 1.2 1996/11/20 17:49:57 fritz Exp $
+ *  $Id: timer.c,v 1.3 2000/05/06 00:52:39 kai Exp $
  *  Copyright (C) 1996  SpellCaster Telecommunications Inc.
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -91,9 +91,7 @@
 	else  {
 		pr_debug("%s: No signature yet, waiting another %d jiffies.\n", 
 			adapter[card]->devicename, CHECKRESET_TIME);
-		del_timer(&adapter[card]->reset_timer);
-		adapter[card]->reset_timer.expires = jiffies + CHECKRESET_TIME;
-		add_timer(&adapter[card]->reset_timer);
+		mod_timer(&adapter[card]->reset_timer, jiffies+CHECKRESET_TIME);
 	}
 	restore_flags(flags);
 		
@@ -138,9 +136,7 @@
 	/* Reinitialize the timer */
 	save_flags(flags);
 	cli();
-	del_timer(&adapter[card]->stat_timer);
-	adapter[card]->stat_timer.expires = jiffies + CHECKSTAT_TIME;
-	add_timer(&adapter[card]->stat_timer);
+	mod_timer(&adapter[card]->stat_timer, jiffies+CHECKSTAT_TIME);
 	restore_flags(flags);
 
 	/* Send a new cePhyStatus message */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/macintosh/mac_hid.c linux.19p18/drivers/macintosh/mac_hid.c
--- linux.vanilla/drivers/macintosh/mac_hid.c	Mon Dec 11 22:12:46 2000
+++ linux.19p18/drivers/macintosh/mac_hid.c	Thu Feb  1 15:10:49 2001
@@ -184,8 +184,6 @@
 
 int mac_hid_kbd_translate(unsigned char keycode, unsigned char *keycodep,
 			  char raw_mode);
-static int mac_hid_sysctl_keycodes(ctl_table *ctl, int write, struct file * filp,
-				   void *buffer, size_t *lenp);
 char mac_hid_kbd_unexpected_up(unsigned char keycode);
 
 static int keyboard_lock_keycodes = 0;
@@ -194,6 +192,8 @@
 int keyboard_sends_linux_keycodes = 1;
 #endif /* CONFIG_MAC_ADBKEYCODES */
 
+static int mac_hid_sysctl_keycodes(ctl_table *ctl, int write, struct file * filp,
+				   void *buffer, size_t *lenp);
 
 static unsigned char e0_keys[128] = {
 	0, 0, 0, KEY_KPCOMMA, 0, KEY_INTL3, 0, 0,		/* 0x00-0x07 */
@@ -225,22 +225,25 @@
 
 extern void pckbd_init_hw(void);
 
-#if defined CONFIG_SYSCTL && (defined(CONFIG_MAC_ADBKEYCODES) || defined(CONFIG_MAC_EMUMOUSEBTN))
+#ifdef CONFIG_SYSCTL
 /* file(s) in /proc/sys/dev/mac_hid */
 ctl_table mac_hid_files[] =
 {
-#ifdef CONFIG_MAC_ADBKEYCODES
   {
+    /* Leave it available when ADB keycodes are disabled for the sanity of
+     * distro installers...
+     */
     DEV_MAC_HID_KEYBOARD_SENDS_LINUX_KEYCODES,
     "keyboard_sends_linux_keycodes", &keyboard_sends_linux_keycodes, sizeof(int),
     0644, NULL, &mac_hid_sysctl_keycodes
   },
+#ifdef CONFIG_MAC_ADBKEYCODES
   {
     DEV_MAC_HID_KEYBOARD_LOCK_KEYCODES,
     "keyboard_lock_keycodes", &keyboard_lock_keycodes, sizeof(int),
     0644, NULL, &proc_dointvec
   },
-#endif
+#endif /* CONFIG_MAC_ADBKEYCODES */
 #ifdef CONFIG_MAC_EMUMOUSEBTN
   {
     DEV_MAC_HID_MOUSE_BUTTON_EMULATION,
@@ -257,7 +260,7 @@
     "mouse_button3_keycode", &mouse_button3_keycode, sizeof(int),
     0644, NULL, &proc_dointvec
   },
-#endif
+#endif /* CONFIG_MAC_EMUMOUSEBTN */
   { 0 }
 };
 
@@ -277,11 +280,13 @@
 
 static struct ctl_table_header *mac_hid_sysctl_header;
 
-#ifdef CONFIG_MAC_ADBKEYCODES
 static
 int mac_hid_sysctl_keycodes(ctl_table *ctl, int write, struct file * filp,
 			    void *buffer, size_t *lenp)
 {
+#ifndef CONFIG_MAC_ADBKEYCODES
+	return write ? 0 : proc_dointvec(ctl, write, filp, buffer, lenp);
+#else /* CONFIG_MAC_ADBKEYCODES */
 	int val = keyboard_sends_linux_keycodes;
 	int ret = 0;
 
@@ -293,14 +298,14 @@
 	    && keyboard_sends_linux_keycodes != val) {
 		if (!keyboard_sends_linux_keycodes) {
 #ifdef CONFIG_MAGIC_SYSRQ
-			ppc_md.ppc_kbd_sysrq_xlate   = mac_hid_kbd_sysrq_xlate;
+			ppc_md.sysrq_xlate   = mac_hid_kbd_sysrq_xlate;
 			SYSRQ_KEY                = 0x69;
 #endif
 			memcpy(pc_key_maps_save, key_maps, sizeof(key_maps));
 			memcpy(key_maps, mac_key_maps_save, sizeof(key_maps));
 		} else {
 #ifdef CONFIG_MAGIC_SYSRQ
-			ppc_md.ppc_kbd_sysrq_xlate   = pckbd_sysrq_xlate;
+			ppc_md.sysrq_xlate   = pckbd_sysrq_xlate;
 			SYSRQ_KEY                = 0x54;
 #endif
 			memcpy(mac_key_maps_save, key_maps, sizeof(key_maps));
@@ -309,8 +314,8 @@
 	}
 
 	return ret;
+#endif /* CONFIG_MAC_ADBKEYCODES */
 }
-#endif
 #endif /* endif CONFIG_SYSCTL */
 
 int mac_hid_kbd_translate(unsigned char scancode, unsigned char *keycode,
@@ -486,7 +491,7 @@
 		pckbd_init_hw();
 #endif
 
-#if defined(CONFIG_SYSCTL) && (defined(CONFIG_MAC_ADBKEYCODES) || defined(CONFIG_MAC_EMUMOUSEBTN))
+#ifdef CONFIG_SYSCTL
 	mac_hid_sysctl_header = register_sysctl_table(mac_hid_root_dir, 1);
 #endif /* CONFIG_SYSCTL */
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/3c527.c linux.19p18/drivers/net/3c527.c
--- linux.vanilla/drivers/net/3c527.c	Mon Dec 11 22:12:47 2000
+++ linux.19p18/drivers/net/3c527.c	Sat Mar  3 22:27:43 2001
@@ -1,9 +1,8 @@
-
-/* 3c527.c: 3Com Etherlink/MC32 driver for Linux
+/* 3c527.c: 3Com Etherlink/MC32 driver for Linux 2.2
  *
  *	(c) Copyright 1998 Red Hat Software Inc
- *	Written by Alan Cox.
- *	Further debugging by Carl Drougge.
+ *	Written by Alan Cox. 
+ *      Modified by Richard Procter (rnp@netlink.co.nz)
  *
  *	Based on skeleton.c written 1993-94 by Donald Becker and ne2.c
  *	(for the MCA stuff) written by Wim Dumon.
@@ -12,26 +11,70 @@
  *	documentation.
  *
  *	This software may be used and distributed according to the terms
- *	of the GNU Public License, incorporated herein by reference.
+ *	of the GNU General Public License, incorporated herein by reference.
  *
  */
 
 static const char *version =
-	"3c527.c:v0.08 2000/02/22 Alan Cox (alan@redhat.com)\n";
+	"3c527.c:v0.5 1999/09/16 Alan Cox (alan@redhat.com)\n";
 
-/*
- *	Things you need
- *	o	The databook.
- *
- *	Traps for the unwary
+/**
+ * DOC: Traps for the unwary
  *
  *	The diagram (Figure 1-1) and the POS summary disagree with the
  *	"Interrupt Level" section in the manual.
  *
+ *	The manual contradicts itself when describing the minimum number 
+ *	buffers in the 'configure lists' command. 
+ *	My card accepts a buffer config of 4/4. 
+ *
+ *	Setting the SAV BP bit does not save bad packets, but
+ *	only enables RX on-card stats collection. 
+ *
  *	The documentation in places seems to miss things. In actual fact
  *	I've always eventually found everything is documented, it just
  *	requires careful study.
- */
+ *
+ * DOC: Theory Of Operation
+ *
+ *	The 3com 3c527 is a 32bit MCA bus mastering adapter with a large
+ *	amount of on board intelligence that housekeeps a somewhat dumber
+ *	Intel NIC. For performance we want to keep the transmit queue deep
+ *	as the card can transmit packets while fetching others from main
+ *	memory by bus master DMA. Transmission and reception are driven by
+ *	circular buffer queues.
+ *
+ *	The mailboxes can be used for controlling how the card traverses
+ *	its buffer rings, but are used only for inital setup in this
+ *	implementation.  The exec mailbox allows a variety of commands to
+ *	be executed. Each command must complete before the next is
+ *	executed. Primarily we use the exec mailbox for controlling the
+ *	multicast lists.  We have to do a certain amount of interesting
+ *	hoop jumping as the multicast list changes can occur in interrupt
+ *	state when the card has an exec command pending. We defer such
+ *	events until the command completion interrupt.
+ *
+ *	A copy break scheme (taken from 3c59x.c) is employed whereby
+ *	received frames exceeding a configurable length are passed
+ *	directly to the higher networking layers without incuring a copy,
+ *	in what amounts to a time/space trade-off.
+ *	 
+ *	The card also keeps a large amount of statistical information
+ *	on-board. In a perfect world, these could be used safely at no
+ *	cost. However, lacking information to the contrary, processing
+ *	them without races would involve so much extra complexity as to
+ *	make it unworthwhile to do so. In the end, a hybrid SW/HW
+ *	implementation was made necessary --- see mc32_update_stats().  
+ *
+ * DOC: Notes
+ *	
+ *	It should be possible to use two or more cards, but at this stage
+ *	only by loading two copies of the same module.
+ *
+ *	The on-board 82586 NIC has trouble receiving multiple
+ *	back-to-back frames and so is likely to drop packets from fast
+ *	senders.
+**/
 
 #include <linux/module.h>
 
@@ -56,6 +99,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
+#include <linux/if_ether.h>
 
 #include "3c527.h"
 
@@ -69,23 +113,36 @@
 #ifndef NET_DEBUG
 #define NET_DEBUG 2
 #endif
+
+#undef DEBUG_IRQ
+
 static unsigned int mc32_debug = NET_DEBUG;
 
 /* The number of low I/O ports used by the ethercard. */
-#define NETCARD_IO_EXTENT	8
+#define MC32_IO_EXTENT	8
 
+/* As implemented, values must be a power-of-2 -- 4/8/16/32 */ 
+#define TX_RING_LEN     32       /* Typically the card supports 37  */
+#define RX_RING_LEN     8        /*     "       "        "          */
+
+/* Copy break point, see above for details. 
+ * Setting to > 1512 effectively disables this feature.	*/	    
+#define RX_COPYBREAK    200      /* Value from 3c59x.c */
+
+/* Issue the 82586 workaround command - this is for "busy lans", but
+ * basically means for all lans now days - has a performance (latency) 
+ * cost, but best set. */ 
+static const int WORKAROUND_82586=1;
 
-struct mc32_mailbox
+/* Pointers to buffers and their on-card records */
+struct mc32_ring_desc 
 {
-	u16	mbox __attribute((packed));
-	u16	data[1] __attribute((packed));
+  volatile struct skb_header *p;                    
+  struct sk_buff *skb;          
 };
 
-/* Information that need to be kept for each board. */
-
-#define TX_RING_MAX	16	/* Typically the card supports 37 */
-#define RX_RING_MAX	32	/*        "     "       "         */
 
+/* Information that needs to be kept for each board. */
 struct mc32_local 
 {
 	struct net_device_stats net_stats;
@@ -93,25 +150,28 @@
 	volatile struct mc32_mailbox *rx_box;
 	volatile struct mc32_mailbox *tx_box;
 	volatile struct mc32_mailbox *exec_box;
-	volatile u16 *stats;
-	u16 tx_chain;
-	u16 rx_chain;
-	u16 tx_len;
-	u16 rx_len;
+        volatile struct mc32_stats *stats;    /* Start of on-card statistics */
+        u16 tx_chain;           /* Transmit list start offset */
+	u16 rx_chain;           /* Receive list start offset */
+        u16 tx_len;             /* Transmit list count */ 
+        u16 rx_len;             /* Receive list count */
+
 	u32 base;
-	u16 rx_halted;
-	u16 tx_halted;
-	u16 rx_pending;		/* ring due a service */
 	u16 exec_pending;
 	u16 mc_reload_wait;	/* a multicast load request is pending */
-	atomic_t tx_count;		/* buffers left */
+	u32 mc_list_valid;	/* True when the mclist is set */
+	u16 xceiver_state;      /* Current transceiver state. bitmapped */ 
+	u16 desired_state;      /* The state we want the transceiver to be in */ 
+	atomic_t tx_count;	/* buffers left */
 	struct wait_queue *event;
-	struct sk_buff *tx_skb[TX_RING_MAX];	/* Transmit ring */
-	u16 tx_skb_top;
-	u16 tx_skb_end;
-	struct sk_buff *rx_skb[RX_RING_MAX];	/* Receive ring */
-	void *rx_ptr[RX_RING_MAX];		/* Data pointers */
-	u32 mc_list_valid;			/* True when the mclist is set */
+
+	struct mc32_ring_desc tx_ring[TX_RING_LEN];	/* Host Transmit ring */
+	struct mc32_ring_desc rx_ring[RX_RING_LEN];	/* Host Receive ring */
+
+	u16 tx_ring_tail;       /* index to tx de-queue end */
+	u16 tx_ring_head;       /* index to tx en-queue end */
+
+	u16 rx_ring_tail;       /* index to rx de-queue end */ 
 };
 
 /* The station (ethernet) address prefix, used for a sanity check. */
@@ -124,18 +184,25 @@
 	char		*name;
 };
 
-static struct mca_adapters_t mc32_adapters[] __initdata = {
+const struct mca_adapters_t mc32_adapters[] = {
 	{ 0x0041, "3COM EtherLink MC/32" },
 	{ 0x8EF5, "IBM High Performance Lan Adapter" },
 	{ 0x0000, NULL }
 };
 
 
-/* Index to functions, as function prototypes. */
+/* Macros for ring index manipulations */ 
+static inline u16 next_rx(u16 rx) { return (rx+1)&(RX_RING_LEN-1); };
+static inline u16 prev_rx(u16 rx) { return (rx-1)&(RX_RING_LEN-1); };
 
+static inline u16 next_tx(u16 tx) { return (tx+1)&(TX_RING_LEN-1); };
+
+
+/* Index to functions, as function prototypes. */
 extern int mc32_probe(struct device *dev);
 
 static int	mc32_probe1(struct device *dev, int ioaddr);
+static int      mc32_command(struct device *dev, u16 cmd, void *data, int len);
 static int	mc32_open(struct device *dev);
 static int	mc32_send_packet(struct sk_buff *skb, struct device *dev);
 static void	mc32_interrupt(int irq, void *dev_id, struct pt_regs *regs);
@@ -144,12 +211,14 @@
 static void	mc32_set_multicast_list(struct device *dev);
 static void	mc32_reset_multicast_list(struct device *dev);
 
-/*
- * Check for a network adaptor of this type, and return '0' iff one exists.
- * If dev->base_addr == 0, probe all likely locations.
- * If dev->base_addr == 1, always return failure.
- * If dev->base_addr == 2, allocate space for the device and return success
- * (detachable devices only).
+/**
+ * mc32_probe:
+ * @dev: device to probe
+ *
+ * Because MCA bus is a real bus and we can scan for cards we could do a
+ * single scan for all boards here. Right now we use the passed in device
+ * structure and scan for only one board. This needs fixing for modules
+ * in paticular.
  */
 
 __initfunc(int mc32_probe(struct device *dev))
@@ -183,15 +252,21 @@
 	return -ENODEV;
 }
 
-/*
- * This is the real probe routine. Linux has a history of friendly device
- * probes on the ISA bus. A good device probes avoids doing writes, and
- * verifies that the correct device exists and functions.
+/**
+ * mc32_probe1:
+ * @dev:  Device structure to fill in
+ * @slot: The MCA bus slot being used by this card
+ *
+ * Decode the slot data and configure the card structures. Having done this we
+ * can reset the card and configure it. The card does a full self test cycle
+ * in firmware so we have to wait for it to return and post us either a 
+ * failure case or some addresses we use to find the board internals.
  */
+
 __initfunc(static int mc32_probe1(struct device *dev, int slot))
 {
 	static unsigned version_printed = 0;
-	int i;
+	int i, err;
 	u8 POS;
 	u32 base;
 	struct mc32_local *lp;
@@ -224,7 +299,7 @@
 		"82586 initialisation failure",
 		"Adapter list configuration error"
 	};
-	
+
 	/* Time to play MCA games */
 
 	if (mc32_debug  &&  version_printed++ == 0)
@@ -327,20 +402,21 @@
 	 *	Grab the IRQ
 	 */
 
-	if(request_irq(dev->irq, &mc32_interrupt, 0, cardname, dev))
-	{
-		printk("%s: unable to get IRQ %d.\n",
-				   dev->name, dev->irq);
-		return -EAGAIN;
+	i = request_irq(dev->irq, &mc32_interrupt, SA_SHIRQ, dev->name, dev); 
+	if(i) {
+		printk("%s: unable to get IRQ %d.\n", dev->name, dev->irq);
+		return i; 
 	}
 
+	request_region(dev->base_addr, MC32_IO_EXTENT, cardname);
+
 	/* Initialize the device structure. */
 	if (dev->priv == NULL) {
 		dev->priv = kmalloc(sizeof(struct mc32_local), GFP_KERNEL);
-		if (dev->priv == NULL)
+		if (dev->priv == NULL)	
 		{
-			free_irq(dev->irq, dev);
-			return -ENOMEM;
+			err = -ENOMEM;
+			goto err_exit_irq; 
 		}
 	}
 
@@ -358,8 +434,8 @@
 		if(i==1000)
 		{
 			printk("%s: failed to boot adapter.\n", dev->name);
-			free_irq(dev->irq, dev);
-			return -ENODEV;
+			err = -ENODEV; 
+			goto err_exit_free;
 		}
 		udelay(1000);
 		if(inb(dev->base_addr+2)&(1<<5))
@@ -373,8 +449,8 @@
 				base<0x0A?" test failure":"");
 		else
 			printk("%s: unknown failure %d.\n", dev->name, base);
-		free_irq(dev->irq, dev);
-		return -ENODEV;
+		err = -ENODEV; 
+		goto err_exit_free;
 	}
 	
 	base=0;
@@ -389,8 +465,8 @@
 			if(n>100)
 			{
 				printk(KERN_ERR "%s: mailbox read fail (%d).\n", dev->name, i);
-				free_irq(dev->irq, dev);
-				return -ENODEV;
+				err = -ENODEV;
+				goto err_exit_free;
 			}
 		}
 
@@ -399,11 +475,11 @@
 	
 	lp->exec_box=bus_to_virt(dev->mem_start+base);
 	
-	base=lp->exec_box->data[1]<<16|lp->exec_box->data[0];
+	base=lp->exec_box->data[1]<<16|lp->exec_box->data[0];  
 	
 	lp->base = dev->mem_start+base;
 	
-	lp->rx_box=bus_to_virt(lp->base + lp->exec_box->data[2]);
+	lp->rx_box=bus_to_virt(lp->base + lp->exec_box->data[2]); 
 	lp->tx_box=bus_to_virt(lp->base + lp->exec_box->data[3]);
 	
 	lp->stats = bus_to_virt(lp->base + lp->exec_box->data[5]);
@@ -412,74 +488,77 @@
 	 *	Descriptor chains (card relative)
 	 */
 	 
-	lp->tx_chain 		= lp->exec_box->data[8];
-	lp->rx_chain 		= lp->exec_box->data[10];
-	lp->tx_len 		= lp->exec_box->data[9];
-	lp->rx_len 		= lp->exec_box->data[11];
-	
-	printk("%s: %d RX buffers, %d TX buffers. Base of 0x%08X.\n",
-		dev->name, lp->rx_len, lp->tx_len, lp->base);
+	lp->tx_chain 		= lp->exec_box->data[8];   /* Transmit list start offset */
+	lp->rx_chain 		= lp->exec_box->data[10];  /* Receive list start offset */
+	lp->tx_len 		= lp->exec_box->data[9];   /* Transmit list count */ 
+	lp->rx_len 		= lp->exec_box->data[11];  /* Receive list count */
 	
-	if(lp->tx_len >TX_RING_MAX)
-		lp->tx_len = TX_RING_MAX;
-		
+	printk("%s: Firmware Rev %d. %d RX buffers, %d TX buffers. Base of 0x%08X.\n",
+		dev->name, lp->exec_box->data[12], lp->rx_len, lp->tx_len, lp->base);
+
 	dev->open		= mc32_open;
 	dev->stop		= mc32_close;
 	dev->hard_start_xmit	= mc32_send_packet;
 	dev->get_stats		= mc32_get_stats;
 	dev->set_multicast_list = mc32_set_multicast_list;
 	
-	lp->rx_halted		= 1;
-	lp->tx_halted		= 1;
-	lp->rx_pending		= 0;
+	lp->xceiver_state = HALTED; 
+	
+	lp->tx_ring_tail=lp->tx_ring_head=0;
 
 	/* Fill in the fields of the device structure with ethernet values. */
 	ether_setup(dev);
+	
 	return 0;
+
+err_exit_free:
+	kfree(dev->priv);
+err_exit_irq:
+	free_irq(dev->irq, dev);
+	release_region(dev->base_addr, MC32_IO_EXTENT);
+	return err;
 }
 
 
-/*
- *	Polled command stuff 
+/**
+ *	mc32_ready_poll:
+ *	@dev:	The device to wait for
+ *	
+ *	Wait until the card becomes ready to accept a command via the
+ *	command register. This tells us nothing about the completion
+ *	status of any pending commands and takes very little time at all.
  */
  
-static void mc32_ring_poll(struct device *dev)
+static void mc32_ready_poll(struct device *dev)
 {
 	int ioaddr = dev->base_addr;
 	while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
 }
 
 
-/*
- *	Send exec commands. This requires a bit of explaining.
+/**
+ *	mc32_command_nowait:
+ *	@dev: The 3c527 to issue the command to
+ *	@cmd: The command word to write to the mailbox
+ *	@data: A data block if the command expects one
+ *	@len: Length of the data block
  *
- *	You feed the card a command, you wait, it interrupts you get a 
- *	reply. All well and good. The complication arises because you use
- *	commands for filter list changes which come in at bh level from things
- *	like IPV6 group stuff.
- *
- *	We have a simple state machine
- *
- *	0	- nothing issued
- *	1	- command issued, wait reply
- *	2	- reply waiting - reader then goes to state 0
- *	3	- command issued, trash reply. In which case the irq
- *		  takes it back to state 0
- */
- 
-
-/*
- *	Send command from interrupt state
+ *	Send a command from interrupt state. If there is a command
+ *	currently being executed then we return an error of -1. It simply
+ *	isn't viable to wait around as commands may be slow. Providing we
+ *	get in, we busy wait for the board to become ready to accept the
+ *	command and issue it. We do not wait for the command to complete
+ *	--- the card will interrupt us when it's done.
  */
 
 static int mc32_command_nowait(struct device *dev, u16 cmd, void *data, int len)
 {
 	struct mc32_local *lp = (struct mc32_local *)dev->priv;
 	int ioaddr = dev->base_addr;
-	
+
 	if(lp->exec_pending)
 		return -1;
-		
+	
 	lp->exec_pending=3;
 	lp->exec_box->mbox=0;
 	lp->exec_box->mbox=cmd;
@@ -493,9 +572,35 @@
 }
 
 
-/*
- *	Send command and block for results. On completion spot and reissue
- *	multicasts
+/**
+ *	mc32_command: 
+ *	@dev: The 3c527 card to issue the command to
+ *	@cmd: The command word to write to the mailbox
+ *	@data: A data block if the command expects one
+ *	@len: Length of the data block
+ *
+ *	Sends exec commands in a user context. This permits us to wait around
+ *	for the replies and also to wait for the command buffer to complete
+ *	from a previous command before we execute our command. After our 
+ *	command completes we will complete any pending multicast reload
+ *	we blocked off by hogging the exec buffer.
+ *
+ *	You feed the card a command, you wait, it interrupts you get a 
+ *	reply. All well and good. The complication arises because you use
+ *	commands for filter list changes which come in at bh level from things
+ *	like IPV6 group stuff.
+ *
+ *	We have a simple state machine
+ *
+ *	0	- nothing issued
+ *
+ *	1	- command issued, wait reply
+ *
+ *	2	- reply waiting - reader then goes to state 0
+ *
+ *	3	- command issued, trash reply. In which case the irq
+ *		  takes it back to state 0
+ *
  */
   
 static int mc32_command(struct device *dev, u16 cmd, void *data, int len)
@@ -531,207 +636,311 @@
 	/* Send the command */
 	while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
 	outb(1<<6, ioaddr+HOST_CMD);	
-	
+
 	save_flags(flags);
 	cli();
+
 	while(lp->exec_pending!=2)
 		sleep_on(&lp->event);
 	lp->exec_pending=0;
 	restore_flags(flags);
 	
-	 
-	if(lp->exec_box->data[0]&(1<<13))
+	if(lp->exec_box->mbox&(1<<13))
 		ret = -1;
+
 	/*
 	 *	A multicast set got blocked - do it now
 	 */
 		
 	if(lp->mc_reload_wait)
+	{
 		mc32_reset_multicast_list(dev);
+	}
 
 	return ret;
 }
 
 
-/*
- *	RX abort
- */
- 
-static void mc32_rx_abort(struct device *dev)
-{
-	struct mc32_local *lp = (struct mc32_local *)dev->priv;
-	int ioaddr = dev->base_addr;
+/**
+ *	mc32_start_transceiver: 
+ *	@dev: The 3c527 card to issue the command to
+ *
+ *	This may be called from the interrupt state, where it is used
+ *	to restart the rx ring if the card runs out of rx buffers. 
+ *	
+ * 	First, we check if it's ok to start the transceiver. We then show
+ * 	the card where to start in the rx ring and issue the
+ * 	commands to start reception and transmission. We don't wait
+ * 	around for these to complete.
+ */ 
 
-	while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
-	
-	lp->rx_box->mbox=0;
-	outb(3<<3, ioaddr+HOST_CMD);	/* Suspend reception */
-}
+static void mc32_start_transceiver(struct device *dev) {
 
- 
-/*
- *	RX enable
- */
- 
-static void mc32_rx_begin(struct device *dev)
-{
 	struct mc32_local *lp = (struct mc32_local *)dev->priv;
 	int ioaddr = dev->base_addr;
-	
-	while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
-	
-	lp->rx_box->mbox=0;
-	outb(1<<3, ioaddr+HOST_CMD);	/* GO */
-	mc32_ring_poll(dev);	
-	
-	lp->rx_halted=0;
-	lp->rx_pending=0;
-}
 
-static void mc32_tx_abort(struct device *dev)
-{
-	struct mc32_local *lp = (struct mc32_local *)dev->priv;
-	int ioaddr = dev->base_addr;
-	
-	while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
-	
+	/* Ignore RX overflow on device closure */ 
+	if (lp->desired_state==HALTED)  
+		return; 
+
+	mc32_ready_poll(dev); 
+
 	lp->tx_box->mbox=0;
-	outb(3, ioaddr+HOST_CMD);	/* Suspend */
-	
-	/* Ring empty */
-	
-	atomic_set(&lp->tx_count, lp->tx_len);
+	lp->rx_box->mbox=0;
+
+	/* Give the card the offset to the post-EOL-bit RX descriptor */ 
+	lp->rx_box->data[0]=lp->rx_ring[prev_rx(lp->rx_ring_tail)].p->next; 
+
+	outb(HOST_CMD_START_RX, ioaddr+HOST_CMD);      
+
+	mc32_ready_poll(dev); 
+	outb(HOST_CMD_RESTRT_TX, ioaddr+HOST_CMD);   /* card ignores this on RX restart */ 
 	
-	/* Flush */
-	if(lp->tx_skb_top!=lp->tx_skb_end)
-	{
-		int i;
-		if(lp->tx_skb_top<=lp->tx_skb_end)
-		{
-			for(i=lp->tx_skb_top;i<lp->tx_skb_end;i++)
-			{
-				dev_kfree_skb(lp->tx_skb[i]);
-				lp->tx_skb[i]=NULL;
-			}
-		}
-		else
-		{
-			for(i=lp->tx_skb_end;i<TX_RING_MAX;i++)
-			{
-				dev_kfree_skb(lp->tx_skb[i]);
-				lp->tx_skb[i]=NULL;
-			}
-			for(i=0;i<lp->tx_skb_top;i++)
-			{
-				dev_kfree_skb(lp->tx_skb[i]);
-				lp->tx_skb[i]=NULL;
-			}
-		}
-	}
-	lp->tx_skb_top=lp->tx_skb_end=0;
+	/* We are not interrupted on start completion */ 
+	lp->xceiver_state=RUNNING; 
 }
 
-/*
- *	TX enable
- */
- 
-static void mc32_tx_begin(struct device *dev)
+
+/**
+ *	mc32_halt_transceiver: 
+ *	@dev: The 3c527 card to issue the command to
+ *
+ *	We issue the commands to halt the card's transceiver. In fact,
+ *	after some experimenting we now simply tell the card to
+ *	suspend. When issuing aborts occasionally odd things happened.
+ *
+ *	We then sleep until the card has notified us that both rx and
+ *	tx have been suspended.
+ */ 
+
+static void mc32_halt_transceiver(struct device *dev) 
 {
 	struct mc32_local *lp = (struct mc32_local *)dev->priv;
 	int ioaddr = dev->base_addr;
-	
-	while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
-	
+	unsigned long flags;
+
+	mc32_ready_poll(dev);	
+
 	lp->tx_box->mbox=0;
-#if 0	
-	outb(5, ioaddr+HOST_CMD);	/* GO */
-	printk("TX=>5\n");
-	mc32_ring_poll(dev);	
-	if(lp->tx_box->mbox&(1<<13))
-		printk("TX begin error!\n");
-#endif		
-	lp->tx_halted=0;
-}
+	lp->rx_box->mbox=0;
 
-	
-/*
- *	Load the rx ring
+	outb(HOST_CMD_SUSPND_RX, ioaddr+HOST_CMD);			
+	mc32_ready_poll(dev); 
+	outb(HOST_CMD_SUSPND_TX, ioaddr+HOST_CMD);	
+		
+	save_flags(flags);
+	cli();
+		
+	while(lp->xceiver_state!=HALTED) 
+		sleep_on(&lp->event); 
+		
+	restore_flags(flags);	
+} 
+
+
+/**
+ *	mc32_load_rx_ring:
+ *	@dev: 3c527 to build the ring for
+ *
+ *	This initalises the on-card and driver datastructures to
+ *	the point where mc32_start_transceiver() can be called.
+ *
+ *	The card sets up the receive ring for us. We are required to use the
+ *	ring it provides although we can change the size of the ring.
+ *
+ * 	We allocate an sk_buff for each ring entry in turn and
+ * 	initalise its house-keeping info. At the same time, we read
+ * 	each 'next' pointer in our rx_ring array. This reduces slow
+ * 	shared-memory reads and makes it easy to access predecessor
+ * 	descriptors.
+ *
+ *	We then set the end-of-list bit for the last entry so that the
+ * 	card will know when it has run out of buffers.
  */
- 
+	 
 static int mc32_load_rx_ring(struct device *dev)
 {
 	struct mc32_local *lp = (struct mc32_local *)dev->priv;
 	int i;
-	u16 base;
+	u16 rx_base;
 	volatile struct skb_header *p;
 	
-	base = lp->rx_box->data[0];
-	
-	/* Fix me - should use card size - also fix flush ! */ 
+	rx_base=lp->rx_chain;
 
-	for(i=0;i<RX_RING_MAX;i++)
+	for(i=0;i<RX_RING_LEN;i++)
 	{
-		lp->rx_skb[i]=alloc_skb(1532, GFP_KERNEL);
-		if(lp->rx_skb[i]==NULL)
+		lp->rx_ring[i].skb=alloc_skb(1532, GFP_KERNEL);
+		skb_reserve(lp->rx_ring[i].skb, 18);  
+
+		if(lp->rx_ring[i].skb==NULL)
 		{
 			for(;i>=0;i--)
-				kfree_skb(lp->rx_skb[i]);
+				kfree_skb(lp->rx_ring[i].skb);
 			return -ENOBUFS;
 		}
-		lp->rx_ptr[i]=lp->rx_skb[i]->data+18;
 		
-		p=bus_to_virt(lp->base+base);
+		p=bus_to_virt(lp->base+rx_base);
+				
 		p->control=0;
-		p->data = virt_to_bus(lp->rx_ptr[i]);
+		p->data=virt_to_bus(lp->rx_ring[i].skb->data);
 		p->status=0;
-		p->length = 1532;
-		base = p->next;
+		p->length=1532;
+	
+		lp->rx_ring[i].p=p; 
+		rx_base=p->next; 
 	}
-	p->control = (1<<6);
-	lp->rx_box->mbox = 0;
+
+	lp->rx_ring[i-1].p->control |= CONTROL_EOL;
+
+	lp->rx_ring_tail=0;
+
 	return 0;
 }	
 
-static void mc32_flush_rx_ring(struct mc32_local *lp)
-{
-	int i;
-	for(i=0;i<RX_RING_MAX;i++)
-		kfree_skb(lp->rx_skb[i]);
-}
 
-static void mc32_flush_tx_ring(struct mc32_local *lp)
+/**
+ *	mc32_flush_rx_ring:
+ *	@lp: Local data of 3c527 to flush the rx ring of
+ *
+ *	Free the buffer for each ring slot. This may be called 
+ *      before mc32_load_rx_ring(), eg. on error in mc32_open().
+ */
+
+static void mc32_flush_rx_ring(struct device *dev)
 {
-	int i;
+	struct mc32_local *lp = (struct mc32_local *)dev->priv;
 	
-	if(lp->tx_skb_top <= lp->tx_skb_end)
+	struct sk_buff *skb;
+	int i; 
+
+	for(i=0; i < RX_RING_LEN; i++) 
+	{ 
+		skb = lp->rx_ring[i].skb;
+		if (skb!=NULL) {
+			kfree_skb(skb);
+			skb=NULL; 
+		}
+		lp->rx_ring[i].p=NULL; 
+	} 
+}
+
+
+/**
+ *	mc32_load_tx_ring: 
+ *	@dev: The 3c527 card to issue the command to
+ *
+ *	This sets up the host transmit data-structures. 
+ *
+ *	First, we obtain from the card it's current postion in the tx
+ *	ring, so that we will know where to begin transmitting
+ *	packets.
+ * 	
+ * 	Then, we read the 'next' pointers from the on-card tx ring into
+ *  	our tx_ring array to reduce slow shared-mem reads. Finally, we
+ * 	intitalise the tx house keeping variables.
+ * 
+ */ 
+
+static void mc32_load_tx_ring(struct device *dev)
+{ 
+	struct mc32_local *lp = (struct mc32_local *)dev->priv;
+	volatile struct skb_header *p;
+	int i; 
+	u16 tx_base;
+
+	tx_base=lp->tx_box->data[0]; 
+
+	for(i=0;i<lp->tx_len;i++) 
 	{
-		for(i=lp->tx_skb_top;i<lp->tx_skb_end;i++)
-			dev_kfree_skb(lp->tx_skb[i]);
+		p=bus_to_virt(lp->base+tx_base);
+		lp->tx_ring[i].p=p; 
+		lp->tx_ring[i].skb=NULL;
+
+		tx_base=p->next;
 	}
-	else
+
+	/* -1 so that tx_ring_head cannot "lap" tx_ring_tail,           */
+	/* which would be bad news for mc32_tx_ring as cur. implemented */ 
+
+	atomic_set(&lp->tx_count, TX_RING_LEN-1); 
+	lp->tx_ring_head=lp->tx_ring_tail=0; 
+} 
+
+
+/**
+ *	mc32_flush_tx_ring:
+ *	@lp: Local data of 3c527 to flush the tx ring of
+ *
+ *	We have to consider two cases here. We want to free the pending
+ *	buffers only. If the ring buffer head is past the start then the
+ *	ring segment we wish to free wraps through zero. The tx ring 
+ *	house-keeping variables are then reset.
+ */
+
+static void mc32_flush_tx_ring(struct device *dev)
+{
+	struct mc32_local *lp = (struct mc32_local *)dev->priv;
+	
+	if(lp->tx_ring_tail!=lp->tx_ring_head)
 	{
-		for(i=0;i<lp->tx_skb_end;i++)
-			dev_kfree_skb(lp->tx_skb[i]);
-		for(i=lp->tx_skb_top;i<TX_RING_MAX;i++)
-			dev_kfree_skb(lp->tx_skb[i]);
+		int i;	
+		if(lp->tx_ring_tail < lp->tx_ring_head)
+		{
+			for(i=lp->tx_ring_tail;i<lp->tx_ring_head;i++)
+			{
+				dev_kfree_skb(lp->tx_ring[i].skb);
+				lp->tx_ring[i].skb=NULL;
+				lp->tx_ring[i].p=NULL; 
+			}
+		}
+		else
+		{
+			for(i=lp->tx_ring_tail; i<TX_RING_LEN; i++) 
+			{
+				dev_kfree_skb(lp->tx_ring[i].skb);
+				lp->tx_ring[i].skb=NULL;
+				lp->tx_ring[i].p=NULL; 
+			}
+			for(i=0; i<lp->tx_ring_head; i++) 
+			{
+				dev_kfree_skb(lp->tx_ring[i].skb);
+				lp->tx_ring[i].skb=NULL;
+				lp->tx_ring[i].p=NULL; 
+			}
+		}
 	}
+	
+	atomic_set(&lp->tx_count, 0); 
+	lp->tx_ring_tail=lp->tx_ring_head=0;
 }
  	
-/*
- * Open/initialize the board. This is called (in the current kernel)
- * sometime after booting when the 'ifconfig' program is run.
+
+/**
+ *	mc32_open
+ *	@dev: device to open
+ *
+ *	The user is trying to bring the card into ready state. This requires
+ *	a brief dialogue with the card. Firstly we enable interrupts and then
+ *	'indications'. Without these enabled the card doesn't bother telling
+ *	us what it has done. This had me puzzled for a week.
+ *
+ *	We configure the number of card descriptors, then load the network
+ *	address and multicast filters. Turn on the workaround mode. This
+ *	works around a bug in the 82586 - it asks the firmware to do
+ *	so. It has a performance (latency) hit but is needed on busy
+ *	[read most] lans. We load the ring with buffers then we kick it
+ *	all off.
  */
 
 static int mc32_open(struct device *dev)
 {
 	int ioaddr = dev->base_addr;
-	u16 zero_word=0;
+	struct mc32_local *lp = (struct mc32_local *)dev->priv;
 	u8 one=1;
 	u8 regs;
-	
-	dev->tbusy = 0;
-	dev->interrupt = 0;
-	dev->start = 1;
+	u16 descnumbuffs[2] = {TX_RING_LEN, RX_RING_LEN};
+
+	MOD_INC_USE_COUNT;
 
 	/*
 	 *	Interrupts enabled
@@ -748,49 +957,84 @@
 
 	mc32_command(dev, 4, &one, 2);
 
-	 	
 	/*
-	 *	Send the command sequence "abort, resume" for RX and TX.
-	 *	The abort cleans up the buffer chains if needed.
+	 *	Poke it to make sure it's really dead. 
 	 */
 
-	mc32_rx_abort(dev);
-	mc32_tx_abort(dev);
-	
+	mc32_halt_transceiver(dev); 
+	mc32_flush_tx_ring(dev); 
+
+	/* 
+	 *	Ask card to set up on-card descriptors to our spec 
+	 */ 
+
+	if(mc32_command(dev, 8, descnumbuffs, 4)) { 
+		printk("%s: %s rejected our buffer configuration!\n",
+	 	       dev->name, cardname);
+		mc32_close(dev); 
+		return -ENOBUFS; 
+	}
+	
+	/* Report new configuration */ 
+	mc32_command(dev, 6, NULL, 0); 
+
+	lp->tx_chain 		= lp->exec_box->data[8];   /* Transmit list start offset */
+	lp->rx_chain 		= lp->exec_box->data[10];  /* Receive list start offset */
+	lp->tx_len 		= lp->exec_box->data[9];   /* Transmit list count */ 
+	lp->rx_len 		= lp->exec_box->data[11];  /* Receive list count */
+ 
 	/* Set Network Address */
 	mc32_command(dev, 1, dev->dev_addr, 6);
 	
 	/* Set the filters */
 	mc32_set_multicast_list(dev);
+		   
+	if (WORKAROUND_82586) { 
+		u16 zero_word=0;
+		mc32_command(dev, 0x0D, &zero_word, 2);   /* 82586 bug workaround on  */
+	}
+
+	mc32_load_tx_ring(dev);
 	
-	/* Issue the 82586 workaround command - this is for "busy lans",
-	   but basically means for all lans now days - has a performance
-	   cost but best set */
-	   
-	mc32_command(dev, 0x0D, &zero_word, 2); /* 82586 bug workaround on */
-	
-	/* Load the ring we just initialised */
-	
-	if(mc32_load_rx_ring(dev))
+	if(mc32_load_rx_ring(dev)) 
 	{
 		mc32_close(dev);
 		return -ENOBUFS;
 	}
+
+	lp->desired_state = RUNNING; 
 	
-	/* And the resume command goes last */
-	
-	mc32_rx_begin(dev);
-	mc32_tx_begin(dev);
-	
-	MOD_INC_USE_COUNT;
+	/* And finally, set the ball rolling... */
+
+	mc32_start_transceiver(dev);
+
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
 
 	return 0;
 }
 
+
+/**
+ *	mc32_send_packet:
+ *	@skb: buffer to transmit
+ *	@dev: 3c527 to send it out of
+ *
+ *	Transmit a buffer. This normally means throwing the buffer onto
+ *	the transmit queue as the queue is quite large. If the queue is
+ *	full then we set tx_busy and return. Once the interrupt handler
+ *	gets messages telling it to reclaim transmit queue entries we will
+ *	clear tx_busy and the kernel will start calling this again.
+ *
+ *	We use cli rather than spinlocks. Since I have no access to an SMP
+ *	MCA machine I don't plan to change it. It is probably the top 
+ *	performance hit for this driver on SMP however.
+ */
+
 static int mc32_send_packet(struct sk_buff *skb, struct device *dev)
 {
 	struct mc32_local *lp = (struct mc32_local *)dev->priv;
-	int ioaddr = dev->base_addr;
 
 	if (dev->tbusy) {
 		/*
@@ -817,9 +1061,7 @@
 	}
 	else 
 	{
-		unsigned long flags;
-		
-		u16 tx_head;
+		unsigned long flags;	       
 		volatile struct skb_header *p, *np;
 
 		save_flags(flags);
@@ -832,159 +1074,303 @@
 			return 1;
 		}
 
-		tx_head = lp->tx_box->data[0];
-		atomic_dec(&lp->tx_count);
+		atomic_dec(&lp->tx_count); 
 
-		/* We will need this to flush the buffer out */
-		
-		lp->tx_skb[lp->tx_skb_end] = skb;
-		lp->tx_skb_end++;
-		lp->tx_skb_end&=(TX_RING_MAX-1);
-		
-		/* TX suspend - shouldnt be needed but apparently is.
-		   This is a research item ... */
-		   
-		while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
-		lp->tx_box->mbox=0;
-		outb(3, ioaddr+HOST_CMD);
-		
-		/* Transmit now stopped */
 		/* P is the last sending/sent buffer as a pointer */
-		p=(struct skb_header *)bus_to_virt(lp->base+tx_head);
+		p=lp->tx_ring[lp->tx_ring_head].p; 
 		
+		lp->tx_ring_head=next_tx(lp->tx_ring_head); 
+
 		/* NP is the buffer we will be loading */
-		np=(struct skb_header *)bus_to_virt(lp->base+p->next);
-		
-		np->control	|= (1<<6);	/* EOL */
-		wmb();
-				
-		np->length	= skb->len;
+		np=lp->tx_ring[lp->tx_ring_head].p; 
 
-		if(np->length < 60)
-			np->length = 60;
+	        /* We will need this to flush the buffer out */
+		lp->tx_ring[lp->tx_ring_head].skb=skb;
+   	   
+		np->length = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len; 
 			
 		np->data	= virt_to_bus(skb->data);
-		np->status	= 0;
-		np->control	= (1<<7)|(1<<6);	/* EOP EOL */
-		wmb();
-		
-		p->status	= 0;
-		p->control	&= ~(1<<6);
+   		np->status	= 0;
+		np->control     = CONTROL_EOP | CONTROL_EOL;     
+	        wmb();
 		
-		dev->tbusy	= 0;			/* Keep feeding me */		
-		
-		while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
-		lp->tx_box->mbox=0;
-		outb(5, ioaddr+HOST_CMD);		/* Restart TX */
-		restore_flags(flags);
+		p->control     &= ~CONTROL_EOL;     /* Clear EOL on p */ 
+	   
+       	        dev->tbusy	= 0;	       /* Keep feeding me */		
+	
+	        restore_flags(flags);
 	}
 	return 0;
 }
 
+
+/**
+ *	mc32_update_stats:
+ *	@dev: 3c527 to service
+ *
+ * 
+ *	Query and reset the on-card stats. There's the small possibility
+ *	of a race here, which would result in an underestimation of
+ *	actual errors. As such, we'd prefer to keep all our stats
+ *	collection in software. As a rule, we do. However it can't be
+ *	used for rx errors and collisions as, by default, the card discards
+ *	bad rx packets. 
+ *
+ *	Setting the SAV BP in the rx filter command supposedly
+ *	stops this behaviour. However, testing shows that it only seems to
+ *	enable the collation of on-card rx statistics --- the driver
+ *	never sees an RX descriptor with an error status set.
+ *
+ */
+
 static void mc32_update_stats(struct device *dev)
 {
-}
+	struct mc32_local *lp = (struct mc32_local *)dev->priv;
+	volatile struct mc32_stats *st = lp->stats; 
+
+	u32 rx_errors=0; 
+      
+	rx_errors+=lp->net_stats.rx_crc_errors   +=st->rx_crc_errors;         
+	                                           st->rx_crc_errors=0;
+	rx_errors+=lp->net_stats.rx_fifo_errors  +=st->rx_overrun_errors;   
+	                                           st->rx_overrun_errors=0; 
+	rx_errors+=lp->net_stats.rx_frame_errors +=st->rx_alignment_errors; 
+ 	                                           st->rx_alignment_errors=0;
+	rx_errors+=lp->net_stats.rx_length_errors+=st->rx_tooshort_errors; 
+	                                           st->rx_tooshort_errors=0;
+	rx_errors+=lp->net_stats.rx_missed_errors+=st->rx_outofresource_errors;
+	                                           st->rx_outofresource_errors=0; 
+        lp->net_stats.rx_errors=rx_errors; 
+						   
+	/* Number of packets which saw one collision */
+	lp->net_stats.collisions+=st->dataC[10];
+	st->dataC[10]=0; 
+
+	/* Number of packets which saw 2--15 collisions */ 
+	lp->net_stats.collisions+=st->dataC[11]; 
+	st->dataC[11]=0; 
+}	
 
 
+/**
+ *	mc32_rx_ring:
+ *	@dev: 3c527 that needs its receive ring processing
+ *
+ *
+ *	We have received one or more indications from the card that a
+ *	receive has completed. The buffer ring thus contains dirty
+ *	entries. We walk the ring by iterating over the circular rx_ring
+ *	array, starting at the next dirty buffer (which happens to be the
+ *	one we finished up at last time around).
+ *
+ *	For each completed packet, we will either copy it and pass it up
+ * 	the stack or, if the packet is near MTU sized, we allocate
+ *	another buffer and flip the old one up the stack.
+ * 
+ *	We must succeed in keeping a buffer on the ring. If neccessary we
+ *	will toss a received packet rather than lose a ring entry. Once
+ *	the first uncompleted descriptor is found, we move the
+ *	End-Of-List bit to include the buffers just processed.
+ *
+ */
+
 static void mc32_rx_ring(struct device *dev)
 {
-	struct mc32_local *lp=dev->priv;
-	int ioaddr = dev->base_addr;
-	int x=0;
+	struct mc32_local *lp=dev->priv;		
 	volatile struct skb_header *p;
-	u16 base;
-	u16 top;
+	u16 rx_ring_tail = lp->rx_ring_tail;
+	u16 rx_old_tail = rx_ring_tail; 
+
+	int x=0;
 	
-	top = base = lp->rx_box->data[0];
 	do
-	{
-		p=(struct skb_header *)bus_to_virt(base+lp->base);
-		if(!(p->status & (1<<7)))
+	{ 
+		p=lp->rx_ring[rx_ring_tail].p; 
+
+		if(!(p->status & (1<<7))) { /* Not COMPLETED */ 
 			break;
-		if(p->status & (1<<6))
-		{
-			u16 length = p->length;
-			struct sk_buff *skb=dev_alloc_skb(length+2);
-			if(skb!=NULL)
+		} 
+		if(p->status & (1<<6)) /* COMPLETED_OK */
+		{		        
+
+			u16 length=p->length;
+			struct sk_buff *skb; 
+			struct sk_buff *newskb; 
+
+			/* Try to save time by avoiding a copy on big frames */
+
+			if ((length > RX_COPYBREAK) 
+			    && ((newskb=dev_alloc_skb(1532)) != NULL)) 
+			{ 
+				skb=lp->rx_ring[rx_ring_tail].skb;
+				skb_put(skb, length);
+				
+				skb_reserve(newskb,18); 
+				lp->rx_ring[rx_ring_tail].skb=newskb;  
+				p->data=virt_to_bus(newskb->data);  
+			} 
+			else 
 			{
+				skb=dev_alloc_skb(length+2);  
+
+				if(skb==NULL) {
+					lp->net_stats.rx_dropped++; 
+					goto dropped; 
+				}
+
 				skb_reserve(skb,2);
-				/*printk("Frame at %p\n", bus_to_virt(p->data)); */
 				memcpy(skb_put(skb, length),
-					bus_to_virt(p->data), length);
-				skb->protocol=eth_type_trans(skb,dev);
-				skb->dev=dev;
-				lp->net_stats.rx_packets++;
-				lp->net_stats.rx_bytes+=skb->len;
-				netif_rx(skb);
-			}
-			else
-				lp->net_stats.rx_dropped++;
-		}
-		else
-		{
-			lp->net_stats.rx_errors++;
-			switch(p->status&0x0F)
-			{
-				case 1:
-					lp->net_stats.rx_crc_errors++;break;
-				case 2:
-					lp->net_stats.rx_fifo_errors++;break;
-				case 3:
-					lp->net_stats.rx_frame_errors++;break;
-				case 4:
-					lp->net_stats.rx_missed_errors++;break;
-				case 5:
-					lp->net_stats.rx_length_errors++;break;
+				       lp->rx_ring[rx_ring_tail].skb->data, length);
 			}
+			
+			skb->protocol=eth_type_trans(skb,dev); 
+			skb->dev=dev; 
+ 			lp->net_stats.rx_packets++; 
+ 			lp->net_stats.rx_bytes+=skb->len; 
+			netif_rx(skb); 
 		}
-		p->length = 1532;
-		p->control &= ~(1<<6);
+
+	dropped:
+		p->length = 1532; 
 		p->status = 0;
-		base = p->next;
+		
+		rx_ring_tail=next_rx(rx_ring_tail); 
+	}
+        while(x++<48);  
+
+	/* If there was actually a frame to be processed, place the EOL bit */ 
+	/* at the descriptor prior to the one to be filled next */ 
+
+	if (rx_ring_tail != rx_old_tail) 
+	{ 
+		lp->rx_ring[prev_rx(rx_ring_tail)].p->control |=  CONTROL_EOL; 
+		lp->rx_ring[prev_rx(rx_old_tail)].p->control  &= ~CONTROL_EOL; 
+
+		lp->rx_ring_tail=rx_ring_tail; 
 	}
-	while(x++<48);
-	
-	/*
-	 *	Restart ring processing
-	 */	
-	
-	while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
-	lp->rx_box->mbox=0;
-	lp->rx_box->data[0] = top;
-	outb(1<<3, ioaddr+HOST_CMD);	
-	lp->rx_halted = 0;
 }
 
 
-/*
- * The typical workload of the driver:
- *   Handle the network interface interrupts.
+/**
+ *	mc32_tx_ring:
+ *	@dev: 3c527 that needs its transmit ring processing
+ *
+ *
+ *	This operates in a similar fashion to mc32_rx_ring. We iterate
+ *	over the transmit ring. For each descriptor which has been
+ *	processed by the card, we free its associated buffer and note
+ *	any errors. This continues until the transmit ring is emptied
+ *	or we reach a descriptor that hasn't yet been processed by the
+ *	card.
+ * 
+ */
+
+static void mc32_tx_ring(struct device *dev) {
+
+  struct mc32_local *lp=(struct mc32_local *)dev->priv;
+  volatile struct skb_header *np;
+
+  /* NB: lp->tx_count=TX_RING_LEN-1 so that tx_ring_head cannot "lap" tail here */
+
+  while (lp->tx_ring_tail != lp->tx_ring_head)  
+  {   
+	  u16 t; 
+
+	  t=next_tx(lp->tx_ring_tail); 
+	  np=lp->tx_ring[t].p; 
+
+	  if(!(np->status & (1<<7))) { /* Not COMPLETED */ 
+		  break; 
+	  } 
+
+	  lp->net_stats.tx_packets++;
+
+	  if(!(np->status & (1<<6))) /* Not COMPLETED_OK */
+	  {
+		  lp->net_stats.tx_errors++;   
+
+		  switch(np->status&0x0F)
+		  {
+		  case 1:
+			  lp->net_stats.tx_aborted_errors++;break; /* Max collisions */ 
+		  case 2:
+			  lp->net_stats.tx_fifo_errors++;break;
+		  case 3:
+			  lp->net_stats.tx_carrier_errors++;break;
+		  case 4:
+			  lp->net_stats.tx_window_errors++;break;  /* CTS Lost */ 
+		  case 5:
+			  lp->net_stats.tx_aborted_errors++;break; /* Transmit timeout */ 
+		  }
+	  }
+	  
+	  
+	  /* Packets are sent in order - this is
+	     basically a FIFO queue of buffers matching
+	     the card ring */
+	  lp->net_stats.tx_bytes+=lp->tx_ring[t].skb->len;
+	  dev_kfree_skb(lp->tx_ring[t].skb);
+	  lp->tx_ring[t].skb=NULL;
+	  atomic_inc(&lp->tx_count);
+	  dev->tbusy=0;
+	  mark_bh(NET_BH);
+
+	  lp->tx_ring_tail=t; 
+  }
+
+} 
+
+
+/**
+ *	mc32_interrupt:
+ *	@irq: Interrupt number
+ *	@dev_id: 3c527 that requires servicing
+ *	@regs: Registers (unused)
+ *
+ *
+ *	An interrupt is raised whenever the 3c527 writes to the command
+ *	register. This register contains the message it wishes to send us
+ *	packed into a single byte field. We keep reading status entries
+ *	until we have processed all the control items, but simply count
+ *	transmit and receive reports. When all reports are in we empty the
+ *	transceiver rings as appropriate. This saves the overhead of
+ *	multiple command requests.
+ *
+ *	Because MCA is level-triggered, we shouldn't miss indications.
+ *	Therefore, we needn't ask the card to suspend interrupts within
+ *	this handler. The card receives an implicit acknowledgment of the
+ *	current interrupt when we read the command register.
+ *
  */
+
 static void mc32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
 	struct device *dev = dev_id;
 	struct mc32_local *lp;
 	int ioaddr, status, boguscount = 0;
+	int rx_event = 0;
+	int tx_event = 0; 
 	
 	if (dev == NULL) {
 		printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq);
 		return;
 	}
-	dev->interrupt = 1;
 
+	dev->interrupt = 1;
+ 
 	ioaddr = dev->base_addr;
 	lp = (struct mc32_local *)dev->priv;
 
 	/* See whats cooking */
-	
-	while((inb(ioaddr+2)&(1<<5)) && boguscount++<2000)
+
+	while((inb(ioaddr+HOST_STATUS)&HOST_STATUS_CWR) && boguscount++<2000)
 	{
 		status=inb(ioaddr+HOST_CMD);
 
 #ifdef DEBUG_IRQ		
-		printk("Status TX%d RX%d EX%d OV%d\n",
+		printk("Status TX%d RX%d EX%d OV%d BC%d\n",
 			(status&7), (status>>3)&7, (status>>6)&1,
-			(status>>7)&1);
+			(status>>7)&1, boguscount);
 #endif
 			
 		switch(status&7)
@@ -992,33 +1378,16 @@
 			case 0:
 				break;
 			case 6: /* TX fail */
-				lp->net_stats.tx_errors++;
 			case 2:	/* TX ok */
-				lp->net_stats.tx_packets++;
-				/* Packets are sent in order - this is
-				   basically a FIFO queue of buffers matching
-				   the card ring */
-				lp->net_stats.tx_bytes+=lp->tx_skb[lp->tx_skb_top]->len;
-				dev_kfree_skb(lp->tx_skb[lp->tx_skb_top]);
-				lp->tx_skb[lp->tx_skb_top]=NULL;
-				lp->tx_skb_top++;
-				lp->tx_skb_top&=(TX_RING_MAX-1);
-				atomic_inc(&lp->tx_count);
-				dev->tbusy=0;
-				mark_bh(NET_BH);
+				tx_event = 1; 
 				break;
 			case 3: /* Halt */
 			case 4: /* Abort */
-				lp->tx_halted=1;
-				wake_up(&lp->event);
-				break;
-			case 5:
-				lp->tx_halted=0;
+				lp->xceiver_state |= TX_HALTED; 
 				wake_up(&lp->event);
 				break;
 			default:
-				printk("%s: strange tx ack %d\n", 
-					dev->name, status&7);
+				printk("%s: strange tx ack %d\n", dev->name, status&7);
 		}
 		status>>=3;
 		switch(status&7)
@@ -1026,155 +1395,199 @@
 			case 0:
 				break;
 			case 2:	/* RX */
-				lp->rx_pending=1;
-				if(!lp->rx_halted)
-				{
-					/*
-					 *	Halt ring receive
-					 */
-					while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
-					outb(3<<3, ioaddr+HOST_CMD);
-				}
+				rx_event=1; 
 				break;
-			case 3:
-			case 4:
-				lp->rx_halted=1;
-				wake_up(&lp->event);
-				break;
-			case 5:
-				lp->rx_halted=0;
+			case 3: /* Halt */
+			case 4: /* Abort */
+				lp->xceiver_state |= RX_HALTED;
 				wake_up(&lp->event);
 				break;
 			case 6:
 				/* Out of RX buffers stat */
+				/* Must restart rx */
 				lp->net_stats.rx_dropped++;
-				lp->rx_pending=1;
-				/* Must restart */
-				lp->rx_halted=1;
+				mc32_rx_ring(dev); 
+				mc32_start_transceiver(dev); 
 				break;
 			default:
 				printk("%s: strange rx ack %d\n", 
-					dev->name, status&7);
-			
+					dev->name, status&7);			
 		}
 		status>>=3;
 		if(status&1)
 		{
+
 			/* 0=no 1=yes 2=replied, get cmd, 3 = wait reply & dump it */
-			if(lp->exec_pending!=3)
+			
+			if(lp->exec_pending!=3) {
 				lp->exec_pending=2;
-			else
-				lp->exec_pending=0;
-			wake_up(&lp->event);
+				wake_up(&lp->event);
+			}
+			else 
+			{				
+			  	lp->exec_pending=0;
+
+				/* A new multicast set may have been
+				   blocked while the old one was
+				   running. If so, do it now. */
+				   
+				if (lp->mc_reload_wait) 
+					mc32_reset_multicast_list(dev);
+				else 
+					wake_up(&lp->event);			       
+			}
 		}
 		if(status&2)
 		{
 			/*
-			 *	Update the stats as soon as
-			 *	we have it flagged and can 
-			 *	send an immediate reply (CRR set)
+			 *	We get interrupted once per
+			 *	counter that is about to overflow. 
 			 */
-			 
-			if(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)
-			{
-				mc32_update_stats(dev);
-				outb(0, ioaddr+HOST_CMD);
-			}
+
+			mc32_update_stats(dev);			
 		}
 	}
-	
+
+
 	/*
-	 *	Process and restart the receive ring. This has some state
-	 *	as we must halt the ring to process it and halting the ring
-	 *	might not occur in the same IRQ handling loop as we issue
-	 *	the halt.
-	 */
+	 *	Process the transmit and receive rings 
+         */
+
+	if(tx_event) 
+		mc32_tx_ring(dev);
 	 
-	if(lp->rx_pending && lp->rx_halted)
-	{
+	if(rx_event) 
 		mc32_rx_ring(dev);
-		lp->rx_pending = 0;
-	}
-	dev->interrupt = 0;
+
+	dev->interrupt = 0;	
+
 	return;
 }
 
 
-/* The inverse routine to mc32_open(). */
+/**
+ *	mc32_close:
+ *	@dev: 3c527 card to shut down
+ *
+ *	The 3c527 is a bus mastering device. We must be careful how we
+ *	shut it down. It may also be running shared interrupt so we have
+ *	to be sure to silence it properly
+ *
+ *	We indicate that the card is closing to the rest of the
+ *	driver.  Otherwise, it is possible that the card may run out
+ *	of receive buffers and restart the transceiver while we're
+ *	trying to close it.
+ * 
+ *	We abort any receive and transmits going on and then wait until
+ *	any pending exec commands have completed in other code threads.
+ *	In theory we can't get here while that is true, in practice I am
+ *	paranoid
+ *
+ *	We turn off the interrupt enable for the board to be sure it can't
+ *	intefere with other devices.
+ */
 
 static int mc32_close(struct device *dev)
 {
 	struct mc32_local *lp = (struct mc32_local *)dev->priv;
+
 	int ioaddr = dev->base_addr;
 	u8 regs;
 	u16 one=1;
 
+	dev->tbusy = 1;
+	dev->start = 0;
+
+	lp->desired_state = HALTED;
+
 	/*
 	 *	Send the indications on command (handy debug check)
 	 */
 
 	mc32_command(dev, 4, &one, 2);
 
-	/* Abort RX and Abort TX */
-	
-	mc32_rx_abort(dev);	
-	mc32_tx_abort(dev);
+	/* Shut down the transceiver */
+
+	mc32_halt_transceiver(dev); 
 	
 	/* Catch any waiting commands */
 	
 	while(lp->exec_pending==1)
 		sleep_on(&lp->event);
-		
+	       
 	/* Ok the card is now stopping */	
 	
 	regs=inb(ioaddr+HOST_CTRL);
 	regs&=~HOST_CTRL_INTE;
 	outb(regs, ioaddr+HOST_CTRL);
 
-	mc32_flush_rx_ring(lp);
-	mc32_flush_tx_ring(lp);
-	
-	dev->tbusy = 1;
-	dev->start = 0;
-
-	/* Update the statistics here. */
+	mc32_flush_rx_ring(dev);
+	mc32_flush_tx_ring(dev);
+		
+	mc32_update_stats(dev); 
 
 	MOD_DEC_USE_COUNT;
 
 	return 0;
-
 }
 
-/*
- * Get the current statistics.
- * This may be called with the card open or closed.
+
+/**
+ *	mc32_get_stats:
+ *	@dev: The 3c527 card to handle
+ *
+ *	We've collected all the stats we can in software already. Now
+ *	it's time to update those kept on-card and return the lot. 
+ * 
  */
 
 static struct net_device_stats *mc32_get_stats(struct device *dev)
 {
-	struct mc32_local *lp = (struct mc32_local *)dev->priv;
+	struct mc32_local *lp;
+	
+	mc32_update_stats(dev); 
+
+	lp = (struct mc32_local *)dev->priv;
+
 	return &lp->net_stats;
 }
 
-/*
- * Set or clear the multicast filter for this adaptor.
- * num_addrs == -1	Promiscuous mode, receive all packets
- * num_addrs == 0	Normal mode, clear multicast list
- * num_addrs > 0	Multicast mode, receive normal and MC packets,
- *			and do best-effort filtering.
+
+/**
+ *	do_mc32_set_multicast_list:
+ *	@dev: 3c527 device to load the list on
+ *	@retry: indicates this is not the first call. 
+ *
+ *
+ * 	Actually set or clear the multicast filter for this adaptor. The
+ *	locking issues are handled by this routine. We have to track
+ *	state as it may take multiple calls to get the command sequence
+ *	completed. We just keep trying to schedule the loads until we
+ *	manage to process them all.
+ * 
+ *	num_addrs == -1	Promiscuous mode, receive all packets
+ * 
+ *	num_addrs == 0	Normal mode, clear multicast list
+ * 
+ *	num_addrs > 0	Multicast mode, receive normal and MC packets, 
+ *			and do best-effort filtering. 
+ *
+ *	See mc32_update_stats() regards setting the SAV BP bit. 
+ *
  */
+
 static void do_mc32_set_multicast_list(struct device *dev, int retry)
 {
 	struct mc32_local *lp = (struct mc32_local *)dev->priv;
-	u16 filt;
+	u16 filt = (1<<2); /* Save Bad Packets, for stats purposes */ 
 
 	if (dev->flags&IFF_PROMISC)
 		/* Enable promiscuous mode */
-		filt = 1;
+		filt |= 1;
 	else if((dev->flags&IFF_ALLMULTI) || dev->mc_count > 10)
 	{
 		dev->flags|=IFF_PROMISC;
-		filt = 1;
+		filt |= 1;
 	}
 	else if(dev->mc_count)
 	{
@@ -1183,9 +1596,7 @@
 		struct dev_mc_list *dmc=dev->mc_list;
 		
 		int i;
-		
-		filt = 0;
-		
+	       
 		if(retry==0)
 			lp->mc_list_valid = 0;
 		if(!lp->mc_list_valid)
@@ -1208,21 +1619,41 @@
 			lp->mc_list_valid=1;
 		}
 	}
-	else 
-	{
-		filt = 0;
-	}
-	if(mc32_command_nowait(dev, 0, &filt, 2)==-1)
+	
+	if(mc32_command_nowait(dev, 0, &filt, 2)==-1) 
 	{
 		lp->mc_reload_wait = 1;
+	} 
+	else { 
+		lp->mc_reload_wait = 0;
 	}
 }
 
+
+/**
+ *	mc32_set_multicast_list:
+ *	@dev: The 3c527 to use
+ *
+ *	Commence loading the multicast list. This is called when the kernel
+ *	changes the lists. It will override any pending list we are trying to
+ *	load.
+ */
+
 static void mc32_set_multicast_list(struct device *dev)
 {
 	do_mc32_set_multicast_list(dev,0);
 }
 
+
+/**
+ *	mc32_reset_multicast_list:
+ *	@dev: The 3c527 to use
+ *
+ *	Attempt the next step in loading the multicast lists. If this attempt
+ *	fails to complete then it will be scheduled and this function called
+ *	again later from elsewhere.
+ */
+
 static void mc32_reset_multicast_list(struct device *dev)
 {
 	do_mc32_set_multicast_list(dev,1);
@@ -1237,6 +1668,14 @@
 	0, 0,  /* I/O address, IRQ */
 	0, 0, 0, NULL, mc32_probe };
 
+/**
+ *	init_module:
+ *
+ *	Probe and locate a 3c527 card. This really should probe and locate
+ *	all the 3c527 cards in the machine not just one of them. Yes you can
+ *	insmod multiple modules for now but it's a hack.
+ */
+
 int init_module(void)
 {
 	int result;
@@ -1247,6 +1686,17 @@
 	return 0;
 }
 
+/**
+ *	cleanup_module:
+ *
+ *	Unloading time. We release the MCA bus resources and the interrupt
+ *	at which point everything is ready to unload. The card must be stopped
+ *	at this point or we would not have been called. When we unload we
+ *	leave the card stopped but not totally shut down. When the card is
+ *	initialized it must be rebooted or the rings reloaded before any
+ *	transmit operations are allowed to start scribbling into memory.
+ */
+
 void cleanup_module(void)
 {
 	int slot;
@@ -1256,8 +1706,6 @@
 
 	/*
 	 * If we don't do this, we can't re-insmod it later.
-	 * Release irq/dma here, when you have jumpered versions and
-	 * allocate them in mc32_probe1().
 	 */
 	 
 	if (this_device.priv)
@@ -1269,6 +1717,7 @@
 		kfree_s(this_device.priv, sizeof(struct mc32_local));
 	}
 	free_irq(this_device.irq, &this_device);
+	release_region(this_device.base_addr, MC32_IO_EXTENT);
 }
 
 #endif /* MODULE */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/3c527.h linux.19p18/drivers/net/3c527.h
--- linux.vanilla/drivers/net/3c527.h	Fri Apr 21 12:46:15 2000
+++ linux.19p18/drivers/net/3c527.h	Sat Mar  3 22:27:43 2001
@@ -7,11 +7,19 @@
  */
   
 #define HOST_CMD		0
+#define         HOST_CMD_START_RX   (1<<3)
+#define         HOST_CMD_SUSPND_RX  (3<<3)
+#define         HOST_CMD_RESTRT_RX  (5<<3)
+
+#define         HOST_CMD_SUSPND_TX  3
+#define         HOST_CMD_RESTRT_TX  5
+
 
 #define HOST_STATUS		2
 #define		HOST_STATUS_CRR	(1<<6)
 #define		HOST_STATUS_CWR	(1<<5)
 
+
 #define HOST_CTRL		6
 #define		HOST_CTRL_ATTN	(1<<7)
 #define 	HOST_CTRL_RESET	(1<<6)
@@ -19,6 +27,17 @@
 
 #define HOST_RAMPAGE		8
 
+#define RX_HALTED (1<<0)
+#define TX_HALTED (1<<1)  
+#define HALTED (RX_HALTED | TX_HALTED)
+#define RUNNING 0
+
+struct mc32_mailbox
+{
+	u16	mbox __attribute((packed));
+	u16	data[1] __attribute((packed));
+};
+
 struct skb_header
 {
 	u8	status __attribute((packed));
@@ -28,13 +47,37 @@
 	u32	data __attribute((packed));
 };
 
-#define STATUS_MASK	0x0F
-#define COMPLETED	0x80
-#define COMPLETED_OK	0x40
-#define BUFFER_BUSY	0x20
+struct mc32_stats
+{
+	/* RX Errors */
+	u32     rx_crc_errors       __attribute((packed)); 	
+	u32     rx_alignment_errors  __attribute((packed)); 	
+	u32     rx_overrun_errors    __attribute((packed));
+	u32     rx_tooshort_errors  __attribute((packed));
+	u32     rx_toolong_errors   __attribute((packed));
+	u32     rx_outofresource_errors  __attribute((packed)); 
+
+	u32     rx_discarded   __attribute((packed));  /* via card pattern match filter */ 
+
+	/* TX Errors */
+	u32     tx_max_collisions __attribute((packed)); 
+	u32     tx_carrier_errors __attribute((packed)); 
+	u32     tx_underrun_errors __attribute((packed)); 
+	u32     tx_cts_errors     __attribute((packed)); 
+	u32     tx_timeout_errors __attribute((packed)) ;
+	
+	/* various cruft */
+	u32     dataA[6] __attribute((packed));   
+        u16	dataB[5] __attribute((packed));   
+  	u32     dataC[14] __attribute((packed)); 	
+};
 
-#define CONTROL_EOP	0x80	/* End Of Packet */
-#define CONTROL_EL	0x40	/* End of List */
+#define STATUS_MASK	0x0F
+#define COMPLETED	(1<<7)
+#define COMPLETED_OK	(1<<6)
+#define BUFFER_BUSY	(1<<5)
 
+#define CONTROL_EOP	(1<<7)	/* End Of Packet */
+#define CONTROL_EOL	(1<<6)	/* End of List */
 
-#define MCA_MC32_ID	0x0041	/* Our MCA ident */
\ No newline at end of file
+#define MCA_MC32_ID	0x0041	/* Our MCA ident */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/3c59x.c linux.19p18/drivers/net/3c59x.c
--- linux.vanilla/drivers/net/3c59x.c	Mon Dec 11 22:12:47 2000
+++ linux.19p18/drivers/net/3c59x.c	Mon Feb 19 18:23:03 2001
@@ -60,14 +60,42 @@
     - In vortex_open(), set vp->tx_full to zero (else we get errors if the device was
       closed with a full Tx ring).
 
-	15Sep00 <2.2.18-pre3> andrewm
+	17Oct00 <2.2.18-pre16> andrewm
 	- Added support for the 3c556B Laptop Hurricane (Louis Gerbarg)
+    - Backported transceiver options handling from 2.4.  This changes the semantics
+      of forcing full duplex in the `options' parm!  (It's better to use
+      `full_duplex' anyway).  See Documentation/vortex.txt (Maciej Rozycki).
+    - Set PCI latency timer to maximum for the 3c590 (From Donald's driver)
+    - Removed all the CARDBUS code (it's never used).
+    - Added INVERT_MII_PWR, EEPROM_8BIT, EEPROM_OFFSET.  Use them.
+    - Use EEPROM_8BIT for the 3c555
+    - Merged ACPI WOL support from Donald's drivers.
+    - Sort-of backported Donald's new medialock code. Called it duplexlock
+      and we now prefer to use `full_duplex=[-1,0,1]' to force duplex mode.
+    - Merged the rx_oom_timer from 2.4.  This gives better handling of OOM
+      conditions.  Backed out the previous way of handling this.
+    - Replace suser() with capable(CAP_NET_ADMIN) in ioctl().
+
+    07Jan01 <2.2.19-pre6> andrewm
+    - Add HAS_NWAY to "3c900 Cyclone 10Mbps TPO"
+    - Added and used wait_for_completion().  3c905CX problems.
+    - Removed the code for older kernel versions.
+    - Add HAS_NWAY to 3cSOHO100-TX (Brett Frankenberger)
+    - Search for phy 24 first for 3c905CX. (D Becker)
+    - Don't free skbs we don't own on oom path in vortex_open().
+    - Added explicit `medialock' flag so we can truly
+      lock the media type down with `options'.
+    - In vortex_error(), only reset the up/down load engine, not all the
+      interface stuff.
+    - Added and used EEPROM_NORESET for 3c556B PM resumes.
+    - Enable WOL with the `enable_wol' module parm
+    - Give the 3c980 HAS_NWAY
 
     - See http://www.uow.edu.au/~andrewm/linux/#3c59x-2.2 for more details.
 */
 
 static char version[] =
-"3c59x.c 15Sep00 Donald Becker and others http://www.scyld.com/network/vortex.html\n";
+"3c59x.c 18Feb01 Donald Becker and others http://www.scyld.com/network/vortex.html\n";
 
 /* "Knobs" that adjust features and parameters. */
 /* Set the copy breakpoint for the copy-only-tiny-frames scheme.
@@ -101,16 +129,6 @@
 
 #include <linux/config.h>
 #include <linux/version.h>
-#ifdef MODULE
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
-#include <linux/module.h>
-#else
-#define MOD_INC_USE_COUNT
-#define MOD_DEC_USE_COUNT
-#endif
-
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
@@ -124,9 +142,8 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
-#if LINUX_VERSION_CODE < 0x20155  ||  defined(CARDBUS)
-#include <linux/bios32.h>
-#endif
+#include <linux/delay.h>
+#include <linux/module.h>
 #include <asm/irq.h>			/* For NR_IRQS only. */
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -136,48 +153,18 @@
 
 #define RUN_AT(x) (jiffies + (x))
 
-#include <linux/delay.h>
-
-#if (LINUX_VERSION_CODE <= 0x20100)
-#ifndef __alpha__
-#define ioremap(a,b) \
-	(((a)<0x100000) ? (void *)((u_long)(a)) : vremap(a,b))
-#define iounmap(v) \
-	do { if ((u_long)(v) > 0x100000) vfree(v); } while (0)
-#endif
-#endif
-#if LINUX_VERSION_CODE <= 0x20139
-#define	net_device_stats enet_statistics
-#define NETSTATS_VER2
-#endif
-#if LINUX_VERSION_CODE < 0x20138
-#define test_and_set_bit(val, addr) set_bit(val, addr)
-#define le32_to_cpu(val) (val)
-#define cpu_to_le32(val) (val)
-#endif
-#if LINUX_VERSION_CODE < 0x20155
-#define PCI_SUPPORT_VER1
-#else
-#define PCI_SUPPORT_VER2
-#endif
-#if LINUX_VERSION_CODE < 0x20159
-#define DEV_FREE_SKB(skb) dev_kfree_skb (skb, FREE_WRITE);
-#else  /* Grrr, unneeded incompatible change. */
-#define DEV_FREE_SKB(skb) dev_kfree_skb(skb);
-#endif
 
-#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
-MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("3Com 3c590/3c900 series Vortex/Boomerang driver");
 MODULE_PARM(debug, "i");
 MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(enable_wol, "1-" __MODULE_STRING(8) "i");
 MODULE_PARM(rx_copybreak, "i");
 MODULE_PARM(max_interrupt_work, "i");
 MODULE_PARM(compaq_ioaddr, "i");
 MODULE_PARM(compaq_irq, "i");
 MODULE_PARM(compaq_device_id, "i");
-#endif
 
 /* Operational parameter that usually are not changed. */
 
@@ -286,7 +273,9 @@
 };
 
 enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4, IS_TORNADO=8,
-	   HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80, };
+	   HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80,
+	   INVERT_MII_PWR=0x100, EEPROM_8BIT=0x200, EEPROM_OFFSET=0x400,
+	   EEPROM_NORESET=0x800};
 static struct device *vortex_probe1(int pci_bus, int pci_devfn,
 									struct device *dev, long ioaddr,
 									int irq, int dev_id, int card_idx);
@@ -316,7 +305,7 @@
 	{"3c900B-FL Cyclone 10base-FL",	0x10B7, 0x900A, 0xffff,
 	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
 	{"3c900 Cyclone 10Mbps TPO",	0x10B7, 0x9004, 0xffff,			/* AKPM: from Don's 0.99M */
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1},
 	{"3c900 Cyclone 10Mbps TPC",	0x10B7, 0x9006, 0xffff,			/* AKPM: from Don's 0.99M */
 	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
 	{"3c905 Boomerang 100baseTx",	0x10B7, 0x9050, 0xffff,
@@ -332,15 +321,15 @@
 	{"3c905C Tornado",	0x10B7, 0x9200, 0xffff,
 	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY, 128, vortex_probe1},
 	{"3c980 Cyclone",	0x10B7, 0x9800, 0xfff0,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1},
 	{"3cSOHO100-TX Hurricane",	0x10B7, 0x7646, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1},
 	{"3c555 Laptop Hurricane",	0x10B7, 0x5055, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|EEPROM_8BIT, 128, vortex_probe1},
 	{"3c556 10/100 Mini PCI Adapter",	0x10B7, 0x6055, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_CB_FNS, 128, vortex_probe1},
+	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_8BIT|HAS_CB_FNS|INVERT_MII_PWR, 128, vortex_probe1},
 	{"3c556B Laptop Hurricane",	0x10B7, 0x6056, 0xffff,
-	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_CB_FNS, 128, vortex_probe1},
+	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_OFFSET|HAS_CB_FNS|INVERT_MII_PWR|EEPROM_NORESET, 128, vortex_probe1},
 	{"3c575 Boomerang CardBus",		0x10B7, 0x5057, 0xffff,
 	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
 	{"3CCFE575 Cyclone CardBus",	0x10B7, 0x5157, 0xffff,
@@ -501,7 +490,7 @@
 };
 
 /* Chip features we care about in vp->capabilities, read from the EEPROM. */
-enum ChipCaps { CapBusMaster=0x20 };
+enum ChipCaps { CapBusMaster=0x20, CapPwrMgmt=0x2000 };
 
 struct vortex_private {
 	/* The Rx and Tx rings should be quad-word-aligned. */
@@ -515,23 +504,27 @@
 	unsigned int cur_rx, cur_tx;		/* The next free ring entry */
 	unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
 	struct net_device_stats stats;
-	struct sk_buff *tx_skb;		/* Packet being eaten by bus master ctrl.  */
+	struct sk_buff *tx_skb;				/* Packet being eaten by bus master ctrl.  */
 
 	/* PCI configuration space information. */
-	u8 pci_bus, pci_devfn;		/* PCI bus location, for power management. */
-	char *cb_fn_base;			/* CardBus function status addr space. */
+	u8 pci_bus, pci_devfn;				/* PCI bus location, for power management. */
+	char *cb_fn_base;					/* CardBus function status addr space. */
 	int chip_id;
 
 	/* The remainder are related to chip state, mostly media selection. */
-	struct timer_list timer;	/* Media selection timer. */
-	int options;				/* User-settable misc. driver options. */
-	unsigned int media_override:3, 			/* Passed-in media type. */
+	struct timer_list timer;			/* Media selection timer. */
+	struct timer_list rx_oom_timer;		/* Rx skb allocation retry timer */
+	int options;						/* User-settable misc. driver options. */
+	unsigned int media_override:4, 		/* Passed-in media type. */
 		default_media:4,				/* Read from the EEPROM/Wn3_Config. */
-		full_duplex:1, force_fd:1, autoselect:1,
-		bus_master:1,				/* Vortex can only do a fragment bus-m. */
+		full_duplex:1,					/* User wants FD (or we're running at FD) */
+		duplexlock:1,					/* User has forced duplex */
+		autoselect:1,					/* Can use NWAY negotiation */
+		bus_master:1,					/* Vortex can only do a fragment bus-m. */
 		full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang  */
-		hw_csums:1,				/* Has hardware checksums. */
-		tx_full:1;
+		tx_full:1,
+		enable_wol:1,
+		medialock:1;
 	u16 status_enable;
 	u16 intr_enable;
 	u16 available_media;				/* From Wn3_Options. */
@@ -571,14 +564,13 @@
   { "Default",	 0,			0xFF, XCVR_10baseT, 10000},
 };
 
-#ifndef CARDBUS
 static int vortex_scan(struct device *dev, struct pci_id_info pci_tbl[]);
-#endif
 static int vortex_open(struct device *dev);
 static void mdio_sync(long ioaddr, int bits);
 static int mdio_read(long ioaddr, int phy_id, int location);
 static void mdio_write(long ioaddr, int phy_id, int location, int value);
 static void vortex_timer(unsigned long arg);
+static void rx_oom_timer(unsigned long arg);
 static int vortex_start_xmit(struct sk_buff *skb, struct device *dev);
 static int boomerang_start_xmit(struct sk_buff *skb, struct device *dev);
 static int vortex_rx(struct device *dev);
@@ -590,116 +582,33 @@
 static struct net_device_stats *vortex_get_stats(struct device *dev);
 static void set_rx_mode(struct device *dev);
 static int vortex_ioctl(struct device *dev, struct ifreq *rq, int cmd);
+static void acpi_wake(int pci_bus, int pci_devfn);
+static void acpi_set_WOL(struct device *dev);
 
 
-/* #define dev_alloc_skb dev_alloc_skb_debug */
+#if 0
+#warning dev_alloc_skb_debug is defined!
+#define dev_alloc_skb dev_alloc_skb_debug
+#endif
 
 /* This driver uses 'options' to pass the media type, full-duplex flag, etc. */
 /* Option count limit only -- unlimited interfaces are supported. */
 #define MAX_UNITS 8
-static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1,};
+static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1};
 static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int enable_wol[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
 /* A list of all installed Vortex devices, for removing the driver module. */
 static struct device *root_vortex_dev = NULL;
 
 #ifdef MODULE
-#ifndef CARDBUS
 /* Variables to work-around the Compaq PCI BIOS32 problem. */
 static int compaq_ioaddr = 0, compaq_irq = 0, compaq_device_id = 0x5900;
-#endif
-
-#ifdef CARDBUS
-
-#include <pcmcia/driver_ops.h>
-
-static dev_node_t *vortex_attach(dev_locator_t *loc)
-{
-	u16 dev_id, vendor_id;
-	u32 io;
-	u8 bus, devfn, irq;
-	struct device *dev;
-	int chip_idx;
-
-	if (loc->bus != LOC_PCI) return NULL;
-	bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
-	pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io);
-	pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq);
-	pcibios_read_config_word(bus, devfn, PCI_VENDOR_ID, &vendor_id);
-	pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id);
-	printk(KERN_INFO "vortex_attach(bus %d, function %d, device %4.4x)\n",
-		   bus, devfn, dev_id);
-	io &= ~3;
-	if (io == 0 || irq == 0) {
-		printk(KERN_ERR "The 3Com CardBus Ethernet interface was not "
-			   "assigned an %s.\n" KERN_ERR "  It will not be activated.\n",
-			   io == 0 ? "I/O address" : "IRQ");
-		return NULL;
-	}
-	for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
-		if (vendor_id == pci_tbl[chip_idx].vendor_id
-			&& (dev_id & pci_tbl[chip_idx].device_id_mask) ==
-			pci_tbl[chip_idx].device_id)
-			break;
-	if (pci_tbl[chip_idx].vendor_id == 0) { 		/* Compiled out! */
-		printk(KERN_INFO "Unable to match chip type %4.4x %4.4x in "
-			   "vortex_attach().\n", vendor_id, dev_id);
-		return NULL;
-	}
-	dev = vortex_probe1(bus, devfn, NULL, io, irq, chip_idx, MAX_UNITS+1);
-	if (dev) {
-		dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
-		if (!node)
-			return NULL;
-		strcpy(node->dev_name, dev->name);
-		node->major = node->minor = 0;
-		node->next = NULL;
-		MOD_INC_USE_COUNT;
-		return node;
-	}
-	return NULL;
-}
-
-static void vortex_detach(dev_node_t *node)
-{
-	struct device **devp, **next;
-	printk(KERN_INFO "vortex_detach(%s)\n", node->dev_name);
-	for (devp = &root_vortex_dev; *devp; devp = next) {
-		next = &((struct vortex_private *)(*devp)->priv)->next_module;
-		if (strcmp((*devp)->name, node->dev_name) == 0) break;
-	}
-	if (*devp) {
-		struct device *dev = *devp;
-		struct vortex_private *vp = dev->priv;
-		if (dev->flags & IFF_UP)
-			vortex_close(dev);
-		dev->flags &= ~(IFF_UP|IFF_RUNNING);
-		unregister_netdev(dev);
-		if (vp->cb_fn_base) iounmap(vp->cb_fn_base);
-		kfree(dev);
-		*devp = *next;
-		kfree(vp);
-		kfree(node);
-		MOD_DEC_USE_COUNT;
-	}
-}
-
-struct driver_operations vortex_ops = {
-	"3c575_cb", vortex_attach, NULL, NULL, vortex_detach
-};
-
-#endif  /* Cardbus support */
-
 
 int init_module(void)
 {
 	if (vortex_debug)
 		printk(KERN_INFO "%s", version);
-#ifdef CARDBUS
-	register_driver(&vortex_ops);
-	return 0;
-#else
 	return vortex_scan(0, pci_tbl);
-#endif
 }
 
 #else
@@ -713,7 +622,30 @@
 }
 #endif  /* not MODULE */
 
-#ifndef CARDBUS
+static void wait_for_completion(struct device *dev, int cmd)
+{
+	int i;
+
+	outw(cmd, dev->base_addr + EL3_CMD);
+	for (i = 0; i < 2000; i++) {
+		if (!(inw(dev->base_addr + EL3_STATUS) & CmdInProgress))
+			return;
+	}
+
+	/* OK, that didn't work.  Do it the slow way.  One second */
+	for (i = 0; i < 100000; i++) {
+		if (!(inw(dev->base_addr + EL3_STATUS) & CmdInProgress)) {
+			if (vortex_debug > 1)
+				printk(KERN_INFO "%s: command 0x%04x took %d usecs!\n",
+					   dev->name, cmd, i * 10);
+			return;
+		}
+		udelay(10);
+	}
+	printk(KERN_ERR "%s: command 0x%04x did not complete! Status=0x%x\n",
+			   dev->name, cmd, inw(dev->base_addr + EL3_STATUS));
+}
+
 static int vortex_scan(struct device *dev, struct pci_id_info pci_tbl[])
 {
 	int cards_found = 0;
@@ -734,8 +666,7 @@
 			long ioaddr;
 
 			if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index,
-									&pci_bus, &pci_device_fn)
-				!= PCIBIOS_SUCCESSFUL)
+									&pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL)
 				break;
 			pcibios_read_config_word(pci_bus, pci_device_fn,
 									 PCI_VENDOR_ID, &vendor);
@@ -749,21 +680,13 @@
 			if (pci_tbl[chip_idx].vendor_id == 0) 		/* Compiled out! */
 				continue;
 
+			/* The Cyclone requires config space re-write if powered down. */
+			acpi_wake(pci_bus, pci_device_fn);
+
 			{
-#if LINUX_VERSION_CODE >= 0x20155
 				struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
 				ioaddr = pdev->base_address[0] & ~3;
 				irq = pdev->irq;
-#else
-				u32 pci_ioaddr;
-				u8 pci_irq_line;
-				pcibios_read_config_byte(pci_bus, pci_device_fn,
-										 PCI_INTERRUPT_LINE, &pci_irq_line);
-				pcibios_read_config_dword(pci_bus, pci_device_fn,
-										  PCI_BASE_ADDRESS_0, &pci_ioaddr);
-				ioaddr = pci_ioaddr & ~3;;
-				irq = pci_irq_line;
-#endif
 			}
 
 			/* Power-up the card. */
@@ -811,21 +734,21 @@
 								chip_idx, cards_found);
 
 			if (dev) {
-				/* Get and check the latency values.  On the 3c590 series
-				   the latency timer must be set to the maximum value to avoid
-				   data corruption that occurs when the timer expires during
-				   a transfer -- a bug in the Vortex chip only. */
-				u8 pci_latency;
-				u8 new_latency = (device & 0xff00) == 0x5900 ? 248 : 32;
-				
-				pcibios_read_config_byte(pci_bus, pci_device_fn,
-										 PCI_LATENCY_TIMER, &pci_latency);
-				if (pci_latency < new_latency) {
-					printk(KERN_INFO "%s: Overriding PCI latency"
-						   " timer (CFLT) setting of %d, new value is %d.\n",
-						   dev->name, pci_latency, new_latency);
-					pcibios_write_config_byte(pci_bus, pci_device_fn,
-											  PCI_LATENCY_TIMER, new_latency);
+				if ((device & 0xff00) == 0x5900) {
+					/* Get and check the latency values.  On the 3c590 series
+					   the latency timer must be set to the maximum value to avoid
+					   data corruption that occurs when the timer expires during
+					   a transfer -- a bug in the Vortex chip only. */
+					u8 pci_latency;
+					u8 new_latency = 248;
+					
+					pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_LATENCY_TIMER, &pci_latency);
+					if (pci_latency < new_latency) {
+						printk(KERN_INFO "%s: Overriding PCI latency"
+							   " timer (CFLT) setting of %d, new value is %d.\n",
+							   dev->name, pci_latency, new_latency);
+						pcibios_write_config_byte(pci_bus, pci_device_fn, PCI_LATENCY_TIMER, new_latency);
+					}
 				}
 				dev = 0;
 				cards_found++;
@@ -866,7 +789,6 @@
 
 	return cards_found ? 0 : -ENODEV;
 }
-#endif  /* ! Cardbus */
 
 static struct device *vortex_probe1(int pci_bus, int pci_devfn,
 									struct device *dev, long ioaddr,
@@ -878,6 +800,10 @@
 	int i;
 
 	dev = init_etherdev(dev, 0);
+	if (dev == NULL) {
+		printk(KERN_EMERG "3c59x: init_etherdev failed\n");
+		return NULL;
+	}
 
 	printk(KERN_INFO "%s: 3Com %s at 0x%lx, ",
 		   dev->name, pci_tbl[chip_idx].name, ioaddr);
@@ -889,12 +815,16 @@
 	/* Make certain the descriptor lists are aligned. */
 	{
 		void *mem = kmalloc(sizeof(*vp) + 15, GFP_KERNEL);
-		if (!mem)
+		if (!mem) {
+			printk(KERN_EMERG "3c59x: out of memory for dev->priv\n");
+			unregister_netdev(dev);
+			kfree(dev);
 			return NULL;
+		}
 		vp =  (void *)(((long)mem + 15) & ~15);
+		memset(vp, 0, sizeof(*vp));
 		vp->priv_addr = mem;
 	}
-	memset(vp, 0, sizeof(*vp));
 	dev->priv = vp;
 
 	vp->next_module = root_vortex_dev;
@@ -906,51 +836,68 @@
 	vp->pci_devfn = pci_devfn;
 
 	/* The lower four bits are the media type. */
+	option = -1;
 	if (dev->mem_start)
 		option = dev->mem_start;
 	else if (card_idx < MAX_UNITS)
 		option = options[card_idx];
-	else
-		option = -1;
 
 	if (option >= 0) {
-		vp->media_override = ((option & 7) == 2)  ?  0  :  option & 7;
-		vp->full_duplex = (option & 8) ? 1 : 0;
+		vp->media_override = ((option & 7) == 2)  ?  0  :  option & 15;
+		if (vp->media_override != 7)
+			vp->medialock = 1;
+		if (option & 0x200) {
+			vp->full_duplex = 1;
+			vp->duplexlock = 1;
+			printk(	"\n" KERN_WARNING
+					"%s: forcing duplex via options is deprecated - use `full_duplex'.\n",
+					dev->name);
+		}
 		vp->bus_master = (option & 16) ? 1 : 0;
 	} else {
 		vp->media_override = 7;
 		vp->full_duplex = 0;
 		vp->bus_master = 0;
 	}
-	if (card_idx < MAX_UNITS  &&  full_duplex[card_idx] > 0)
-		vp->full_duplex = 1;
-
-	vp->force_fd = vp->full_duplex;
+	if (card_idx < MAX_UNITS) {
+		if (enable_wol[card_idx] > 0)
+			vp->enable_wol = 1;
+		if (full_duplex[card_idx] == 0) {	/* full_duplex=0 : force half duplex */
+			vp->duplexlock = 1;
+		}
+		if (full_duplex[card_idx] > 0) {	/* full_duplex=1: force full duplex */
+			vp->duplexlock = 1;
+			vp->full_duplex = 1;
+		}
+		/* full_duplex=-1: duplex is not forced */
+	}
 	vp->options = option;
 
 	/* Read the station address from the EEPROM. */
 	EL3WINDOW(0);
-	for (i = 0; i < 0x40; i++) {
-		int timer;
-#ifdef CARDBUS
-		outw(0x230 + i, ioaddr + Wn0EepromCmd);
-#else
-		if (pci_tbl[chip_idx].device_id == 0x6055) {
-			outw(0x230 + i, ioaddr + Wn0EepromCmd);
-		} else if (pci_tbl[chip_idx].device_id == 0x6056) {
-			outw(EEPROM_Read + 0x30 + i, ioaddr + Wn0EepromCmd);
-		} else {
-			outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd);
-		}
-#endif
-		/* Pause for at least 162 us. for the read to take place. */
-		for (timer = 10; timer >= 0; timer--) {
-			udelay(162);
-			if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0)
-				break;
+	{
+		int base;
+
+		if (pci_tbl[chip_idx].drv_flags & EEPROM_8BIT)
+			base = 0x230;
+		else if (pci_tbl[chip_idx].drv_flags & EEPROM_OFFSET)
+			base = EEPROM_Read + 0x30;
+		else
+			base = EEPROM_Read;
+
+		for (i = 0; i < 0x40; i++) {
+			int timer;
+			outw(base + i, ioaddr + Wn0EepromCmd);
+			/* Pause for at least 162 us. for the read to take place. */
+			for (timer = 10; timer >= 0; timer--) {
+				udelay(162);
+				if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0)
+					break;
+			}
+			eeprom[i] = inw(ioaddr + Wn0EepromData);
 		}
-		eeprom[i] = inw(ioaddr + Wn0EepromData);
 	}
+
 	for (i = 0; i < 0x18; i++)
 		checksum ^= eeprom[i];
 	checksum = (checksum ^ (checksum >> 8)) & 0xff;
@@ -978,6 +925,7 @@
 
 	if (pci_tbl[vp->chip_id].drv_flags & HAS_CB_FNS) {
 		u32 fn_st_addr;			/* Cardbus function status space */
+		u16 n;
 		pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_2,
 								  &fn_st_addr);
 		if (fn_st_addr)
@@ -985,11 +933,12 @@
 		printk("%s: CardBus functions mapped %8.8x->%p (PCMCIA committee"
 			   " brain-damage).\n", dev->name, fn_st_addr, vp->cb_fn_base);
 		EL3WINDOW(2);
-		if (pci_tbl[chip_idx].device_id == 0x6055) {
-			outw(0x4010 | inw(ioaddr + Wn2_ResetOptions), ioaddr + Wn2_ResetOptions);
-		} else {
-			outw(0x10 | inw(ioaddr + Wn2_ResetOptions), ioaddr + Wn2_ResetOptions);
-		}
+
+		n = inw(ioaddr + Wn2_ResetOptions) & ~0x4010;
+		n |= 0x10;
+		if (pci_tbl[chip_idx].drv_flags & INVERT_MII_PWR)
+			n |= 0x4000;
+		outw(n, ioaddr + Wn2_ResetOptions);
 	}
 
 	/* Extract our information from the EEPROM data. */
@@ -997,7 +946,7 @@
 	vp->info2 = eeprom[15];
 	vp->capabilities = eeprom[16];
 
-	if (vp->info1 & 0x8000)
+	if (!vp->duplexlock && (vp->info1 & 0x8000))
 		vp->full_duplex = 1;
 
 	{
@@ -1035,8 +984,19 @@
 		mii_preamble_required++;
 		mii_preamble_required++;
 		mdio_read(ioaddr, 24, 1);
-		for (phy = 1; phy <= 32 && phy_idx < sizeof(vp->phys); phy++) {
-			int mii_status, phyx = phy & 0x1f;
+		for (phy = 0; phy < 32 && phy_idx < 1; phy++) {
+			int mii_status, phyx;
+
+			/*
+			 * For the 3c905CX we look at index 24 first, because it bogusly
+			 * reports an external PHY at all indices
+			 */
+			if (phy == 0)
+				phyx = 24;
+			else if (phy <= 24)
+				phyx = phy - 1;
+			else
+				phyx = phy;
 			mii_status = mdio_read(ioaddr, phyx, 1);
 			if (mii_status  &&  mii_status != 0xffff) {
 				vp->phys[phy_idx++] = phyx;
@@ -1060,6 +1020,9 @@
 		}
 	}
 
+	if (vp->enable_wol && (vp->capabilities & CapPwrMgmt))
+		acpi_set_WOL(dev);
+
 	if (vp->capabilities & CapBusMaster) {
 		vp->full_bus_master_tx = 1;
 		printk(KERN_INFO"  Enabling bus-master transmits and %s receives.\n",
@@ -1093,6 +1056,9 @@
 
 	MOD_INC_USE_COUNT;
 
+	if (vp->enable_wol)
+		acpi_wake(vp->pci_bus, vp->pci_devfn);
+
 	/* Before initializing select the active media port. */
 	EL3WINDOW(3);
 	config = inl(ioaddr + Wn3_Config);
@@ -1104,7 +1070,9 @@
 				   media_tbl[vp->media_override].name);
 		dev->if_port = vp->media_override;
 	} else if (vp->autoselect && pci_tbl[vp->chip_id].drv_flags & HAS_NWAY) {
-			dev->if_port = XCVR_NWAY;
+		if (vortex_debug > 1)
+			printk(KERN_INFO "%s: using NWAY from config\n", dev->name);
+		dev->if_port = XCVR_NWAY;
 	} else if (vp->autoselect) {
 		/* Find first available media type, starting with 100baseTx. */
 		dev->if_port = XCVR_100baseTx;
@@ -1113,11 +1081,11 @@
 	} else
 		dev->if_port = vp->default_media;
 
-	if (vortex_debug > 1)
-		printk(KERN_DEBUG "%s: Initial media type %s.\n",
-			   dev->name, media_tbl[dev->if_port].name);
+	printk(KERN_INFO "%s: Initial media type %s.\n", dev->name, media_tbl[dev->if_port].name);
+
+	if (!vp->duplexlock && (vp->info1 & 0x8000))
+		vp->full_duplex = 1;
 
-	vp->full_duplex = vp->force_fd;
 	config = BFINS(config, dev->if_port, 20, 4);
 	outl(config, ioaddr + Wn3_Config);
 
@@ -1129,35 +1097,25 @@
 		mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5);
 		if (mii_reg5 == 0xffff  ||  mii_reg5 == 0x0000)
 			;					/* No MII device or no link partner report */
-		else if ((mii_reg5 & 0x0100) != 0	/* 100baseTx-FD */
-				 || (mii_reg5 & 0x00C0) == 0x0040) /* 10T-FD, but not 100-HD */
+		else if (!vp->duplexlock &&
+				((mii_reg5 & 0x0100) != 0			/* 100baseTx-FD */
+				|| (mii_reg5 & 0x00C0) == 0x0040))		/* 10T-FD, but not 100-HD */
 			vp->full_duplex = 1;
-		if (vortex_debug > 1)
-			printk(KERN_INFO "%s: MII #%d status %4.4x, link partner capability %4.4x,"
-				   " setting %s-duplex.\n", dev->name, vp->phys[0],
-				   mii_reg1, mii_reg5, vp->full_duplex ? "full" : "half");
+		printk(KERN_INFO "%s: MII #%d status %4.4x, link partner capability %4.4x,"
+			   " setting %s-duplex.\n", dev->name, vp->phys[0],
+			   mii_reg1, mii_reg5, vp->full_duplex ? "full" : "half");
 		EL3WINDOW(3);
 	}
 
 	/* Set the full-duplex bit. */
-	outb(((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) |
-		 (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl);
+	outb((vp->full_duplex ? 0x20 : 0) | (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl);
 
 	if (vortex_debug > 1) {
-		printk(KERN_DEBUG "%s: vortex_open() InternalConfig %8.8x.\n",
-			dev->name, config);
+		printk(KERN_DEBUG "%s: vortex_open() InternalConfig %8.8x.\n", dev->name, config);
 	}
 
-	outw(TxReset, ioaddr + EL3_CMD);
-	for (i = 2000; i >= 0 ; i--)
-		if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-			break;
-
-	outw(RxReset, ioaddr + EL3_CMD);
-	/* Wait a few ticks for the RxReset command to complete. */
-	for (i = 2000; i >= 0 ; i--)
-		if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-			break;
+	wait_for_completion(dev, TxReset);
+	wait_for_completion(dev, RxReset);
 
 	outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
 
@@ -1224,18 +1182,15 @@
 			if (skb == NULL)
 				break;			/* Bad news!  */
 			skb->dev = dev;			/* Mark as being used by this device. */
-#if LINUX_VERSION_CODE >= 0x10300
 			skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
 			vp->rx_ring[i].addr = cpu_to_le32(virt_to_bus(skb->tail));
-#else
-			vp->rx_ring[i].addr = virt_to_bus(skb->data);
-#endif
 		}
 		if (i != RX_RING_SIZE) {
 			int j;
-			for (j = 0; j < RX_RING_SIZE; j++) {
+			printk(KERN_EMERG "%s: no memory for rx ring\n", dev->name);
+			for (j = 0; j < i; j++) {
 				if (vp->rx_skbuff[j])
-					DEV_FREE_SKB(vp->rx_skbuff[j]);
+					dev_kfree_skb(vp->rx_skbuff[j]);
 			}
 			retval = -ENOMEM;
 			goto out_free_irq;
@@ -1285,6 +1240,10 @@
 	vp->timer.function = &vortex_timer;		/* timer handler */
 	add_timer(&vp->timer);
 
+	init_timer(&vp->rx_oom_timer);
+	vp->rx_oom_timer.data = (unsigned long)dev;
+	vp->rx_oom_timer.function = rx_oom_timer;
+
 	return 0;
 
 out_free_irq:
@@ -1306,6 +1265,8 @@
 		printk(KERN_DEBUG "%s: Media selection timer tick happened, %s.\n",
 			   dev->name, media_tbl[dev->if_port].name);
 
+	if (vp->medialock)
+		goto leave_media_alone;
 	disable_irq(dev->irq);
 	old_window = inw(ioaddr + EL3_CMD) >> 13;
 	EL3WINDOW(4);
@@ -1332,7 +1293,7 @@
 					 dev->name, mii_status);
 		  if (mii_status & 0x0004) {
 			  int mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5);
-			  if (! vp->force_fd  &&  mii_reg5 != 0xffff) {
+			  if (!vp->duplexlock && mii_reg5 != 0xffff) {
 				  int duplex = (mii_reg5&0x0100) ||
 					  (mii_reg5 & 0x01C0) == 0x0040;
 				  if (vp->full_duplex != duplex) {
@@ -1342,7 +1303,7 @@
 							 dev->name, vp->full_duplex ? "full" : "half",
 							 vp->phys[0], mii_reg5);
 					  /* Set the full-duplex bit. */
-					  EL3WINDOW(3);   /* AKPM */
+					  EL3WINDOW(3);
 					  outb((vp->full_duplex ? 0x20 : 0) |
 						   (dev->mtu > 1500 ? 0x40 : 0),
 						   ioaddr + Wn3_MAC_Ctrl);
@@ -1392,6 +1353,7 @@
 	EL3WINDOW(old_window);
 	enable_irq(dev->irq);
 
+leave_media_alone:
 	if (vortex_debug > 2)
 	  printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n",
 			 dev->name, media_tbl[dev->if_port].name);
@@ -1407,7 +1369,6 @@
 {
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	long ioaddr = dev->base_addr;
-	int j;
 
 	printk(KERN_ERR "%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
 		   dev->name, inb(ioaddr + TxStatus),
@@ -1435,12 +1396,7 @@
 			__restore_flags(flags);
 		}
 	}
-	outw(TxReset, ioaddr + EL3_CMD);
-	for (j = 200; j >= 0 ; j--)
-		if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-			break;
 
-#if ! defined(final_version) && LINUX_VERSION_CODE >= 0x10300
 	if (vp->full_bus_master_tx) {
 		int i;
 		printk(KERN_DEBUG "  Flags; bus-master %d, full %d; dirty %d "
@@ -1456,7 +1412,7 @@
 				   le32_to_cpu(vp->tx_ring[i].status));
 		}
 	}
-#endif
+	wait_for_completion(dev, TxReset);
 	vp->stats.tx_errors++;
 	if (vp->full_bus_master_tx) {
 		if (vortex_debug > 0)
@@ -1494,7 +1450,6 @@
 	struct vortex_private *vp = (struct vortex_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 	int do_tx_reset = 0;
-	int i;
 
 	if (status & TxComplete) {			/* Really "TxError" for us. */
 		unsigned char tx_status = inb(ioaddr + TxStatus);
@@ -1545,20 +1500,14 @@
 				   dev->name, fifo_diag);
 		/* Adapter failure requires Tx/Rx reset and reinit. */
 		if (vp->full_bus_master_tx) {
-			outw(TotalReset | 0xff, ioaddr + EL3_CMD);
-			for (i = 2000; i >= 0 ; i--)
-				if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-					break;
+			wait_for_completion(dev, TotalReset|0xff);
 			/* Re-enable the receiver. */
 			outw(RxEnable, ioaddr + EL3_CMD);
 			outw(TxEnable, ioaddr + EL3_CMD);
 		} else if (fifo_diag & 0x0400)
 			do_tx_reset = 1;
 		if (fifo_diag & 0x3000) {
-			outw(RxReset, ioaddr + EL3_CMD);
-			for (i = 2000; i >= 0 ; i--)
-				if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-					break;
+			wait_for_completion(dev, RxReset);
 			/* Set the Rx filter to the current state. */
 			set_rx_mode(dev);
 			outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */
@@ -1566,11 +1515,7 @@
 		}
 	}
 	if (do_tx_reset) {
-		int j;
-		outw(TxReset, ioaddr + EL3_CMD);
-		for (j = 4000; j >= 0 ; j--)
-			if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-				break;
+		wait_for_completion(dev, TxReset);
 		outw(TxEnable, ioaddr + EL3_CMD);
 		if (!vp->full_bus_master_tx) {
 			clear_bit(0, (void*)&dev->tbusy);
@@ -1580,7 +1525,6 @@
 
 }
 
-
 static int
 vortex_start_xmit(struct sk_buff *skb, struct device *dev)
 {
@@ -1609,7 +1553,7 @@
 #else
 		outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
 #endif
-		DEV_FREE_SKB(skb);
+		dev_kfree_skb(skb);
 		if (inw(ioaddr + TxFree) > 1536) {
 			clear_bit(0, (void*)&dev->tbusy);
 		} else
@@ -1631,13 +1575,8 @@
 						 dev->name, tx_status);
 				if (tx_status & 0x04) vp->stats.tx_fifo_errors++;
 				if (tx_status & 0x38) vp->stats.tx_aborted_errors++;
-				if (tx_status & 0x30) {
-					int j;
-					outw(TxReset, ioaddr + EL3_CMD);
-					for (j = 200; j >= 0 ; j--)
-						if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-							break;
-				}
+				if (tx_status & 0x30)
+					wait_for_completion(dev, TxReset);
 				outw(TxEnable, ioaddr + EL3_CMD);
 			}
 			outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */
@@ -1663,7 +1602,6 @@
 		struct boom_tx_desc *prev_entry =
 			&vp->tx_ring[(vp->cur_tx-1) % TX_RING_SIZE];
 		unsigned long flags;
-		int i;
 
 		if (vortex_debug > 3)
 			printk(KERN_DEBUG "%s: Trying to send a boomerang packet, Tx index %d.\n",
@@ -1681,11 +1619,7 @@
 		vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded);
 
 		spin_lock_irqsave(&vp->lock, flags);
-		outw(DownStall, ioaddr + EL3_CMD);
-		/* Wait for the stall to complete. */
-		for (i = 4000; i >= 0; i--)
-			if ( (inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0)
-				break;
+		wait_for_completion(dev, DownStall);
 		prev_entry->next = cpu_to_le32(virt_to_bus(&vp->tx_ring[entry]));
 		if (inl(ioaddr + DownListPtr) == 0) {
 			outl(virt_to_bus(&vp->tx_ring[entry]), ioaddr + DownListPtr);
@@ -1761,7 +1695,7 @@
 		if (status & DMADone) {
 			if (inw(ioaddr + Wn7_MasterStatus) & 0x1000) {
 				outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */
-				DEV_FREE_SKB(vp->tx_skb); /* Release the transfered buffer */
+				dev_kfree_skb(vp->tx_skb); /* Release the transfered buffer */
 				if (inw(ioaddr + TxFree) > 1536) {
 					clear_bit(0, (void*)&dev->tbusy);
 					mark_bh(NET_BH);
@@ -1854,7 +1788,7 @@
 					virt_to_bus(&vp->tx_ring[entry]))
 					break;			/* It still hasn't been processed. */
 				if (vp->tx_skbuff[entry]) {
-					DEV_FREE_SKB(vp->tx_skbuff[entry]);
+					dev_kfree_skb(vp->tx_skbuff[entry]);
 					vp->tx_skbuff[entry] = 0;
 				}
 				/* vp->stats.tx_packets++;  Counted below. */
@@ -1898,14 +1832,6 @@
 
 	} while ((status = inw(ioaddr + EL3_STATUS)) & IntLatch);
 
-	/*
-	 * If we have totally run out to rx skb's due to persistent OOM,
-	 * we can use the Tx interrupt to retry the allocation.  Dirty
-	 * but expedient
-	 */
-	if ((vp->cur_rx - vp->dirty_rx) == RX_RING_SIZE)
-		boomerang_rx(dev);
-
 	if (vortex_debug > 4)
 		printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n",
 			   dev->name, status);
@@ -1980,12 +1906,8 @@
 				printk(KERN_NOTICE "%s: No memory to allocate a sk_buff of "
 					   "size %d.\n", dev->name, pkt_len);
 		}
-		outw(RxDiscard, ioaddr + EL3_CMD);
 		vp->stats.rx_dropped++;
-		/* Wait a limited time to skip this packet. */
-		for (i = 200; i >= 0; i--)
-			if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
-				break;
+		wait_for_completion(dev, RxDiscard);
 	}
 
 	return 0;
@@ -2074,8 +1996,16 @@
 		entry = vp->dirty_rx % RX_RING_SIZE;
 		if (vp->rx_skbuff[entry] == NULL) {
 			skb = dev_alloc_skb(PKT_BUF_SZ);
-			if (skb == NULL)
+			if (skb == NULL) {
+				static unsigned long last_jif;
+				if ((jiffies - last_jif) > 10 * HZ) {
+					printk(KERN_WARNING "%s: memory shortage\n", dev->name);
+					last_jif = jiffies;
+				}
+				if ((vp->cur_rx - vp->dirty_rx) == RX_RING_SIZE)
+					mod_timer(&vp->rx_oom_timer, RUN_AT(HZ * 1));
 				break;			/* Bad news!  */
+			}
 			skb->dev = dev;			/* Mark as being used by this device. */
 			skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
 			vp->rx_ring[entry].addr = cpu_to_le32(virt_to_bus(skb->tail));
@@ -2087,6 +2017,26 @@
 	return 0;
 }
 
+/*
+ * If we've hit a total OOM refilling the Rx ring we poll once a second
+ * for some memory.  Otherwise there is no way to restart the rx process.
+ */
+static void
+rx_oom_timer(unsigned long arg)
+{
+	struct device *dev = (struct device *)arg;
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+
+	spin_lock_irq(&vp->lock);
+	if ((vp->cur_rx - vp->dirty_rx) == RX_RING_SIZE)	/* This test is redundant, but makes me feel good */
+		boomerang_rx(dev);
+	if (vortex_debug > 1) {
+		printk(KERN_DEBUG "%s: rx_oom_timer %s\n", dev->name,
+			((vp->cur_rx - vp->dirty_rx) != RX_RING_SIZE) ? "succeeded" : "retrying");
+	}
+	spin_unlock_irq(&vp->lock);
+}
+
 static int
 vortex_close(struct device *dev)
 {
@@ -2106,6 +2056,7 @@
 	}
 
 	del_timer(&vp->timer);
+	del_timer(&vp->rx_oom_timer);
 
 	/* Turn off statistics ASAP.  We update vp->stats below. */
 	outw(StatsDisable, ioaddr + EL3_CMD);
@@ -2127,10 +2078,7 @@
 		outl(0, ioaddr + UpListPtr);
 		for (i = 0; i < RX_RING_SIZE; i++)
 			if (vp->rx_skbuff[i]) {
-#if LINUX_VERSION_CODE < 0x20100
-				vp->rx_skbuff[i]->free = 1;
-#endif
-				DEV_FREE_SKB(vp->rx_skbuff[i]);
+				dev_kfree_skb(vp->rx_skbuff[i]);
 				vp->rx_skbuff[i] = 0;
 			}
 	}
@@ -2138,11 +2086,13 @@
 		outl(0, ioaddr + DownListPtr);
 		for (i = 0; i < TX_RING_SIZE; i++)
 			if (vp->tx_skbuff[i]) {
-				DEV_FREE_SKB(vp->tx_skbuff[i]);
+				dev_kfree_skb(vp->tx_skbuff[i]);
 				vp->tx_skbuff[i] = 0;
 			}
 	}
 
+	if (vp->enable_wol && (vp->capabilities & CapPwrMgmt))
+		acpi_set_WOL(dev);
 	MOD_DEC_USE_COUNT;
 
 	return 0;
@@ -2219,7 +2169,7 @@
 		retval = 0;
 		break;
 	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
-		if (!suser()) {
+		if (!capable(CAP_NET_ADMIN)) {
 			retval = -EPERM;
 		} else {
 			EL3WINDOW(4);
@@ -2349,22 +2299,66 @@
 	return;
 }
 
+/* ACPI: Advanced Configuration and Power Interface. */
+/* Set Wake-On-LAN mode and put the board into D3 (power-down) state. */
+static void acpi_set_WOL(struct device *dev)
+{
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+
+	/* Power up on: 1==Downloaded Filter, 2==Magic Packets, 4==Link Status. */
+	EL3WINDOW(7);
+	outw(2, ioaddr + 0x0c);
+	/* The RxFilter must accept the WOL frames. */
+	outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD);
+	outw(RxEnable, ioaddr + EL3_CMD);
+	/* Change the power state to D3; RxEnable doesn't take effect. */
+	pcibios_write_config_word(vp->pci_bus, vp->pci_devfn, 0xe0, 0x8103);
+}
+
+/* Change from D3 (sleep) to D0 (active).
+   Problem: The Cyclone forgets all PCI config info during the transition! */
+static void acpi_wake(int bus, int devfn)
+{
+	u32 base0, base1, romaddr;
+	u16 pci_command, pwr_command;
+	u8  pci_latency, pci_cacheline, irq;
+
+	pcibios_read_config_word(bus, devfn, 0xe0, &pwr_command);
+	if ((pwr_command & 3) == 0)
+		return;
+	pcibios_read_config_word( bus, devfn, PCI_COMMAND, &pci_command);
+	pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &base0);
+	pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_1, &base1);
+	pcibios_read_config_dword(bus, devfn, PCI_ROM_ADDRESS, &romaddr);
+	pcibios_read_config_byte( bus, devfn, PCI_LATENCY_TIMER, &pci_latency);
+	pcibios_read_config_byte( bus, devfn, PCI_CACHE_LINE_SIZE, &pci_cacheline);
+	pcibios_read_config_byte( bus, devfn, PCI_INTERRUPT_LINE, &irq);
+
+	pcibios_write_config_word( bus, devfn, 0xe0, 0x0000);
+	pcibios_write_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, base0);
+	pcibios_write_config_dword(bus, devfn, PCI_BASE_ADDRESS_1, base1);
+	pcibios_write_config_dword(bus, devfn, PCI_ROM_ADDRESS, romaddr);
+	pcibios_write_config_byte( bus, devfn, PCI_INTERRUPT_LINE, irq);
+	pcibios_write_config_byte( bus, devfn, PCI_LATENCY_TIMER, pci_latency);
+	pcibios_write_config_byte( bus, devfn, PCI_CACHE_LINE_SIZE, pci_cacheline);
+	pcibios_write_config_word( bus, devfn, PCI_COMMAND, pci_command | 5);
+}
+
 
 #ifdef MODULE
 void cleanup_module(void)
 {
 	struct device *next_dev;
 
-#ifdef CARDBUS
-	unregister_driver(&vortex_ops);
-#endif
-
 	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
 	while (root_vortex_dev) {
 		struct vortex_private *vp=(void *)(root_vortex_dev->priv);
+		int drv_flags = pci_tbl[vp->chip_id].drv_flags;
 		next_dev = vp->next_module;
 		unregister_netdev(root_vortex_dev);
-		outw(TotalReset, root_vortex_dev->base_addr + EL3_CMD);
+		outw((drv_flags & EEPROM_NORESET) ? (TotalReset|0x10) : TotalReset,
+				root_vortex_dev->base_addr + EL3_CMD);
 		release_region(root_vortex_dev->base_addr,
 					   pci_tbl[vp->chip_id].io_size);
 		kfree(root_vortex_dev);
@@ -2377,9 +2371,6 @@
 
 /*
  * Local variables:
- *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c"
- *  cardbus-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c -o 3c575_cb.o -I/usr/src/pcmcia-cs-3.0.5/include/"
  *  c-indent-level: 4
  *  c-basic-offset: 4
  *  tab-width: 4
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/8139too.c linux.19p18/drivers/net/8139too.c
--- linux.vanilla/drivers/net/8139too.c	Mon Dec 11 22:12:47 2000
+++ linux.19p18/drivers/net/8139too.c	Mon Feb 19 18:28:56 2001
@@ -5,12 +5,12 @@
  	Maintained by Jeff Garzik <jgarzik@mandrakesoft.com>
  
  	Much code comes from Donald Becker's rtl8139.c driver,
- 	versions 1.11 and older.  This driver was originally based
- 	on rtl8139.c version 1.07.  Header of rtl8139.c version 1.11:
+ 	versions 1.13 and older.  This driver was originally based
+ 	on rtl8139.c version 1.07.  Header of rtl8139.c version 1.13:
  
  	-----<snip>-----
  
-         	Written 1997-2000 by Donald Becker.
+         	Written 1997-2001 by Donald Becker.
  		This software may be used and distributed according to the
  		terms of the GNU General Public License (GPL), incorporated
  		herein by reference.  Drivers based on or derived from this
@@ -45,7 +45,7 @@
 		Tigran Aivazian - bug fixes, skbuff free cleanup
 
 		Martin Mares - suggestions for PCI cleanup
-		
+
 		David S. Miller - PCI DMA and softnet updates
 
 		Ernst Gill - fixes ported from BSD driver
@@ -54,12 +54,12 @@
 			posted MMIO write bugginess
 
 		Gerard Sharp - bug fix, testing and feedback
-		
+
 		David Ford - Rx ring wrap fix
-		
+
 		Dan DeMaggio - swapped RTL8139 cards with me, and allowed me
 		to find and fix a crucial bug on older chipsets.
-		
+
 		Donald Becker/Chris Butterworth/Marcus Westergren -
 		Noticed various Rx packet size-related buglets.
 
@@ -70,6 +70,13 @@
 		Martin Dennett - incredibly helpful insight on undocumented
 		features of the 8139 chips
 
+		Jean-Jacques Michel - bug fix
+		
+		Tobias Ringström - Rx interrupt status checking suggestion
+
+		Andrew Morton - Clear blocked signals, avoid
+		buffer overrun setting current->comm.
+
 	Submitting bug reports:
 
 		"rtl8139-diag -mmmaaavvveefN" output
@@ -130,6 +137,7 @@
 
 */
 
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
@@ -137,19 +145,22 @@
 #include <linux/ioport.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
 #include <linux/delay.h>
 #include <asm/io.h>
 
 
-#define RTL8139_VERSION "0.9.10-2.2"
-#define RTL8139_MODULE_NAME "8139too"
-#define RTL8139_DRIVER_NAME   RTL8139_MODULE_NAME " FastEthernet driver " RTL8139_VERSION
+#define RTL8139_VERSION "0.9.14-2.2"
+#define MODNAME "8139too"
+#define RTL8139_DRIVER_NAME   MODNAME " FastEthernet driver " RTL8139_VERSION
 #define RTL8139_AUTHOR "Jeff Garzik <jgarzik@mandrakesoft.com>"
-#define PFX RTL8139_MODULE_NAME ": "
+#define PFX MODNAME ": "
 
 
-/* define to 1 to enable PIO instead of MMIO */
-#undef USE_IO_OPS
+/* enable PIO instead of MMIO, if CONFIG_8139TOO_PIO is selected */
+#ifdef CONFIG_8139TOO_PIO
+#define USE_IO_OPS 1
+#endif
 
 /* define to 1 to enable copious debugging info */
 #undef RTL8139_DEBUG
@@ -215,7 +226,7 @@
 #define PCI_USES_MEM		2
 #define PCI_USES_MASTER 	4
 
-static inline unsigned int pci_calc_resource_flags(unsigned int flags)
+static inline unsigned int rtl8139_pci_calc_resource_flags(unsigned int flags)
 {
 	if (flags & PCI_BASE_ADDRESS_SPACE_IO)
 		return IORESOURCE_IO;
@@ -256,27 +267,28 @@
 			sz = ~(sz & PCI_BASE_ADDRESS_IO_MASK) & 0xffff;
 		}
 		res->end = res->start + (unsigned long) sz;
-		res->flags |= (l & 0xf) | pci_calc_resource_flags(l);
+		res->flags |= (l & 0xf) | rtl8139_pci_calc_resource_flags(l);
 	}
 }
 
-#define pci_resource_start(dev_priv,bar)	((dev_priv)->rtl8139_pci_resource[(bar)].start)
-#define pci_resource_end(dev_priv,bar)	((dev_priv)->rtl8139_pci_resource[(bar)].end)
-#define pci_resource_flags(dev_priv,bar)	((dev_priv)->rtl8139_pci_resource[(bar)].flags)
-#define pci_resource_len(dev_priv,bar) \
-	((pci_resource_start((dev_priv),(bar)) == 0 &&	\
-	  pci_resource_end((dev_priv),(bar)) ==		\
-	  pci_resource_start((dev_priv),(bar))) ? 0 :	\
+#define rtl8139_pci_resource_start(dev_priv,bar)	((dev_priv)->rtl8139_pci_resource[(bar)].start)
+#define rtl8139_pci_resource_end(dev_priv,bar)	((dev_priv)->rtl8139_pci_resource[(bar)].end)
+#define rtl8139_pci_resource_flags(dev_priv,bar)	((dev_priv)->rtl8139_pci_resource[(bar)].flags)
+#define rtl8139_pci_resource_len(dev_priv,bar) \
+	((rtl8139_pci_resource_start((dev_priv),(bar)) == 0 &&	\
+	  rtl8139_pci_resource_end((dev_priv),(bar)) ==		\
+	  rtl8139_pci_resource_start((dev_priv),(bar))) ? 0 :	\
 	  						\
-	 (pci_resource_end((dev_priv),(bar)) -		\
-	  pci_resource_start((dev_priv),(bar)) + 1))
-
-#define arraysize(x)            (sizeof(x)/sizeof(*(x)))
+	 (rtl8139_pci_resource_end((dev_priv),(bar)) -		\
+	  rtl8139_pci_resource_start((dev_priv),(bar)) + 1))
 
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
 
 /* A few user-configurable values. */
 /* media options */
-static int media[] = {-1, -1, -1, -1, -1, -1, -1, -1};
+#define MAX_UNITS 8
+static int media[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
 
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
 static int max_interrupt_work = 20;
@@ -295,8 +307,11 @@
 /* Number of Tx descriptor registers. */
 #define NUM_TX_DESC	4
 
+/* max supported ethernet frame size -- must be at least (dev->mtu+14+4).*/
+#define MAX_ETH_FRAME_SIZE	1536
+
 /* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
-#define TX_BUF_SIZE	1536
+#define TX_BUF_SIZE	MAX_ETH_FRAME_SIZE
 #define TX_BUF_TOT_LEN	(TX_BUF_SIZE * NUM_TX_DESC)
 
 /* PCI Tuning Parameters
@@ -315,6 +330,7 @@
 
 
 enum {
+	HAS_MII_XCVR = 0x010000,
 	HAS_CHIP_XCVR = 0x020000,
 	HAS_LNK_CHNG = 0x040000,
 };
@@ -322,26 +338,34 @@
 #define RTL_MIN_IO_SIZE 0x80
 #define RTL8139B_IO_SIZE 256
 
+#define RTL8129_CAPS	HAS_MII_XCVR
 #define RTL8139_CAPS	HAS_CHIP_XCVR|HAS_LNK_CHNG
 
 typedef enum {
 	RTL8139 = 0,
 	RTL8139_CB,
 	SMC1211TX,
+	/*MPX5030,*/
 	DELTA8139,
 	ADDTRON8139,
+	DFE538TX,
+	RTL8129,
 } board_t;
 
 
 /* indexed by board_t, above */
 static struct {
 	const char *name;
+	u32 hw_flags;
 } board_info[] = {
-	{ "RealTek RTL8139 Fast Ethernet" },
-	{ "RealTek RTL8139B PCI/CardBus" },
-	{ "SMC1211TX EZCard 10/100 (RealTek RTL8139)" },
-	{ "Delta Electronics 8139 10/100BaseTX" },
-	{ "Addtron Technolgy 8139 10/100BaseTX" },
+	{ "RealTek RTL8139 Fast Ethernet", RTL8139_CAPS },
+	{ "RealTek RTL8139B PCI/CardBus", RTL8139_CAPS },
+	{ "SMC1211TX EZCard 10/100 (RealTek RTL8139)", RTL8139_CAPS },
+/*	{ MPX5030, "Accton MPX5030 (RealTek RTL8139)", RTL8139_CAPS },*/
+	{ "Delta Electronics 8139 10/100BaseTX", RTL8139_CAPS },
+	{ "Addtron Technolgy 8139 10/100BaseTX", RTL8139_CAPS },
+	{ "D-Link DFE-538TX (RealTek RTL8139)", RTL8139_CAPS },
+	{ "RealTek RTL8129", RTL8129_CAPS },
 };
 
 struct pci_device_id {
@@ -353,8 +377,11 @@
 	{0x10ec, 0x8139, RTL8139 },
 	{0x10ec, 0x8138, RTL8139_CB },
 	{0x1113, 0x1211, SMC1211TX },
+/*	{0x1113, 0x1211, MPX5030 },*/
 	{0x1500, 0x1360, DELTA8139 },
 	{0x4033, 0x1360, ADDTRON8139 },
+	{0x1186, 0x1300, DFE538TX },
+	{0x10ec, 0x8129, RTL8129 },
 	{0,}
 };
 
@@ -561,17 +588,17 @@
 	  0x40,
 	  0xf0fe0040, /* XXX copied from RTL8139A, verify */
 	},
-	
+
 	{ "RTL-8139 rev K",
 	  0x60,
 	  0xf0fe0040,
 	},
-	
+
 	{ "RTL-8139A",
 	  0x70,
 	  0xf0fe0040,
 	},
-	
+
 	{ "RTL-8139B",
 	  0x78,
 	  0xf0fc0040
@@ -591,18 +618,16 @@
 
 
 struct rtl8139_private {
-	board_t board;
 	void *mmio_addr;
 	int drv_flags;
 	struct pci_dev *pci_dev;
 	struct resource rtl8139_pci_resource[4];
 	struct net_device_stats stats;
-	struct timer_list timer;	/* Media selection timer. */
 	unsigned char *rx_ring;
 	unsigned int cur_rx;	/* Index into the Rx buffer of next Rx pkt. */
 	unsigned int tx_flag;
-	atomic_t cur_tx;
-	atomic_t dirty_tx;
+	unsigned long cur_tx;
+	unsigned long dirty_tx;
 	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
 	struct ring_info tx_info[NUM_TX_DESC];
 	unsigned char *tx_buf[NUM_TX_DESC];	/* Tx bounce buffers */
@@ -610,6 +635,7 @@
 	dma_addr_t rx_ring_dma;
 	dma_addr_t tx_bufs_dma;
 	char phys[4];		/* MII device addresses. */
+	u16 advertising;					/* NWay media advertisement */
 	char twistie, twist_row, twist_col;	/* Twister tune state. */
 	unsigned int full_duplex:1;	/* Full-duplex operation requested. */
 	unsigned int duplex_lock:1;
@@ -619,6 +645,9 @@
 	unsigned int mediasense:1;	/* Media sensing in progress. */
 	spinlock_t lock;
 	chip_t chipset;
+	pid_t thr_pid;
+	wait_queue_head_t thr_wait;
+	struct semaphore thr_exited;
 };
 
 
@@ -628,7 +657,7 @@
 static int mdio_read (struct device *dev, int phy_id, int location);
 static void mdio_write (struct device *dev, int phy_id, int location,
 			int val);
-static void rtl8139_timer (unsigned long data);
+static int rtl8139_thread (void *data);
 static void rtl8139_tx_timeout (struct device *dev);
 static void rtl8139_init_ring (struct device *dev);
 static int rtl8139_start_xmit (struct sk_buff *skb,
@@ -642,12 +671,11 @@
 static void rtl8139_set_rx_mode (struct device *dev);
 static void rtl8139_hw_start (struct device *dev);
 
-
 #ifdef USE_IO_OPS
 
 #define RTL_R8(reg)		inb (((unsigned long)ioaddr) + (reg))
 #define RTL_R16(reg)		inw (((unsigned long)ioaddr) + (reg))
-#define RTL_R32(reg)		inl (((unsigned long)ioaddr) + (reg))
+#define RTL_R32(reg)		((unsigned long) inl (((unsigned long)ioaddr) + (reg)))
 #define RTL_W8(reg, val8)	outb ((val8), ((unsigned long)ioaddr) + (reg))
 #define RTL_W16(reg, val16)	outw ((val16), ((unsigned long)ioaddr) + (reg))
 #define RTL_W32(reg, val32)	outl ((val32), ((unsigned long)ioaddr) + (reg))
@@ -695,12 +723,12 @@
 /* read MMIO register */
 #define RTL_R8(reg)		readb (ioaddr + (reg))
 #define RTL_R16(reg)		readw (ioaddr + (reg))
-#define RTL_R32(reg)		readl (ioaddr + (reg))
+#define RTL_R32(reg)		((unsigned long) readl (ioaddr + (reg)))
 
 #endif /* USE_IO_OPS */
 
 
-static const u16 rtl8139_intr_mask = 
+static const u16 rtl8139_intr_mask =
 	PCIErr | PCSTimeout | RxUnderrun | RxOverflow | RxFIFOOver |
 	TxErr | TxOK | RxErr | RxOK;
 
@@ -742,15 +770,15 @@
 
 	rtl8139_read_pci_resources(pdev, &tp->rtl8139_pci_resource[0]);
 
-	pio_start = pci_resource_start (tp, 0);
-	pio_end = pci_resource_end (tp, 0);
-	pio_flags = pci_resource_flags (tp, 0);
-	pio_len = pci_resource_len (tp, 0);
-
-	mmio_start = pci_resource_start (tp, 1);
-	mmio_end = pci_resource_end (tp, 1);
-	mmio_flags = pci_resource_flags (tp, 1);
-	mmio_len = pci_resource_len (tp, 1);
+	pio_start = rtl8139_pci_resource_start (tp, 0);
+	pio_end = rtl8139_pci_resource_end (tp, 0);
+	pio_flags = rtl8139_pci_resource_flags (tp, 0);
+	pio_len = rtl8139_pci_resource_len (tp, 0);
+
+	mmio_start = rtl8139_pci_resource_start (tp, 1);
+	mmio_end = rtl8139_pci_resource_end (tp, 1);
+	mmio_flags = rtl8139_pci_resource_flags (tp, 1);
+	mmio_len = rtl8139_pci_resource_len (tp, 1);
 
 	/* set this immediately, we need to know before
 	 * we talk to the chip directly */
@@ -765,17 +793,16 @@
 		rc = -ENODEV;
 		goto err_out;
 	}
-	
+
 	/* make sure PCI base addr 1 is MMIO */
 	if (!(mmio_flags & IORESOURCE_MEM)) {
 		printk (KERN_ERR PFX "region #1 not an MMIO resource, aborting\n");
 		rc = -ENODEV;
 		goto err_out;
 	}
-	
+
 	/* check for weird/broken PCI region reporting */
-	if ((pio_len != mmio_len) ||
-	    (pio_len < RTL_MIN_IO_SIZE) ||
+	if ((pio_len < RTL_MIN_IO_SIZE) ||
 	    (mmio_len < RTL_MIN_IO_SIZE)) {
 		printk (KERN_ERR PFX "Invalid PCI region size(s), aborting\n");
 		rc = -ENODEV;
@@ -831,14 +858,6 @@
 		RTL_W8 (Config1, 0);
 	}
 
-#ifndef USE_IO_OPS
-	/* sanity checks -- ensure PIO and MMIO registers agree */
-	assert (inb (pio_start+Config0) == readb (ioaddr+Config0));
-	assert (inb (pio_start+Config1) == readb (ioaddr+Config1));
-	assert (inb (pio_start+TxConfig) == readb (ioaddr+TxConfig));
-	assert (inb (pio_start+RxConfig) == readb (ioaddr+RxConfig));
-#endif /* !USE_IO_OPS */
-	
 	/* make sure chip thinks PIO and MMIO are enabled */
 	tmp8 = RTL_R8 (Config1);
 	if ((tmp8 & Cfg1_PIO) == 0) {
@@ -851,10 +870,10 @@
 		rc = -EIO;
 		goto err_out_iounmap;
 	}
-	
+
 	/* identify chip attached to board */
 	tmp = RTL_R8 (ChipVersion);
-	for (i = arraysize (rtl_chip_info) - 1; i >= 0; i--)
+	for (i = ARRAY_SIZE (rtl_chip_info) - 1; i >= 0; i--)
 		if (tmp == rtl_chip_info[i].version) {
 			tp->chipset = i;
 			goto match;
@@ -863,7 +882,7 @@
 	/* if unknown chip, assume array element #0, original RTL-8139 in this case */
 	printk (KERN_DEBUG PFX "PCI device %08lX: unknown chip version, assuming RTL-8139\n",
 		(unsigned long) pdev);
-	printk (KERN_DEBUG PFX "PCI device %08lX: TxConfig = 0x%x\n", (unsigned long) pdev, RTL_R32 (TxConfig));
+	printk (KERN_DEBUG PFX "PCI device %08lX: TxConfig = 0x%lx\n", (unsigned long) pdev, RTL_R32 (TxConfig));
 	tp->chipset = 0;
 
 match:
@@ -871,11 +890,11 @@
 		tmp,
 		tp->chipset,
 		rtl_chip_info[tp->chipset].name);
-	
+
 	DPRINTK ("EXIT, returning 0\n");
 	*ioaddr_out = ioaddr;
 	*dev_out = dev;
-	return 0;	
+	return 0;
 
 err_out_iounmap:
 	assert (ioaddr > 0);
@@ -901,7 +920,7 @@
 	u8 tmp;
 
 	DPRINTK ("ENTER\n");
-	
+
 	assert (pdev != NULL);
 	assert (ent != NULL);
 
@@ -912,9 +931,9 @@
 		DPRINTK ("EXIT, returning %d\n", i);
 		return i;
 	}
-	
+
 	tp = dev->priv;
-	
+
 	assert (ioaddr != NULL);
 	assert (dev != NULL);
 	assert (tp != NULL);
@@ -939,14 +958,12 @@
 	tp = dev->priv;
 
 	/* note: tp->chipset set in rtl8139_init_board */
-	tp->drv_flags = PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
-			PCI_COMMAND_MASTER | RTL8139_CAPS;
+	tp->drv_flags = board_info[ent->board].hw_flags;
 	tp->pci_dev = pdev;
-	tp->board = ent->board;
 	tp->mmio_addr = ioaddr;
-	tp->lock = SPIN_LOCK_UNLOCKED;
-
-	tp->phys[0] = 32;
+	spin_lock_init (&tp->lock);
+	init_waitqueue_head (&tp->thr_wait);
+	init_MUTEX_LOCKED (&tp->thr_exited);
 
 	if (rtl8139_device_count == 0) {
 		printk (KERN_INFO "%s: " RTL8139_DRIVER_NAME " " RTL8139_AUTHOR "\n", dev->name);
@@ -964,6 +981,30 @@
 		dev->dev_addr[2], dev->dev_addr[3],
 		dev->dev_addr[4], dev->dev_addr[5]);
 
+	/* Find the connected MII xcvrs.
+	   Doing this in open() would allow detecting external xcvrs later, but
+	   takes too much time. */
+	if (tp->drv_flags & HAS_MII_XCVR) {
+		int phy, phy_idx = 0;
+		for (phy = 0; phy < 32 && phy_idx < sizeof(tp->phys); phy++) {
+			int mii_status = mdio_read(dev, phy, 1);
+			if (mii_status != 0xffff  &&  mii_status != 0x0000) {
+				tp->phys[phy_idx++] = phy;
+				tp->advertising = mdio_read(dev, phy, 4);
+				printk(KERN_INFO "%s: MII transceiver %d status 0x%4.4x "
+					   "advertising %4.4x.\n",
+					   dev->name, phy, mii_status, tp->advertising);
+			}
+		}
+		if (phy_idx == 0) {
+			printk(KERN_INFO "%s: No MII transceivers found!  Assuming SYM "
+				   "transceiver.\n",
+				   dev->name);
+			tp->phys[0] = 32;
+		}
+	} else
+		tp->phys[0] = 32;
+
 	/* Put the chip into low-power mode. */
 	RTL_W8_F (Cfg9346, Cfg9346_Unlock);
 
@@ -974,21 +1015,29 @@
 	RTL_W8_F (HltClk, 'H');	/* 'R' would leave the clock running. */
 
 	/* The lower four bits are the media type. */
-	option = (board_idx > 7) ? 0 : media[board_idx];
+	option = (board_idx >= MAX_UNITS) ? 0 : media[board_idx];
 	if (option > 0) {
-		tp->full_duplex = (option & 0x200) ? 1 : 0;
-		tp->default_port = option & 15;
+		tp->full_duplex = (option & 0x210) ? 1 : 0;
+		tp->default_port = option & 0xFF;
 		if (tp->default_port)
 			tp->medialock = 1;
 	}
-
+	if (board_idx < MAX_UNITS  &&  full_duplex[board_idx] > 0)
+		tp->full_duplex = full_duplex[board_idx];
 	if (tp->full_duplex) {
-		printk (KERN_INFO
-			"%s: Media type forced to Full Duplex.\n",
-			dev->name);
-		mdio_write (dev, tp->phys[0], 4, 0x141);
+		printk (KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name);
+		/* Changing the MII-advertised media because might prevent
+		   re-connection. */
 		tp->duplex_lock = 1;
 	}
+	if (tp->default_port) {
+		printk(KERN_INFO "  Forcing %dMbs %s-duplex operation.\n",
+			   (option & 0x20 ? 100 : 10),
+			   (option & 0x10 ? "full" : "half"));
+		mdio_write(dev, tp->phys[0], 0,
+				   ((option & 0x20) ? 0x2000 : 0) | 	/* 100mbps? */
+				   ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */
+	}
 
 	rtl8139_device_tab[rtl8139_device_count++] = dev;
 	
@@ -1017,8 +1066,8 @@
 	iounmap (np->mmio_addr);
 #endif /* !USE_IO_OPS */
 
-	release_region (pci_resource_start (np, 0),
-			pci_resource_len (np, 0));
+	release_region (rtl8139_pci_resource_start (np, 0),
+			rtl8139_pci_resource_len (np, 0));
 #ifndef RTL8139_NDEBUG
 	/* poison memory before freeing */
 	memset (dev, 0xBC,
@@ -1108,7 +1157,7 @@
 #define MDIO_WRITE0 (MDIO_DIR)
 #define MDIO_WRITE1 (MDIO_DIR | MDIO_DATA_OUT)
 
-#define mdio_delay()	readb(mdio_addr)
+#define mdio_delay(mdio_addr)	readb(mdio_addr)
 
 
 static char mii_2_8139_map[8] = {
@@ -1132,9 +1181,9 @@
 
 	for (i = 32; i >= 0; i--) {
 		writeb (MDIO_WRITE1, mdio_addr);
-		mdio_delay ();
+		mdio_delay (mdio_addr);
 		writeb (MDIO_WRITE1 | MDIO_CLK, mdio_addr);
-		mdio_delay ();
+		mdio_delay (mdio_addr);
 	}
 
 	DPRINTK ("EXIT\n");
@@ -1143,7 +1192,7 @@
 
 static int mdio_read (struct device *dev, int phy_id, int location)
 {
-	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+	struct rtl8139_private *tp = dev->priv;
 	void *mdio_addr = tp->mmio_addr + Config4;
 	int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
 	int retval = 0;
@@ -1162,20 +1211,18 @@
 		int dataval = (mii_cmd & (1 << i)) ? MDIO_DATA_OUT : 0;
 
 		writeb (MDIO_DIR | dataval, mdio_addr);
-		mdio_delay ();
+		mdio_delay (mdio_addr);
 		writeb (MDIO_DIR | dataval | MDIO_CLK, mdio_addr);
-		mdio_delay ();
+		mdio_delay (mdio_addr);
 	}
 
 	/* Read the two transition, 16 data, and wire-idle bits. */
 	for (i = 19; i > 0; i--) {
 		writeb (0, mdio_addr);
-		mdio_delay ();
-		retval =
-		    (retval << 1) | ((readb (mdio_addr) & MDIO_DATA_IN) ? 1
-				     : 0);
+		mdio_delay (mdio_addr);
+		retval = (retval << 1) | ((readb (mdio_addr) & MDIO_DATA_IN) ? 1 : 0);
 		writeb (MDIO_CLK, mdio_addr);
-		mdio_delay ();
+		mdio_delay (mdio_addr);
 	}
 
 	DPRINTK ("EXIT, returning %d\n", (retval >> 1) & 0xffff);
@@ -1186,21 +1233,21 @@
 static void mdio_write (struct device *dev, int phy_id, int location,
 			int value)
 {
-	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+	struct rtl8139_private *tp = dev->priv;
 	void *mdio_addr = tp->mmio_addr + Config4;
-	int mii_cmd =
-	    (0x5002 << 16) | (phy_id << 23) | (location << 18) | value;
+	int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location << 18) | value;
 	int i;
 
 	DPRINTK ("ENTER\n");
 
 	if (phy_id > 31) {	/* Really a 8139.  Use internal registers. */
-		if (location < 8 && mii_2_8139_map[location]) {
-			writew (value,
-				tp->mmio_addr + mii_2_8139_map[location]);
-			readw (tp->mmio_addr + mii_2_8139_map[location]);
-		}
-		DPRINTK ("EXIT after directly using 8139 internal regs\n");
+		void *ioaddr = tp->mmio_addr;
+		if (location == 0) {
+			RTL_W8_F (Cfg9346, Cfg9346_Unlock);
+			RTL_W16_F (BasicModeCtrl, value);
+			RTL_W8_F (Cfg9346, Cfg9346_Lock);
+		} else if (location < 8 && mii_2_8139_map[location])
+			RTL_W16_F (mii_2_8139_map[location], value);
 		return;
 	}
 	mdio_sync (mdio_addr);
@@ -1210,26 +1257,25 @@
 		int dataval =
 		    (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;
 		writeb (dataval, mdio_addr);
-		mdio_delay ();
+		mdio_delay (mdio_addr);
 		writeb (dataval | MDIO_CLK, mdio_addr);
-		mdio_delay ();
+		mdio_delay (mdio_addr);
 	}
 
 	/* Clear out extra bits. */
 	for (i = 2; i > 0; i--) {
 		writeb (0, mdio_addr);
-		mdio_delay ();
+		mdio_delay (mdio_addr);
 		writeb (MDIO_CLK, mdio_addr);
-		mdio_delay ();
+		mdio_delay (mdio_addr);
 	}
-
-	DPRINTK ("EXIT\n");
+	return;
 }
 
 
 static int rtl8139_open (struct device *dev)
 {
-	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+	struct rtl8139_private *tp = dev->priv;
 	int retval;
 #ifdef RTL8139_DEBUG
 	void *ioaddr = tp->mmio_addr;
@@ -1260,11 +1306,12 @@
 		DPRINTK ("EXIT, returning -ENOMEM\n");
 		MOD_DEC_USE_COUNT;
 		return -ENOMEM;
-		
+
 	}
-	
+
 	tp->full_duplex = tp->duplex_lock;
 	tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000;
+	tp->twistie = 1;
 
 	rtl8139_init_ring (dev);
 	rtl8139_hw_start (dev);
@@ -1275,13 +1322,10 @@
 			dev->irq, RTL_R8 (MediaStatus),
 			tp->full_duplex ? "full" : "half");
 
-	/* Set the timer to switch to check for link beat and perhaps switch
-	   to an alternate media type. */
-	init_timer (&tp->timer);
-	tp->timer.expires = jiffies + 3 * HZ;
-	tp->timer.data = (unsigned long) dev;
-	tp->timer.function = &rtl8139_timer;
-	add_timer (&tp->timer);
+	tp->thr_pid = kernel_thread (rtl8139_thread, dev, CLONE_FS | CLONE_FILES);
+	if (tp->thr_pid < 0)
+		printk (KERN_WARNING "%s: unable to start kernel thread\n",
+			dev->name);
 
 	DPRINTK ("EXIT, returning 0\n");
 	return 0;
@@ -1291,13 +1335,13 @@
 /* Start the hardware at open or resume. */
 static void rtl8139_hw_start (struct device *dev)
 {
-	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+	struct rtl8139_private *tp = dev->priv;
 	void *ioaddr = tp->mmio_addr;
 	u32 i;
 	u8 tmp;
 
 	DPRINTK ("ENTER\n");
-	
+
 	/* Soft reset the chip. */
 	RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear) | CmdReset);
 	udelay (100);
@@ -1307,6 +1351,8 @@
 		if ((RTL_R8 (ChipCmd) & CmdReset) == 0)
 			break;
 
+	/* unlock Config[01234] and BMCR register writes */
+	RTL_W8_F (Cfg9346, Cfg9346_Unlock);
 	/* Restore our idea of the MAC address. */
 	RTL_W32_F (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0)));
 	RTL_W32_F (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4)));
@@ -1322,12 +1368,23 @@
 	/* Check this value: the documentation for IFG contradicts ifself. */
 	RTL_W32 (TxConfig, (TX_DMA_BURST << TxDMAShift));
 
-	/* unlock Config[01234] and BMCR register writes */
-	RTL_W8_F (Cfg9346, Cfg9346_Unlock);
-	udelay (10);
-
 	tp->cur_rx = 0;
 
+	/* This is check_duplex() */
+	if (tp->phys[0] >= 0  ||  (tp->drv_flags & HAS_MII_XCVR)) {
+		u16 mii_reg5 = mdio_read(dev, tp->phys[0], 5);
+		if (mii_reg5 == 0xffff)
+			;					/* Not there */
+		else if ((mii_reg5 & 0x0100) == 0x0100
+				 || (mii_reg5 & 0x00C0) == 0x0040)
+			tp->full_duplex = 1;
+		printk(KERN_INFO"%s: Setting %s%s-duplex based on"
+			   " auto-negotiated partner ability %4.4x.\n", dev->name,
+			   mii_reg5 == 0 ? "" :
+			   (mii_reg5 & 0x0180) ? "100Mbps " : "10Mbps ",
+			   tp->full_duplex ? "full" : "half", mii_reg5);
+	}
+
 	if (tp->chipset >= CH_8139A) {
 		tmp = RTL_R8 (Config1) & Config1Clear;
 		tmp |= Cfg1_Driver_Load;
@@ -1341,9 +1398,9 @@
 	if (tp->chipset >= CH_8139B) {
 		tmp = RTL_R8 (Config4) & ~(1<<2);
 		/* chip will clear Rx FIFO overflow automatically */
-		tmp |= (1<<7);  
+		tmp |= (1<<7);
 		RTL_W8 (Config4, tmp);
-	
+
 		/* disable magic packet scanning, which is enabled
 		 * when PM is enabled above (Config1) */
 		RTL_W8 (Config3, RTL_R8 (Config3) & ~(1<<5));
@@ -1383,14 +1440,14 @@
 /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
 static void rtl8139_init_ring (struct device *dev)
 {
-	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+	struct rtl8139_private *tp = dev->priv;
 	int i;
 
 	DPRINTK ("ENTER\n");
 
 	tp->cur_rx = 0;
-	atomic_set (&tp->cur_tx, 0);
-	atomic_set (&tp->dirty_tx, 0);
+	tp->cur_tx = 0;
+	tp->dirty_tx = 0;
 
 	for (i = 0; i < NUM_TX_DESC; i++) {
 		tp->tx_info[i].skb = NULL;
@@ -1401,7 +1458,10 @@
 }
 
 
-#ifndef RTL_TUNE_TWISTER
+/* This must be global for CONFIG_8139TOO_TUNE_TWISTER case */
+static int next_tick = 3 * HZ;
+
+#ifndef CONFIG_8139TOO_TUNE_TWISTER
 static inline void rtl8139_tune_twister (struct device *dev,
 				  struct rtl8139_private *tp) {}
 #else
@@ -1409,6 +1469,7 @@
 				  struct rtl8139_private *tp)
 {
 	int linkcase;
+	void *ioaddr = tp->mmio_addr;
 
 	DPRINTK ("ENTER\n");
 
@@ -1492,15 +1553,13 @@
 
 	DPRINTK ("EXIT\n");
 }
-#endif /* RTL_TUNE_TWISTER */
+#endif /* CONFIG_8139TOO_TUNE_TWISTER */
 
 
-static void rtl8139_timer (unsigned long data)
+static inline void rtl8139_thread_iter (struct device *dev,
+					struct rtl8139_private *tp,
+					void *ioaddr)
 {
-	struct device *dev = (struct device *) data;
-	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
-	void *ioaddr = tp->mmio_addr;
-	int next_tick = 60 * HZ;
 	int mii_reg5;
 
 	mii_reg5 = mdio_read (dev, tp->phys[0], 5);
@@ -1521,30 +1580,82 @@
 		}
 	}
 
+	next_tick = HZ * 60;
+
 	rtl8139_tune_twister (dev, tp);
 
 	DPRINTK ("%s: Media selection tick, Link partner %4.4x.\n",
 		 dev->name, RTL_R16 (NWayLPAR));
 	DPRINTK ("%s:  Other registers are IntMask %4.4x IntStatus %4.4x"
-		 " RxStatus %4.4x.\n", dev->name,
+		 " RxStatus %4.4lx.\n", dev->name,
 		 RTL_R16 (IntrMask),
 		 RTL_R16 (IntrStatus),
 		 RTL_R32 (RxEarlyStatus));
 	DPRINTK ("%s:  Chip config %2.2x %2.2x.\n",
 		 dev->name, RTL_R8 (Config0),
 		 RTL_R8 (Config1));
+}
+
 
-	tp->timer.expires = jiffies + next_tick;
-	add_timer (&tp->timer);
+static int rtl8139_thread (void *data)
+{
+	struct device *dev = (struct device *) data;
+	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+	unsigned long timeout;
+
+	daemonize ();
+	spin_lock_irq(&current->sigmask_lock);
+	sigemptyset(&current->blocked);
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+
+	strncpy (current->comm, dev->name, sizeof(current->comm) - 1);
+	current->comm[sizeof(current->comm) - 1] = '\0';
+
+	while (1) {
+		timeout = next_tick;
+		do {
+			timeout = interruptible_sleep_on_timeout (&tp->thr_wait, timeout);
+		} while (!signal_pending (current) && (timeout > 0));
+
+		if (signal_pending (current))
+			break;
+
+		rtnl_lock ();
+		rtl8139_thread_iter (dev, tp, tp->mmio_addr);
+		rtnl_unlock ();
+	}
+
+	up (&tp->thr_exited);
+	return 0;
+}
+
+
+static void rtl8139_tx_clear (struct rtl8139_private *tp)
+{
+	int i;
+
+	tp->cur_tx = 0;
+	tp->dirty_tx = 0;
+
+	/* Dump the unsent Tx packets. */
+	for (i = 0; i < NUM_TX_DESC; i++) {
+		struct ring_info *rp = &tp->tx_info[i];
+		if (rp->skb) {
+			dev_kfree_skb (rp->skb);
+			rp->skb = NULL;
+			tp->stats.tx_dropped++;
+		}
+	}
 }
 
 
 static void rtl8139_tx_timeout (struct device *dev)
 {
-	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+	struct rtl8139_private *tp = dev->priv;
 	void *ioaddr = tp->mmio_addr;
 	int i;
-	unsigned long flags;
+	u8 tmp8;
 
 	DPRINTK ("%s: Transmit timeout, status %2.2x %4.4x "
 		 "media %2.2x.\n", dev->name,
@@ -1552,46 +1663,36 @@
 		 RTL_R16 (IntrStatus),
 		 RTL_R8 (MediaStatus));
 
+	/* disable Tx ASAP, if not already */
+	tmp8 = RTL_R8 (ChipCmd);
+	if (tmp8 & CmdTxEnb)
+		RTL_W8 (ChipCmd, tmp8 & ~CmdTxEnb);
+
 	/* Disable interrupts by clearing the interrupt mask. */
 	RTL_W16 (IntrMask, 0x0000);
 
 	/* Emit info to figure out what went wrong. */
-        printk (KERN_DEBUG "%s: Tx queue start entry %d  dirty entry %d.\n",
-		dev->name, atomic_read (&tp->cur_tx),
-		atomic_read (&tp->dirty_tx));
+        printk (KERN_DEBUG "%s: Tx queue start entry %ld  dirty entry %ld.\n",
+		dev->name, tp->cur_tx, tp->dirty_tx);
 	for (i = 0; i < NUM_TX_DESC; i++)
-		printk (KERN_DEBUG "%s:  Tx descriptor %d is %8.8x.%s\n",
+		printk (KERN_DEBUG "%s:  Tx descriptor %d is %8.8lx.%s\n",
 			dev->name, i, RTL_R32 (TxStatus0 + (i * 4)),
-			i == atomic_read (&tp->dirty_tx) % NUM_TX_DESC ?
+			i == tp->dirty_tx % NUM_TX_DESC ?
 				" (queue head)" : "");
 
-	spin_lock_irqsave (&tp->lock, flags);
-
 	/* Stop a shared interrupt from scavenging while we are. */
-	atomic_set (&tp->cur_tx, 0);
-	atomic_set (&tp->dirty_tx, 0);
-
-	/* Dump the unsent Tx packets. */
-	for (i = 0; i < NUM_TX_DESC; i++) {
-		struct ring_info *rp = &tp->tx_info[i];
-		if (rp->skb) {
-			dev_kfree_skb (rp->skb);
-			rp->skb = NULL;
-			tp->stats.tx_dropped++;
-		}
-	}
-	
-	spin_unlock_irqrestore (&tp->lock, flags);
+	spin_lock_irq (&tp->lock);
+	rtl8139_tx_clear (tp);
+	spin_unlock_irq (&tp->lock);
 
 	/* ...and finally, reset everything */
 	rtl8139_hw_start (dev);
 }
 
 
-
 static int rtl8139_start_xmit (struct sk_buff *skb, struct device *dev)
 {
-	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+	struct rtl8139_private *tp = dev->priv;
 	void *ioaddr = tp->mmio_addr;
 	int entry;
 
@@ -1602,22 +1703,34 @@
 	}
 
 	/* Calculate the next Tx descriptor entry. */
-	entry = atomic_read (&tp->cur_tx) % NUM_TX_DESC;
+	entry = tp->cur_tx % NUM_TX_DESC;
 
 	assert (tp->tx_info[entry].skb == NULL);
 
 	tp->tx_info[entry].skb = skb;
-	memcpy (tp->tx_buf[entry], skb->data, skb->len);
+	if ((long) skb->data & 3) {      /* Must use alignment buffer. */
+		/* tp->tx_info[entry].mapping = 0 */
+		memcpy (tp->tx_buf[entry], skb->data, skb->len);
+		RTL_W32 (TxAddr0 + (entry * 4),
+			 tp->tx_bufs_dma + (tp->tx_buf[entry] - tp->tx_bufs));
+	} else {
+		RTL_W32 (TxAddr0 + (entry * 4), virt_to_bus(skb->data));
+	}
 
 	/* Note: the chip doesn't have auto-pad! */
 	RTL_W32 (TxStatus0 + (entry * sizeof(u32)),
 		 tp->tx_flag | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
 
 	dev->trans_start = jiffies;
-	atomic_inc (&tp->cur_tx);
-	if ((atomic_read (&tp->cur_tx) - atomic_read (&tp->dirty_tx)) >= NUM_TX_DESC)
+
+	spin_lock_irq (&tp->lock);
+
+	tp->cur_tx++;
+	if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx)
 		netif_stop_queue (dev);
 
+	spin_unlock_irq (&tp->lock);
+
 	DPRINTK ("%s: Queued Tx packet at %p size %u to slot %d.\n",
 		 dev->name, skb->data, skb->len, entry);
 
@@ -1625,24 +1738,24 @@
 }
 
 
-static inline void rtl8139_tx_interrupt (struct device *dev,
+static void rtl8139_tx_interrupt (struct device *dev,
 					 struct rtl8139_private *tp,
 					 void *ioaddr)
 {
-	unsigned int dirty_tx;
+	unsigned long dirty_tx, tx_left;
 
 	assert (dev != NULL);
 	assert (tp != NULL);
 	assert (ioaddr != NULL);
-	
-	dirty_tx = atomic_read (&tp->dirty_tx);
 
-	while ((atomic_read (&tp->cur_tx) - dirty_tx) > 0) {
+	dirty_tx = tp->dirty_tx;
+	tx_left = tp->cur_tx - dirty_tx;
+	while (tx_left > 0) {
 		int entry = dirty_tx % NUM_TX_DESC;
 		int txstatus;
 
 		txstatus = RTL_R32 (TxStatus0 + (entry * sizeof (u32)));
-		
+
 		if (!(txstatus & (TxStatOK | TxUnderrun | TxAborted)))
 			break;	/* It still hasn't been Txed */
 
@@ -1675,26 +1788,27 @@
 			tp->stats.tx_bytes += txstatus & 0x7ff;
 			tp->stats.tx_packets++;
 		}
-
 		dev_kfree_skb_irq (tp->tx_info[entry].skb);
 		tp->tx_info[entry].skb = NULL;
+
 		dirty_tx++;
-		if (netif_queue_stopped (dev) &&
-		    (atomic_read (&tp->cur_tx) - dirty_tx < NUM_TX_DESC))
-			netif_wake_queue (dev);
-		mark_bh(NET_BH);
+		tx_left--;
 	}
 
 #ifndef RTL8139_NDEBUG
-	if (atomic_read (&tp->cur_tx) - dirty_tx > NUM_TX_DESC) {
-		printk (KERN_ERR
-		  "%s: Out-of-sync dirty pointer, %d vs. %d.\n",
-		     dev->name, dirty_tx, atomic_read (&tp->cur_tx));
+	if (tp->cur_tx - dirty_tx > NUM_TX_DESC) {
+		printk (KERN_ERR "%s: Out-of-sync dirty pointer, %ld vs. %ld.\n",
+		     dev->name, dirty_tx, tp->cur_tx);
 		dirty_tx += NUM_TX_DESC;
 	}
 #endif /* RTL8139_NDEBUG */
 
-	atomic_set (&tp->dirty_tx, dirty_tx);
+	/* only wake the queue if we did work, and the queue is stopped */
+	if (tp->dirty_tx != dirty_tx) {
+		tp->dirty_tx = dirty_tx;
+		if (netif_queue_stopped (dev))
+			netif_wake_queue (dev);
+	}
 }
 
 /* TODO: clean this up!  Rx reset need not be this intensive */
@@ -1769,10 +1883,15 @@
 
 	while ((RTL_R8 (ChipCmd) & RxBufEmpty) == 0) {
 		int ring_offset = cur_rx % RX_BUF_LEN;
-		u32 rx_status = le32_to_cpu (*(u32 *) (rx_ring + ring_offset));
-		int rx_size = rx_status >> 16;
+		u32 rx_status;
+		unsigned int rx_size;
+		unsigned int pkt_size;
 		struct sk_buff *skb;
-		int pkt_size = rx_size - 4;
+
+		/* read size+status of next frame from DMA ring buffer */
+		rx_status = le32_to_cpu (*(u32 *) (rx_ring + ring_offset));
+		rx_size = rx_status >> 16;
+		pkt_size = rx_size - 4;
 
 		DPRINTK ("%s:  rtl8139_rx() status %4.4x, size %4.4x,"
 			 " cur %4.4x.\n", dev->name, rx_status,
@@ -1800,11 +1919,13 @@
 		if (rx_size == 0xfff0)
 			break;
 
-		/* if Rx err received, Rx process gets reset, so
-		 * we abort any further Rx processing
+		/* If Rx err or invalid rx_size/rx_status received
+		 * (which happens if we get lost in the ring),
+		 * Rx process gets reset, so we abort any further
+		 * Rx processing.
 		 */
-		if (rx_status &
-		    (RxBadSymbol | RxRunt | RxTooLong | RxCRCErr | RxBadAlign)) {
+		if ((rx_size > (MAX_ETH_FRAME_SIZE+4)) ||
+		    (!(rx_status & RxStatusOK))) {
 			rtl8139_rx_err (rx_status, dev, tp, ioaddr);
 			return;
 		}
@@ -1819,24 +1940,24 @@
 		 */
 
 		skb = dev_alloc_skb (pkt_size + 2);
-		if (skb == NULL) {
+		if (skb) {
+			skb->dev = dev;
+			skb_reserve (skb, 2);	/* 16 byte align the IP fields. */
+
+			eth_copy_and_sum (skb, &rx_ring[ring_offset + 4], pkt_size, 0);
+			skb_put (skb, pkt_size);
+
+			skb->protocol = eth_type_trans (skb, dev);
+			netif_rx (skb);
+			mark_bh(NET_BH);
+			tp->stats.rx_bytes += pkt_size ;
+			tp->stats.rx_packets++;
+		} else {
 			printk (KERN_WARNING
 				"%s: Memory squeeze, dropping packet.\n",
 				dev->name);
 			tp->stats.rx_dropped++;
-			break;
 		}
-		skb->dev = dev;
-		skb_reserve (skb, 2);	/* 16 byte align the IP fields. */
-
-		eth_copy_and_sum (skb, &rx_ring[ring_offset + 4], pkt_size, 0);
-		skb_put (skb, pkt_size);
-
-		skb->protocol = eth_type_trans (skb, dev);
-		netif_rx (skb);
-		mark_bh(NET_BH);
-		tp->stats.rx_bytes += pkt_size ;
-		tp->stats.rx_packets++;
 
 		cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
 		RTL_W16_F (RxBufPtr, cur_rx - 16);
@@ -1858,11 +1979,11 @@
 {
 	printk (KERN_DEBUG "%s: Abnormal interrupt, status %8.8x.\n",
 		dev->name, status);
-		 
+
 	assert (dev != NULL);
 	assert (tp != NULL);
 	assert (ioaddr != NULL);
-	
+
 	/* Update the error count. */
 	tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
 	RTL_W32 (RxMissed, 0);
@@ -1877,9 +1998,12 @@
 			tp->full_duplex = duplex;
 			RTL_W8 (Cfg9346, Cfg9346_Unlock);
 			RTL_W8 (Config1, tp->full_duplex ? 0x60 : 0x20);
+			RTL_W8 (Cfg9346, Cfg9346_Lock);
 		}
 		status &= ~RxUnderrun;
 	}
+
+	/* XXX along with rtl8139_rx_err, are we double-counting errors? */
 	if (status &
 	    (RxUnderrun | RxOverflow | RxErr | RxFIFOOver))
 		tp->stats.rx_errors++;
@@ -1909,20 +2033,18 @@
 			       struct pt_regs *regs)
 {
 	struct device *dev = (struct device *) dev_instance;
-	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+	struct rtl8139_private *tp = dev->priv;
 	int boguscnt = max_interrupt_work;
 	void *ioaddr = tp->mmio_addr;
 	int status = 0, link_changed = 0; /* avoid bogus "uninit" warning */
 
-	spin_lock (&tp->lock);
-	
 	do {
 		status = RTL_R16 (IntrStatus);
 
 		/* h/w no longer present (hotplug?) or major error, bail */
 		if (status == 0xFFFF)
 			break;
-		
+
 		/* Acknowledge all of the current interrupt sources ASAP, but
 		   an first get an additional status bit from CSCR. */
 		if (status & RxUnderrun)
@@ -1966,8 +2088,11 @@
 		if (status & (RxOK | RxUnderrun | RxOverflow | RxFIFOOver))	/* Rx interrupt */
 			rtl8139_rx_interrupt (dev, tp, ioaddr);
 
-		if (status & (TxOK | TxErr))
+		if (status & (TxOK | TxErr)) {
+			spin_lock (&tp->lock);
 			rtl8139_tx_interrupt (dev, tp, ioaddr);
+			spin_unlock (&tp->lock);
+		}
 
 		boguscnt--;
 	} while (boguscnt > 0);
@@ -1982,8 +2107,6 @@
 		RTL_W16 (IntrStatus, 0xffff);
 	}
 
-	spin_unlock (&tp->lock);
-	
 	DPRINTK ("%s: exiting interrupt, intr_status=%#4.4x.\n",
 		 dev->name, RTL_R16 (IntrStatus));
 }
@@ -1991,41 +2114,51 @@
 
 static int rtl8139_close (struct device *dev)
 {
-	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+	struct rtl8139_private *tp = dev->priv;
 	void *ioaddr = tp->mmio_addr;
 	int i;
-	unsigned long flags;
+	int ret = 0;
 
 	DPRINTK ("ENTER\n");
 
 	netif_stop_queue (dev);
 	dev->start = 0;
+	if (tp->thr_pid >= 0) {
+		ret = kill_proc (tp->thr_pid, SIGTERM, 1);
+		if (ret) {
+			printk (KERN_ERR "%s: unable to signal thread\n", dev->name);
+			return ret;
+		}
+		down (&tp->thr_exited);
+	}
 
 	DPRINTK ("%s: Shutting down ethercard, status was 0x%4.4x.\n",
 			dev->name, RTL_R16 (IntrStatus));
 
-	del_timer (&tp->timer);
-	
-	spin_lock_irqsave (&tp->lock, flags);
-
-	/* Disable interrupts by clearing the interrupt mask. */
-	RTL_W16 (IntrMask, 0x0000);
+	spin_lock_irq(&tp->lock);
 
 	/* Stop the chip's Tx and Rx DMA processes. */
 	RTL_W8 (ChipCmd, (RTL_R8 (ChipCmd) & ChipCmdClear));
 
+	/* Disable interrupts by clearing the interrupt mask. */
+	RTL_W16 (IntrMask, 0x0000);
+
 	/* Update the error counts. */
 	tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
 	RTL_W32 (RxMissed, 0);
 
-	spin_unlock_irqrestore (&tp->lock, flags);
-	
+	spin_unlock_irq (&tp->lock);
+
+	synchronize_irq ();
+
 	/* snooze for a small bit */
 	if (current->need_resched)
 		schedule ();
 
 	free_irq (dev->irq, dev);
 
+	rtl8139_tx_clear (tp);
+
 	for (i = 0; i < NUM_TX_DESC; i++) {
 		struct sk_buff *skb = tp->tx_info[i].skb;
 
@@ -2055,9 +2188,8 @@
 
 static int mii_ioctl (struct device *dev, struct ifreq *rq, int cmd)
 {
-	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+	struct rtl8139_private *tp = dev->priv;
 	u16 *data = (u16 *) & rq->ifr_data;
-	unsigned long flags;
 	int rc = 0;
 
 	DPRINTK ("ENTER\n");
@@ -2068,9 +2200,7 @@
 		/* Fall Through */
 
 	case SIOCDEVPRIVATE + 1:	/* Read the specified MII register. */
-		spin_lock_irqsave (&tp->lock, flags);
 		data[3] = mdio_read (dev, data[0], data[1] & 0x1f);
-		spin_unlock_irqrestore (&tp->lock, flags);
 		break;
 
 	case SIOCDEVPRIVATE + 2:	/* Write the specified MII register */
@@ -2079,10 +2209,20 @@
 			break;
 		}
 
-		spin_lock_irqsave (&tp->lock, flags);
-		mdio_write (dev, data[0], data[1] & 0x1f, data[2]);
-		spin_unlock_irqrestore (&tp->lock, flags);
-		break;
+		if (data[0] == tp->phys[0]) {
+			u16 value = data[2];
+			switch (data[1]) {
+			case 0:
+				/* Check for autonegotiation on or reset. */
+				tp->medialock = (value & 0x9000) ? 0 : 1;
+				if (tp->medialock)
+					tp->full_duplex = (value & 0x0100) ? 1 : 0;
+				break;
+			case 4: tp->advertising = value; break;
+			}
+		}
+		mdio_write(dev, data[0], data[1] & 0x1f, data[2]);
+  		break;
 
 	default:
 		rc = -EOPNOTSUPP;
@@ -2096,22 +2236,16 @@
 
 static struct net_device_stats *rtl8139_get_stats (struct device *dev)
 {
-	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+	struct rtl8139_private *tp = dev->priv;
 	void *ioaddr = tp->mmio_addr;
 
 	DPRINTK ("ENTER\n");
 
-	assert (tp != NULL);
-
 	if (netif_running(dev)) {
-		unsigned long flags;
-
-		spin_lock_irqsave (&tp->lock, flags);
-
+		spin_lock_irq(&tp->lock);
 		tp->stats.rx_missed_errors += RTL_R32 (RxMissed);
 		RTL_W32 (RxMissed, 0);
-
-		spin_unlock_irqrestore (&tp->lock, flags);
+		spin_unlock_irq(&tp->lock);
 	}
 
 	DPRINTK ("EXIT\n");
@@ -2134,8 +2268,7 @@
 		unsigned char current_octet = *data++;
 		int bit;
 		for (bit = 0; bit < 8; bit++, current_octet >>= 1)
-			crc = (crc << 1) ^
-			    ((crc < 0) ^ (current_octet & 1) ?
+			crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ?
 			     ethernet_polynomial : 0);
 	}
 
@@ -2146,15 +2279,16 @@
 
 static void rtl8139_set_rx_mode (struct device *dev)
 {
-	struct rtl8139_private *tp = (struct rtl8139_private *) dev->priv;
+	struct rtl8139_private *tp = dev->priv;
 	void *ioaddr = tp->mmio_addr;
+	unsigned long flags;
 	u32 mc_filter[2];	/* Multicast hash filter */
 	int i, rx_mode;
 	u32 tmp;
 
 	DPRINTK ("ENTER\n");
 
-	DPRINTK ("%s:   rtl8139_set_rx_mode(%4.4x) done -- Rx config %8.8x.\n",
+	DPRINTK ("%s:   rtl8139_set_rx_mode(%4.4x) done -- Rx config %8.8lx.\n",
 			dev->name, dev->flags, RTL_R32 (RxConfig));
 
 	/* Note: do not reorder, GCC is clever about common statements. */
@@ -2180,8 +2314,8 @@
 			set_bit (ether_crc (ETH_ALEN, mclist->dmi_addr) >> 26,
 				 mc_filter);
 	}
-	
-	spin_lock_irq (&tp->lock);
+
+	spin_lock_irqsave (&tp->lock, flags);
 
 	/* We can safely update without stopping the chip. */
 	tmp = rtl8139_rx_config | rx_mode |
@@ -2190,7 +2324,7 @@
 	RTL_W32_F (MAR0 + 0, mc_filter[0]);
 	RTL_W32_F (MAR0 + 4, mc_filter[1]);
 
-	spin_unlock_irq (&tp->lock);
+	spin_unlock_irqrestore (&tp->lock, flags);
 
 	DPRINTK ("EXIT\n");
 }
@@ -2231,8 +2365,8 @@
 MODULE_DESCRIPTION ("RealTek RTL-8139 Fast Ethernet driver");
 MODULE_PARM (multicast_filter_limit, "i");
 MODULE_PARM (max_interrupt_work, "i");
-MODULE_PARM (debug, "i");
-MODULE_PARM (media, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM (media, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM (full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
 
 int init_module(void)
 {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/Config.in linux.19p18/drivers/net/Config.in
--- linux.vanilla/drivers/net/Config.in	Mon Dec 11 22:12:47 2000
+++ linux.19p18/drivers/net/Config.in	Tue Feb 27 16:10:14 2001
@@ -101,7 +101,11 @@
       tristate 'RealTek 8129/8139 (not 8019/8029!) support' CONFIG_RTL8139
   fi
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      tristate 'RealTek 8139too driver support' CONFIG_RTL8139TOO
+      tristate 'Alternative RealTek 8139 driver (8139too) support' CONFIG_RTL8139TOO
+      if [ "$CONFIG_RTL8139TOO" != "n" ]; then
+          bool '  Use PIO instead of MMIO' CONFIG_8139TOO_PIO
+          bool '  Support for automatic channel equalization' CONFIG_8139TOO_TUNE_TWISTER
+      fi
   fi
   bool 'Other ISA cards' CONFIG_NET_ISA
   if [ "$CONFIG_NET_ISA" = "y" ]; then
@@ -132,9 +136,11 @@
   if [ "$CONFIG_NET_EISA" = "y" ]; then
     tristate 'AMD PCnet32 (VLB and PCI) support' CONFIG_PCNET32
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      tristate 'Adaptec Starfire support (EXPERIMENTAL)' CONFIG_ADAPTEC_STARFIRE
       tristate 'Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200
     fi
     tristate 'Apricot Xen-II on board Ethernet' CONFIG_APRICOT
+    tristate 'LP486E on board Ethernet' CONFIG_LP486E
     tristate 'CS89x0 support' CONFIG_CS89x0
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       tristate 'DM9102 PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_DM9102
@@ -182,7 +188,9 @@
       tristate 'Packet Engines GNIC-II (Hamachi) support' CONFIG_HAMACHI
       tristate 'Packet Engines Yellowfin Gigabit-NIC support' CONFIG_YELLOWFIN
     fi
-    tristate 'SysKonnect SK-98xx support' CONFIG_SK98LIN
+    if [ "$CONFIG_PCI" = "y" ]; then
+      tristate 'SysKonnect SK-98xx support' CONFIG_SK98LIN
+    fi
 endmenu
 
 bool 'FDDI driver support' CONFIG_FDDI
@@ -305,7 +313,7 @@
 #
 
 tristate 'MultiGate (COMX) synchronous serial boards support' CONFIG_COMX
-   if [ "$CONFIG_COMX" != "n" ]; then
+if [ "$CONFIG_COMX" != "n" ]; then
    dep_tristate '  Support for COMX/CMX/HiCOMX boards' CONFIG_COMX_HW_COMX $CONFIG_COMX
    dep_tristate '  Support for LoCOMX board' CONFIG_COMX_HW_LOCOMX $CONFIG_COMX
    dep_tristate '  Support for MixCOM board' CONFIG_COMX_HW_MIXCOM $CONFIG_COMX
@@ -326,7 +334,7 @@
     dep_tristate '  SDL RISCom/N2 support' CONFIG_N2 $CONFIG_HDLC
     dep_tristate '  Moxa C101 support' CONFIG_C101 $CONFIG_HDLC
 
-    if [ "$CONFIG_PCI" != "n" ]; then
+    if [ "$CONFIG_PCI" = "y" ]; then
       dep_tristate '  SBE wanXL support' CONFIG_WANXL $CONFIG_HDLC
       dep_tristate '  Cyclades-PC300 support' CONFIG_PC300 $CONFIG_HDLC
       if [ "$CONFIG_PC300" != "n" ]; then
@@ -347,12 +355,13 @@
 #	Wan router core.
 #
 
-if [ "$CONFIG_WAN_ROUTER" != "n" ]; then
+#  CONFIG_WAN_ROUTER is defined only when CONFIG_EXPERIMENTAL=y
+if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_WAN_ROUTER" != "n" ]; then
   bool 'WAN drivers' CONFIG_WAN_DRIVERS 
   if [ "$CONFIG_WAN_DRIVERS" = "y" ]; then
     dep_tristate 'Sangoma WANPIPE(tm) multi-port cards: (select M not Y !)' CONFIG_VENDOR_SANGOMA $CONFIG_WAN_DRIVERS 
     if [ "$CONFIG_INET" != "n" ]; then
-    if [ "$CONFIG_VENDOR_SANGOMA" != "n" ]; then
+      if [ "$CONFIG_VENDOR_SANGOMA" != "n" ]; then
         int  '  Maximum number of cards' CONFIG_WANPIPE_CARDS 1
         #bool '  WANPIPE X.25 support' CONFIG_WANPIPE_X25
         bool '  WANPIPE Frame Relay support' CONFIG_WANPIPE_FR
@@ -366,17 +375,21 @@
 #
 # Xpeed drivers
 #
-tristate 'Xpeed X200/X300 DSL NIC support' CONFIG_XPEED
+if [ "$CONFIG_PCI" = "y" ]; then
+   tristate 'Xpeed X200/X300 DSL NIC support' CONFIG_XPEED
+fi
 
 endmenu
 
 #
 # X.25 network drivers
 #
-if [ "$CONFIG_X25" != "n" ]; then
-if [ "$CONFIG_LAPB" = "y" -o "$CONFIG_LAPB" = "m" ]; then
+
+#  CONFIG_X25 is defined only when CONFIG_EXPERIMENTAL=y
+if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_X25" != "n" ]; then
+  if [ "$CONFIG_LAPB" = "y" -o "$CONFIG_LAPB" = "m" ]; then
     dep_tristate 'LAPB over Ethernet driver' CONFIG_LAPBETHER $CONFIG_LAPB
     dep_tristate 'X.25 async driver' CONFIG_X25_ASY $CONFIG_LAPB
-fi
+  fi
 fi
 tristate 'SBNI12-xx support' CONFIG_SBNI
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/Makefile linux.19p18/drivers/net/Makefile
--- linux.vanilla/drivers/net/Makefile	Mon Dec 11 22:12:47 2000
+++ linux.19p18/drivers/net/Makefile	Mon Feb 12 14:59:32 2001
@@ -742,6 +742,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_ADAPTEC_STARFIRE),y)
+L_OBJS += starfire.o
+else
+  ifeq ($(CONFIG_ADAPTEC_STARFIRE),m)
+  M_OBJS += starfire.o
+  endif
+endif
+
 ifeq ($(CONFIG_AC3200),y)
 L_OBJS += ac3200.o
 CONFIG_8390_BUILTIN = y
@@ -774,6 +782,11 @@
   ifeq ($(CONFIG_BVME6000_NET),m)
   CONFIG_82596_MODULE = y
   endif
+endif
+
+# This is also a 82596 and should probably be merged
+ifeq ($(CONFIG_LP486E),y)
+L_OBJS += lp486e.o
 endif
 
 ifeq ($(CONFIG_DEC_ELCP),y)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/Space.c linux.19p18/drivers/net/Space.c
--- linux.vanilla/drivers/net/Space.c	Mon Dec 11 22:12:47 2000
+++ linux.19p18/drivers/net/Space.c	Tue Feb 13 18:37:58 2001
@@ -64,6 +64,7 @@
 extern int fmv18x_probe(struct device *);
 extern int eth16i_probe(struct device *);
 extern int depca_probe(struct device *);
+extern int lp486e_probe(struct device *);
 extern int i82596_probe(struct device *);
 extern int ewrk3_probe(struct device *);
 extern int de4x5_probe(struct device *);
@@ -126,6 +127,7 @@
 extern int rcpci_probe(struct device *);
 extern int dmfe_probe(struct device *);
 extern int sktr_probe(struct device *dev);
+extern int starfire_probe(struct device *dev);
 
 /* Gigabit Ethernet adapters */
 extern int yellowfin_probe(struct device *dev);
@@ -277,9 +279,12 @@
 #ifdef CONFIG_VIA_RHINE
 	{via_rhine_probe, 0},
 #endif
-#ifdef CONFI_NET_DM9102
+#ifdef CONFIG_NET_DM9102
 	{dmfe_probe, 0},
-#endif	
+#endif
+#ifdef CONFIG_ADAPTEC_STARFIRE
+	{starfire_probe, 0},
+#endif
 	{NULL, 0},
 };
 
@@ -419,6 +424,9 @@
 #endif
 #if defined(CONFIG_APRICOT) || defined(CONFIG_MVME16x_NET) || defined(CONFIG_BVME6000_NET)	/* Intel I82596 */
 	{i82596_probe, 0},
+#endif
+#if defined(CONFIG_LP486E)
+	{lp486e_probe, 0},
 #endif
 #ifdef CONFIG_EL1		/* 3c501 */
 	{el1_probe, 0},
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/cosa.c linux.19p18/drivers/net/cosa.c
--- linux.vanilla/drivers/net/cosa.c	Mon Dec 11 22:12:48 2000
+++ linux.19p18/drivers/net/cosa.c	Mon Feb 12 14:51:17 2001
@@ -817,7 +817,7 @@
 	up(&chan->rsem);
 
 	if (copy_to_user(buf, kbuf, count)) {
-		kfree(buf);
+		kfree(kbuf);
 		return -EFAULT;
 	}
 	kfree(kbuf);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/cs89x0.c linux.19p18/drivers/net/cs89x0.c
--- linux.vanilla/drivers/net/cs89x0.c	Fri Apr 21 12:46:16 2000
+++ linux.19p18/drivers/net/cs89x0.c	Wed Feb  7 09:41:34 2001
@@ -27,6 +27,8 @@
                     : is running from all accounts.
                     
   Alan Cox          : Removed 1.2 support, added 2.1 extra counters.
+
+  Arnaldo Melo	    : release resources on failure in cs89x0_probe1
 */
 
 static char *version =
@@ -249,13 +251,17 @@
 	struct net_local *lp;
 	static unsigned version_printed = 0;
 	int i;
+	char priv_alloced_here = 0;
 	unsigned rev_type = 0;
 	int eeprom_buff[CHKSUM_LEN];
 
 	/* Initialize the device structure. */
 	if (dev->priv == NULL) {
 		dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+		if (!dev->priv)
+			return -ENOMEM;
                 memset(dev->priv, 0, sizeof(struct net_local));
+		priv_alloced_here = 1;
         }
 	lp = (struct net_local *)dev->priv;
 
@@ -265,12 +271,12 @@
 	if (ioaddr & 1) {
 		ioaddr &= ~1;
 		if ((inw(ioaddr + ADD_PORT) & ADD_MASK) != ADD_SIG)
-			return ENODEV;
+			goto err;
 		outw(PP_ChipID, ioaddr + ADD_PORT);
 	}
 
 	if (inw(ioaddr + DATA_PORT) != CHIP_EISA_ID_SIG)
-		return ENODEV;
+		goto err;
 
 	/* Fill in the 'dev' fields. */
 	dev->base_addr = ioaddr;
@@ -388,6 +394,11 @@
 
 	printk("\n");
 	return 0;
+err:	if (priv_alloced_here) {
+		kfree(dev->priv);
+		dev->priv = NULL;
+	}
+	return -ENODEV;
 }
 
 
@@ -1007,16 +1018,15 @@
 MODULE_PARM(io, "i");
 MODULE_PARM(irq, "i");
 MODULE_PARM(debug, "i");
-MODULE_PARM(media, "s");
+MODULE_PARM(media, "c8");
 MODULE_PARM(duplex, "i");
 
 EXPORT_NO_SYMBOLS;
 
 /*
-* media=t             - specify media type
-   or media=2
+* media=rj45             - specify media type
+   or media=bnc
    or media=aui
-   or medai=auto
 * duplex=0            - specify forced half/full/autonegotiate duplex
 * debug=#             - debug level
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/eepro100.c linux.19p18/drivers/net/eepro100.c
--- linux.vanilla/drivers/net/eepro100.c	Mon Dec 11 22:12:48 2000
+++ linux.19p18/drivers/net/eepro100.c	Sun Feb 25 23:21:00 2001
@@ -751,6 +751,7 @@
 	   This takes less than 10usec and will easily finish before the next
 	   action. */
 	outl(PortReset, ioaddr + SCBPort);
+	inl(ioaddr + SCBPort);
 	/* Honor PortReset timing. */
 	udelay(10);
 
@@ -778,7 +779,7 @@
 		/* The self-test results must be paragraph aligned. */
 		s32 str[6], *volatile self_test_results;
 		int boguscnt = 16000;	/* Timeout for set-test. */
-		if (eeprom[3] & 0x03)
+		if ((eeprom[3] & 0x03) != 0x03)
 			printk(KERN_INFO "  Receiver lock-up bug exists -- enabling"
 				   " work-around.\n");
 		printk(KERN_INFO "  Board assembly %4.4x%2.2x-%3.3d, Physical"
@@ -839,6 +840,7 @@
 #endif  /* kernel_bloat */
 
 	outl(PortReset, ioaddr + SCBPort);
+	inl(ioaddr + SCBPort);
 	/* Honor PortReset timing. */
 	udelay(10);
 
@@ -1062,6 +1064,9 @@
 	/* Set the segment registers to '0'. */
 	wait_for_cmd_done(ioaddr + SCBCmd);
 	outl(0, ioaddr + SCBPointer);
+	/* impose a delay to avoid a bug */
+	inl(ioaddr + SCBPointer);
+	udelay(10);
 	outb(RxAddrLoad, ioaddr + SCBCmd);
 	wait_for_cmd_done(ioaddr + SCBCmd);
 	outb(CUCmdBase, ioaddr + SCBCmd);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/gmac.c linux.19p18/drivers/net/gmac.c
--- linux.vanilla/drivers/net/gmac.c	Mon Dec 11 22:12:48 2000
+++ linux.19p18/drivers/net/gmac.c	Thu Feb 15 16:12:00 2001
@@ -9,7 +9,7 @@
  * Changes:
  * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 08/06/2000
  * - check init_etherdev return in gmac_probe1
- * BenH <bh40@calva.net> - 03/09/2000
+ * BenH <benh@kernel.crashing.org> - 03/09/2000
  * - Add support for new PHYs
  * - Add some PowerBook sleep code
  * 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/irda/irtty.c linux.19p18/drivers/net/irda/irtty.c
--- linux.vanilla/drivers/net/irda/irtty.c	Sun Jun 11 21:44:14 2000
+++ linux.19p18/drivers/net/irda/irtty.c	Sat Mar  3 22:28:26 2001
@@ -282,6 +282,11 @@
 	tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
 	tty->disc_data = 0;
 	
+	/* We are not using any dongle anymore! */
+	if (self->dongle)
+		irda_device_dongle_cleanup(self->dongle);
+	self->dongle = NULL;
+
 	/* Remove netdevice */
 	if (self->netdev) {
 		rtnl_lock();
@@ -291,11 +296,6 @@
 		kfree(self->netdev);
 	}
 	
-	/* We are not using any dongle anymore! */
-	if (self->dongle)
-		irda_device_dongle_cleanup(self->dongle);
-	self->dongle = NULL;
-
 	/* Remove speed changing task if any */
 	if (self->task)
 		irda_task_delete(self->task);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/lance.c linux.19p18/drivers/net/lance.c
--- linux.vanilla/drivers/net/lance.c	Fri Apr 21 12:46:17 2000
+++ linux.19p18/drivers/net/lance.c	Wed Dec 13 21:57:10 2000
@@ -926,6 +926,8 @@
 
 	lp->tx_ring[entry].misc = 0x0000;
 
+	lp->stats.tx_bytes += skb->len;
+
 	/* If any part of this buffer is >16M we must copy it to a low-memory
 	   buffer. */
 	if ((u32)virt_to_bus(skb->data) + skb->len > 0x01000000) {
@@ -941,7 +943,6 @@
 		lp->tx_ring[entry].base = ((u32)virt_to_bus(skb->data) & 0xffffff) | 0x83000000;
 	}
 	lp->cur_tx++;
-	lp->stats.tx_bytes += skb->len;
 
 	/* Trigger an immediate send poll. */
 	outw(0x0000, ioaddr+LANCE_ADDR);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/lanstreamer.c linux.19p18/drivers/net/lanstreamer.c
--- linux.vanilla/drivers/net/lanstreamer.c	Fri Apr 21 12:46:17 2000
+++ linux.19p18/drivers/net/lanstreamer.c	Thu Dec 21 22:49:57 2000
@@ -58,6 +58,7 @@
  *            First release to the public
  *  03/03/00 - Merged to kernel, indented -kr -i8 -bri0, fixed some missing
  *		malloc free checks, reviewed code. <alan@redhat.com>
+ *  12/18/00 - Made it SMP safe   - George Staikos <staikos@0wned.org>
  *  
  *  To Do:
  *
@@ -108,6 +109,7 @@
 #include <net/checksum.h>
 
 #include <asm/io.h>
+#include <asm/spinlock.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
 
@@ -285,6 +287,8 @@
 	streamer_priv = (struct streamer_private *) dev->priv;
 	streamer_mmio = streamer_priv->streamer_mmio;
 
+        streamer_priv->lock = (spinlock_t) SPIN_LOCK_UNLOCKED;
+
 	printk("%s \n", version);
 	printk(KERN_INFO "%s: IBM PCI tokenring card. I/O at %hx, MMIO at %p, using irq %d\n",
 			dev->name, (unsigned int) dev->base_addr,
@@ -823,6 +827,7 @@
 	__u16 misr;
 	__u16 sisrmask;
 
+        spin_lock(&(streamer_priv->lock));
 	sisrmask = SISR_MI;
 	writew(~sisrmask, streamer_mmio + SISR_MASK_RUM);
 	sisr = readw(streamer_mmio + SISR);
@@ -831,6 +836,7 @@
 	writew(~misr, streamer_mmio + MISR_RUM);
 
 	if (!sisr) {		/* Interrupt isn't for us */
+                spin_unlock(&(streamer_priv->lock));
 		return;
 	}
 
@@ -919,6 +925,7 @@
 
 	dev->interrupt = 0;
 	writew(SISR_MI, streamer_mmio + SISR_MASK_SUM);
+        spin_unlock(&(streamer_priv->lock));
 }
 
 
@@ -927,11 +934,14 @@
 	struct streamer_private *streamer_priv =
 	    (struct streamer_private *) dev->priv;
 	__u8 *streamer_mmio = streamer_priv->streamer_mmio;
+        int flags;
 
 	if (test_and_set_bit(0, (void *) &dev->tbusy) != 0) {
 		return 1;
 	}
 
+        spin_lock_irqsave(&(streamer_priv->lock), flags);
+
 	if (streamer_priv->free_tx_ring_entries) {
 		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].status = 0;
 		streamer_priv->streamer_tx_ring[streamer_priv->tx_ring_free].bufcnt_framelen = 0x00010000 | skb->len;
@@ -956,8 +966,10 @@
 
 		streamer_priv->tx_ring_free = (streamer_priv->tx_ring_free + 1) & (STREAMER_TX_RING_SIZE - 1);
 		dev->tbusy = 0;
+                spin_unlock_irqrestore(&(streamer_priv->lock), flags);
 		return 0;
 	} else {
+                spin_unlock_irqrestore(&(streamer_priv->lock), flags);
 		return 1;
 	}
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/lanstreamer.h linux.19p18/drivers/net/lanstreamer.h
--- linux.vanilla/drivers/net/lanstreamer.h	Fri Apr 21 12:46:17 2000
+++ linux.19p18/drivers/net/lanstreamer.h	Thu Dec 21 22:50:02 2000
@@ -283,6 +283,7 @@
 	__u16 streamer_addr_table_addr, streamer_parms_addr;
 	__u16 mac_rx_buffer;
 	__u8 streamer_laa[6];
+        spinlock_t lock;
 };
 
 struct streamer_adapter_addr_table {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/lp486e.c linux.19p18/drivers/net/lp486e.c
--- linux.vanilla/drivers/net/lp486e.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/net/lp486e.c	Wed Dec 13 22:30:41 2000
@@ -0,0 +1,1401 @@
+/* Intel Professional Workstation/panther ethernet driver */
+/* lp486e.c: A panther 82596 ethernet driver for linux. */
+/*
+    History and copyrights:
+
+    Driver skeleton
+        Written 1993 by Donald Becker.
+        Copyright 1993 United States Government as represented by the Director,
+        National Security Agency.  This software may only be used and
+	distributed according to the terms of the GNU Public License
+	as modified by SRC, incorporated herein by reference.
+
+        The author may be reached as becker@super.org or
+        C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
+
+    Apricot
+        Written 1994 by Mark Evans.
+        This driver is for the Apricot 82596 bus-master interface
+
+        Modularised 12/94 Mark Evans
+
+    Professional Workstation
+	Derived from apricot.c by Ard van Breemen
+	<ard@murphy.nl>|<ard@cstmel.hobby.nl>|<ard@cstmel.nl.eu.org>
+
+	Credits:
+	Thanks to Murphy Software BV for letting me write this in their time.
+	Well, actually, I get payed doing this...
+	(Also: see http://www.murphy.nl for murphy, and my homepage ~ard for
+	more information on the Professional Workstation)
+
+    Present version
+	aeb@cwi.nl
+*/
+/*
+    There are currently two motherboards that I know of in the
+    professional workstation. The only one that I know is the
+    intel panther motherboard. -- ard
+*/
+/*
+The pws is equipped with an intel 82596. This is a very intelligent controller
+which runs its own micro-code. Communication with the hostprocessor is done
+through linked lists of commands and buffers in the hostprocessors memory.
+A complete description of the 82596 is available from intel. Search for
+a file called "29021806.pdf". It is a complete description of the chip itself.
+To use it for the pws some additions are needed regarding generation of
+the PORT and CA signal, and the interrupt glue needed for a pc.
+I/O map:
+PORT  SIZE ACTION MEANING
+0xCB0    2 WRITE  Lower 16 bits for PORT command
+0xCB2    2 WRITE  Upper 16 bits for PORT command, and issue of PORT command
+0xCB4    1 WRITE  Generation of CA signal
+0xCB8    1 WRITE  Clear interrupt glue
+All other communication is through memory!
+*/
+
+#define SLOW_DOWN_IO udelay(5);
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#define kkmalloc(typ, prio)	(typ *)(kmalloc(sizeof(typ), prio))
+
+#ifdef REALLY_OLD
+#ifndef HAVE_PORTRESERVE
+#define check_region(addr, size)	0
+#define request_region(addr, size,name)	do ; while(0)
+#endif
+
+#ifndef HAVE_ALLOC_SKB
+#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority)
+#define kfree_skbmem(buff, size) kfree_s(buff,size)
+#endif
+#endif /* REALLY_OLD */
+
+#define LOG_SRCDST    0x80000000
+#define LOG_STATINT   0x40000000
+#define LOG_STARTINT  0x20000000
+
+#define i596_debug debug
+
+static int i596_debug = 0;
+
+static const char * const medianame[] = {
+	"10baseT", "AUI",
+	"10baseT-FD", "AUI-FD",
+};
+
+#define LP486E_TOTAL_SIZE 16
+
+#define I596_NULL (0xffffffff)
+
+#define CMD_EOL		0x8000	/* The last command of the list, stop. */
+#define CMD_SUSP	0x4000	/* Suspend after doing cmd. */
+#define CMD_INTR	0x2000	/* Interrupt after doing cmd. */
+
+#define CMD_FLEX	0x0008	/* Enable flexible memory model */
+
+enum commands {
+	CmdNOP = 0,
+	CmdIASetup = 1,
+	CmdConfigure = 2,
+	CmdMulticastList = 3,
+	CmdTx = 4,
+	CmdTDR = 5,
+	CmdDump = 6,
+	CmdDiagnose = 7
+};
+
+char *CUcmdnames[8] = { "NOP", "IASetup", "Configure", "MulticastList",
+			"Tx", "TDR", "Dump", "Diagnose" };
+
+/* Status word bits */
+#define	STAT_CX		0x8000	/* The CU finished executing a command
+				   with the Interrupt bit set */
+#define	STAT_FR		0x4000	/* The RU finished receiving a frame */
+#define	STAT_CNA	0x2000	/* The CU left the active state */
+#define	STAT_RNR	0x1000	/* The RU left the active state */
+#define STAT_ACK	(STAT_CX | STAT_FR | STAT_CNA | STAT_RNR)
+#define	STAT_CUS	0x0700	/* Status of CU: 0: idle, 1: suspended,
+				   2: active, 3-7: unused */
+#define STAT_RUS	0x00f0	/* Status of RU: 0: idle, 1: suspended,
+				   2: no resources, 4: ready,
+				   10: no resources due to no more RBDs,
+				   12: no more RBDs, other: unused */
+#define	STAT_T		0x0008	/* Bus throttle timers loaded */
+#define	STAT_ZERO	0x0807	/* Always zero */
+
+char *CUstates[8] = { "idle", "suspended", "active", 0, 0, 0, 0, 0 };
+char *RUstates[16] = { "idle", "suspended", "no resources", 0, "ready", 0,
+		       0, 0, 0, 0, "no RBDs", 0, "out of RBDs", 0, 0, 0 };
+
+#if 0
+static void
+i596_out_status(int status) {
+	int bad = 0;
+	char *s;
+
+	printk("status %4.4x:", status);
+	if (status == 0xffff)
+		printk(" strange..\n");
+	else {
+		if (status & STAT_CX)
+			printk("  CU done");
+		if (status & STAT_CNA)
+			printk("  CU stopped");
+		if (status & STAT_FR)
+			printk("  got a frame");
+		if (status & STAT_RNR)
+			printk("  RU stopped");
+		if (status & STAT_T)
+			printk("  throttled");
+		if (status & STAT_ZERO)
+			bad = 1;
+		s = CUstates[(status & STAT_CUS) >> 8];
+		if (!s)
+			bad = 1;
+		else
+			printk("  CU(%s)", s);
+		s = RUstates[(status & STAT_RUS) >> 4];
+		if (!s)
+			bad = 1;
+		else
+			printk("  RU(%s)", s);
+		if (bad)
+			printk("  bad status");
+		printk("\n");
+	}
+}
+#endif
+
+/* Command word bits */
+#define ACK_CX		0x8000
+#define ACK_FR		0x4000
+#define ACK_CNA		0x2000
+#define ACK_RNR		0x1000
+
+#define CUC_START	0x0100
+#define CUC_RESUME	0x0200
+#define CUC_SUSPEND	0x0300
+#define CUC_ABORT	0x0400
+
+#define RX_START	0x0010
+#define RX_RESUME	0x0020
+#define RX_SUSPEND	0x0030
+#define RX_ABORT	0x0040
+
+typedef u32 phys_addr;
+
+static inline phys_addr
+va_to_pa(volatile void *x) {
+	return x ? virt_to_bus(x) : I596_NULL;
+}
+
+static inline void *
+pa_to_va(phys_addr x) {
+	return (x == I596_NULL) ? NULL : bus_to_virt(x);
+}
+
+/* status bits for cmd */
+#define CMD_STAT_C	0x8000	/* CU command complete */
+#define CMD_STAT_B	0x4000	/* CU command in progress */
+#define CMD_STAT_OK	0x2000	/* CU command completed without errors */
+#define CMD_STAT_A	0x1000	/* CU command abnormally terminated */
+
+struct i596_cmd {		/* 8 bytes */
+	unsigned short status;
+	unsigned short command;
+	phys_addr pa_next;	/* va_to_pa(struct i596_cmd *next) */
+};
+
+#define EOF		0x8000
+#define SIZE_MASK	0x3fff
+
+struct i596_tbd {
+	unsigned short size;
+	unsigned short pad;
+	phys_addr pa_next;	/* va_to_pa(struct i596_tbd *next) */
+	phys_addr pa_data;	/* va_to_pa(char *data) */
+	struct sk_buff *skb;
+};
+
+struct tx_cmd {
+	struct i596_cmd cmd;
+	phys_addr pa_tbd;	/* va_to_pa(struct i596_tbd *tbd) */
+	unsigned short size;
+	unsigned short pad;
+};
+
+/* status bits for rfd */
+#define RFD_STAT_C	0x8000	/* Frame reception complete */
+#define RFD_STAT_B	0x4000	/* Frame reception in progress */
+#define RFD_STAT_OK	0x2000	/* Frame received without errors */
+#define RFD_STATUS	0x1fff
+#define RFD_LENGTH_ERR	0x1000
+#define RFD_CRC_ERR	0x0800
+#define RFD_ALIGN_ERR	0x0400
+#define RFD_NOBUFS_ERR	0x0200
+#define RFD_DMA_ERR	0x0100	/* DMA overrun failure to acquire system bus */
+#define RFD_SHORT_FRAME_ERR	0x0080
+#define RFD_NOEOP_ERR	0x0040
+#define RFD_TRUNC_ERR	0x0020
+#define RFD_MULTICAST  0x0002	/* 0: destination had our address
+				   1: destination was broadcast/multicast */
+#define RFD_COLLISION  0x0001
+
+/* receive frame descriptor */
+struct i596_rfd {
+	unsigned short stat;
+	unsigned short cmd;
+	phys_addr pa_next;	/* va_to_pa(struct i596_rfd *next) */
+	phys_addr pa_rbd;	/* va_to_pa(struct i596_rbd *rbd) */
+	unsigned short count;
+	unsigned short size;
+	char data[1532];
+};
+
+#define RBD_EL		0x8000
+#define RBD_P		0x4000
+#define RBD_SIZEMASK	0x3fff
+#define RBD_EOF		0x8000
+#define RBD_F		0x4000
+
+/* receive buffer descriptor */
+struct i596_rbd {
+	unsigned short size;
+	unsigned short pad;
+	phys_addr pa_next;	/* va_to_pa(struct i596_tbd *next) */
+	phys_addr pa_data;	/* va_to_pa(char *data) */
+	phys_addr pa_prev;	/* va_to_pa(struct i596_tbd *prev) */
+	
+	/* Driver private part */
+	struct sk_buff *skb;
+};
+
+#define RX_RING_SIZE 64
+#define RX_SKBSIZE (ETH_FRAME_LEN+10)
+#define RX_RBD_SIZE 32
+
+/* System Control Block - 40 bytes */
+struct i596_scb {
+	u16 status;		/* 0 */
+	u16 command;		/* 2 */
+	phys_addr pa_cmd;	/* 4 - va_to_pa(struct i596_cmd *cmd) */
+	phys_addr pa_rfd;	/* 8 - va_to_pa(struct i596_rfd *rfd) */
+	u32 crc_err;		/* 12 */
+	u32 align_err;		/* 16 */
+	u32 resource_err;	/* 20 */
+	u32 over_err;		/* 24 */
+	u32 rcvdt_err;		/* 28 */
+	u32 short_err;		/* 32 */
+	u16 t_on;		/* 36 */
+	u16 t_off;		/* 38 */
+};
+
+/* Intermediate System Configuration Pointer - 8 bytes */
+struct i596_iscp {
+	u32 busy;		/* 0 */
+	phys_addr pa_scb;	/* 4 - va_to_pa(struct i596_scb *scb) */
+};
+
+/* System Configuration Pointer - 12 bytes */
+struct i596_scp {
+	u32 sysbus;		/* 0 */
+	u32 pad;		/* 4 */
+	phys_addr pa_iscp;	/* 8 - va_to_pa(struct i596_iscp *iscp) */
+};
+
+/* Selftest and dump results - needs 16-byte alignment */
+/*
+ * The size of the dump area is 304 bytes. When the dump is executed
+ * by the Port command an extra word will be appended to the dump area.
+ * The extra word is a copy of the Dump status word (containing the
+ * C, B, OK bits). [I find 0xa006, with a0 for C+OK and 6 for dump]
+ */
+struct i596_dump {
+	u16 dump[153];		/* (304 = 130h) + 2 bytes */
+};
+
+struct i596_private {		/* aligned to a 16-byte boundary */
+	struct i596_scp scp;	/* 0 - needs 16-byte alignment */
+	struct i596_iscp iscp;	/* 12 */
+	struct i596_scb scb;	/* 20 */
+	u32 dummy;		/* 60 */
+	struct i596_dump dump;	/* 64 - needs 16-byte alignment */
+
+	struct i596_cmd set_add;
+	char eth_addr[8];	/* directly follows set_add */
+
+	struct i596_cmd set_conf;
+	char i596_config[16];	/* directly follows set_conf */
+
+	struct i596_cmd tdr;
+	unsigned long tdr_stat;	/* directly follows tdr */
+
+	int last_restart;
+	volatile struct i596_rbd *rbd_list;
+	volatile struct i596_rbd *rbd_tail;
+	volatile struct i596_rfd *rx_tail;
+	volatile struct i596_cmd *cmd_tail;
+	volatile struct i596_cmd *cmd_head;
+	int cmd_backlog;
+	unsigned long last_cmd;
+	struct enet_statistics stats;
+};
+
+static char init_setup[14] = {
+	0x8E,	/* length 14 bytes, prefetch on */
+	0xC8,	/* default: fifo to 8, monitor off */
+	0x40,	/* default: don't save bad frames (apricot.c had 0x80) */
+	0x2E,	/* (default is 0x26)
+		   No source address insertion, 8 byte preamble */
+	0x00,	/* default priority and backoff */
+	0x60,	/* default interframe spacing */
+	0x00,	/* default slot time LSB */
+	0xf2,	/* default slot time and nr of retries */
+	0x00,	/* default various bits
+		   (0: promiscuous mode, 1: broadcast disable,
+		    2: encoding mode, 3: transmit on no CRS,
+		    4: no CRC insertion, 5: CRC type,
+		    6: bit stuffing, 7: padding) */
+	0x00,	/* default carrier sense and collision detect */
+	0x40,	/* default minimum frame length */
+	0xff,	/* (default is 0xff, and that is what apricot.c has;
+		   elp486.c has 0xfb: Enable crc append in memory.) */
+	0x00,	/* default: not full duplex */
+	0x7f	/* (default is 0x3f) multi IA */
+};
+
+static int i596_open(struct device *dev);
+static int i596_start_xmit(struct sk_buff *skb, struct device *dev);
+static void i596_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int i596_close(struct device *dev);
+static struct enet_statistics *i596_get_stats(struct device *dev);
+static void i596_add_cmd(struct device *dev, struct i596_cmd *cmd);
+static void print_eth(char *);
+static void set_multicast_list(struct device *dev);
+
+static int
+i596_timeout(struct device *dev, char *msg, int ct) {
+	volatile struct i596_private *lp;
+	int boguscnt = ct;
+
+	lp = (struct i596_private *) dev->priv;
+	while (lp->scb.command) {
+		if (--boguscnt == 0) {
+			printk("%s: %s timed out - stat %4.4x, cmd %4.4x\n",
+			       dev->name, msg,
+			       lp->scb.status, lp->scb.command);
+			return 1;
+		}
+		udelay(5);
+	}
+	return 0;
+}
+
+static inline int
+init_rx_bufs(struct device *dev, int num) {
+	volatile struct i596_private *lp;
+	struct i596_rfd *rfd;
+	int i;
+	// struct i596_rbd *rbd;
+
+	lp = (struct i596_private *) dev->priv;
+	lp->scb.pa_rfd = I596_NULL;
+
+	for (i = 0; i < num; i++) {
+		rfd = kkmalloc(struct i596_rfd, GFP_KERNEL);
+		if (rfd == NULL)
+			break;
+
+		rfd->stat = 0;
+		rfd->pa_rbd = I596_NULL;
+		rfd->count = 0;
+		rfd->size = 1532;
+		if (i == 0) {
+			rfd->cmd = CMD_EOL;
+			lp->rx_tail = rfd;
+		} else {
+			rfd->cmd = 0;
+		}
+		rfd->pa_next = lp->scb.pa_rfd;
+		lp->scb.pa_rfd = va_to_pa(rfd);
+		lp->rx_tail->pa_next = lp->scb.pa_rfd;
+	}
+
+#if 0
+	for (i = 0; i<RX_RBD_SIZE; i++) {
+		rbd = kkmalloc(struct i596_rbd,GFP_KERNEL);
+		if (rbd) {
+			rbd->pad = 0;
+			rbd->count = 0;
+			rbd->skb = dev_alloc_skb(RX_SKB_SIZE);
+			if (!rbd->skb) {
+				printk("dev_alloc_skb failed");
+			}
+			rbd->next = rfd->rbd;
+			if (i) {
+				rfd->rbd->prev = rbd;
+				rbd->size = RX_SKB_SIZE;
+			} else {
+				rbd->size = (RX_SKB_SIZE | RBD_EL);
+				lp->rbd_tail = rbd;
+			}
+
+			rfd->rbd = rbd;
+		} else {
+			printk("Could not kmalloc rbd\n");
+		}
+	}
+	lp->rbd_tail->next = rfd->rbd;
+#endif
+	return (i);
+}
+
+static inline void
+remove_rx_bufs(struct device *dev) {
+	struct i596_private *lp;
+	struct i596_rfd *rfd;
+
+	lp = (struct i596_private *) dev->priv;
+	lp->rx_tail->pa_next = I596_NULL;
+
+	do {
+		rfd = pa_to_va(lp->scb.pa_rfd);
+		lp->scb.pa_rfd = rfd->pa_next;
+		kfree(rfd);
+	} while (rfd != lp->rx_tail);
+
+	lp->rx_tail = 0;
+
+#if 0
+	for (lp->rbd_list) {
+	}
+#endif
+}
+
+#define PORT_RESET              0x00    /* reset 82596 */
+#define PORT_SELFTEST           0x01    /* selftest */
+#define PORT_ALTSCP             0x02    /* alternate SCB address */
+#define PORT_DUMP               0x03    /* dump */
+
+#define IOADDR	0xcb0
+#define IRQ	10		/* default IRQ - can be changed by ECU */
+
+/* The 82596 requires two 16-bit write cycles for a port command */
+static inline void
+PORT(phys_addr a, unsigned int cmd) {
+	if (a & 0xf)
+		printk("lp486e.c: PORT: address not aligned\n");
+	outw(((a & 0xffff) | cmd), IOADDR);
+	outw(((a>>16) & 0xffff), IOADDR+2);
+}
+
+static inline void
+CA(void) {
+	outb(0, IOADDR+4);
+	udelay(8);
+}
+
+static inline void
+CLEAR_INT(void) {
+	outb(0, IOADDR+8);
+}
+
+#define SIZE(x)	(sizeof(x)/sizeof((x)[0]))
+
+#if 0
+/* selftest or dump */
+static void
+i596_port_do(struct device *dev, int portcmd, char *cmdname) {
+	volatile struct i596_private *lp = (struct i596_private *)dev->priv;
+	volatile u16 *outp;
+	int i, m;
+
+	memset((void *)&(lp->dump), 0, sizeof(struct i596_dump));
+	outp = &(lp->dump.dump[0]);
+
+	PORT(va_to_pa(outp), portcmd);
+	mdelay(30);             /* random, unmotivated */
+
+	printk("lp486e i82596 %s result:\n", cmdname);
+	for (m = SIZE(lp->dump.dump); m && lp->dump.dump[m-1] == 0; m--)
+		;
+	for (i = 0; i < m; i++) {
+		printk(" %04x", lp->dump.dump[i]);
+		if (i%8 == 7)
+			printk("\n");
+	}
+	printk("\n");
+}
+#endif
+
+static int
+i596_scp_setup(struct device *dev) {
+	volatile struct i596_private *lp = (struct i596_private *)dev->priv;
+	int boguscnt;
+
+	/* Setup SCP, ISCP, SCB */
+	/*
+	 * sysbus bits:
+	 *  only a single byte is significant - here 0x44
+	 *  0x80: big endian mode (details depend on stepping)
+	 *  0x40: 1
+	 *  0x20: interrupt pin is active low
+	 *  0x10: lock function disabled
+	 *  0x08: external triggering of bus throttle timers
+	 *  0x06: 00: 82586 compat mode, 01: segmented mode, 10: linear mode
+	 *  0x01: unused
+	 */
+	lp->scp.sysbus = 0x00440000; 		/* linear mode */
+	lp->scp.pad = 0;			/* must be zero */
+	lp->scp.pa_iscp = va_to_pa(&(lp->iscp));
+
+	/*
+	 * The CPU sets the ISCP to 1 before it gives the first CA()
+	 */
+	lp->iscp.busy = 0x0001;
+	lp->iscp.pa_scb = va_to_pa(&(lp->scb));
+
+	lp->scb.command = 0;
+	lp->scb.status = 0;
+	lp->scb.pa_cmd = I596_NULL;
+	/* lp->scb.pa_rfd has been initialised already */
+
+	lp->last_cmd = jiffies;
+	lp->cmd_backlog = 0;
+	lp->cmd_head = NULL;
+
+	/*
+	 * Reset the 82596.
+	 * We need to wait 10 systemclock cycles, and
+	 * 5 serial clock cycles.
+	 */
+	PORT(0, PORT_RESET);	/* address part ignored */
+	udelay(100);
+
+	/*
+	 * Before the CA signal is asserted, the default SCP address
+	 * (0x00fffff4) can be changed to a 16-byte aligned value
+	 */
+	PORT(va_to_pa(&lp->scp), PORT_ALTSCP);	/* change the scp address */
+
+	/*
+	 * The initialization procedure begins when a
+	 * Channel Attention signal is asserted after a reset.
+	 */
+	CA();
+
+	CLEAR_INT();
+
+	/*
+	 * The ISCP busy is cleared by the 82596 after the SCB base
+	 * and offset are read.
+	 */
+	boguscnt = 100;
+	while (lp->iscp.busy) {
+		if (--boguscnt == 0) {
+			/* No i82596 present? */
+			printk("%s: i82596 initialization timed out\n",
+			       dev->name);
+			return 1;
+		}
+		udelay(5);
+	}
+	/* I find here boguscnt==100, so no delay was required. */
+
+	return 0;
+}
+
+static int
+init_i596(struct device *dev) {
+	volatile struct i596_private *lp;
+
+	if (i596_scp_setup(dev))
+		return 1;
+
+	lp = (struct i596_private *) dev->priv;
+	lp->scb.command = 0;
+
+	memcpy ((void *)lp->i596_config, init_setup, 14);
+	lp->set_conf.command = CmdConfigure;
+	i596_add_cmd(dev, (void *)&lp->set_conf);
+
+	memcpy ((void *)lp->eth_addr, dev->dev_addr, 6);
+	lp->set_add.command = CmdIASetup;
+	i596_add_cmd(dev, (struct i596_cmd *)&lp->set_add);
+
+	lp->tdr.command = CmdTDR;
+	i596_add_cmd(dev, (struct i596_cmd *)&lp->tdr);
+
+	if (lp->scb.command && i596_timeout(dev, "i82596 init", 200))
+		return 1;
+
+	lp->scb.command = RX_START;
+	CA();
+
+	if (lp->scb.command && i596_timeout(dev, "Receive Unit start", 100))
+		return 1;
+
+	return 0;
+}
+
+/* Receive a single frame */
+static inline int
+i596_rx_one(struct device *dev, volatile struct i596_private *lp,
+	    struct i596_rfd *rfd, int *frames) {
+
+	if (rfd->stat & RFD_STAT_OK) {
+		/* a good frame */
+		int pkt_len = (rfd->count & 0x3fff);
+		struct sk_buff *skb = dev_alloc_skb(pkt_len);
+
+		(*frames)++;
+
+		if (rfd->cmd & CMD_EOL)
+			printk("Received on EOL\n");
+
+		if (skb == NULL) {
+			printk ("%s: i596_rx Memory squeeze, "
+				"dropping packet.\n", dev->name);
+			lp->stats.rx_dropped++;
+			return 1;
+		}
+
+		skb->dev = dev;		
+		memcpy(skb_put(skb,pkt_len), rfd->data, pkt_len);
+
+		skb->protocol = eth_type_trans(skb,dev);
+		netif_rx(skb);
+		lp->stats.rx_packets++;
+	} else {
+#if 0
+		printk("Frame reception error status %04x\n",
+		       rfd->stat);
+#endif
+		lp->stats.rx_errors++;
+		if (rfd->stat & RFD_COLLISION)
+			lp->stats.collisions++;
+		if (rfd->stat & RFD_SHORT_FRAME_ERR)
+			lp->stats.rx_length_errors++;
+		if (rfd->stat & RFD_DMA_ERR)
+			lp->stats.rx_over_errors++;
+		if (rfd->stat & RFD_NOBUFS_ERR)
+			lp->stats.rx_fifo_errors++;
+		if (rfd->stat & RFD_ALIGN_ERR)
+			lp->stats.rx_frame_errors++;
+		if (rfd->stat & RFD_CRC_ERR)
+			lp->stats.rx_crc_errors++;
+		if (rfd->stat & RFD_LENGTH_ERR)
+			lp->stats.rx_length_errors++;
+	}
+	rfd->stat = rfd->count = 0;
+	return 0;
+}
+
+static int
+i596_rx(struct device *dev) {
+	volatile struct i596_private *lp = (struct i596_private *) dev->priv;
+	struct i596_rfd *rfd;
+	int frames = 0;
+
+	while (1) {
+		rfd = pa_to_va(lp->scb.pa_rfd);
+		if (!rfd) {
+			printk("i596_rx: NULL rfd?\n");
+			return 0;
+		}
+#if 1
+		if (rfd->stat && !(rfd->stat & (RFD_STAT_C | RFD_STAT_B)))
+			printk("SF:%p-%04x\n", rfd, rfd->stat);
+#endif
+		if (!(rfd->stat & RFD_STAT_C))
+			break;		/* next one not ready */
+		if (i596_rx_one(dev, lp, rfd, &frames))
+			break;		/* out of memory */
+		rfd->cmd = CMD_EOL;
+		lp->rx_tail->cmd = 0;
+		lp->rx_tail = rfd;
+		lp->scb.pa_rfd = rfd->pa_next;
+	}
+
+	return frames;
+}
+
+static void
+i596_cleanup_cmd(struct device *dev) {
+	volatile struct i596_private *lp;
+	struct i596_cmd *cmd;
+
+	lp = (struct i596_private *) dev->priv;
+	while (lp->cmd_head) {
+		cmd = (struct i596_cmd *)lp->cmd_head;
+
+		lp->cmd_head = pa_to_va(lp->cmd_head->pa_next);
+		lp->cmd_backlog--;
+
+		switch ((cmd->command) & 0x7) {
+			case CmdTx: {
+				struct tx_cmd *tx_cmd = (struct tx_cmd *) cmd;
+				struct i596_tbd * tx_cmd_tbd;
+				tx_cmd_tbd = pa_to_va(tx_cmd->pa_tbd);
+
+				dev_kfree_skb(tx_cmd_tbd->skb);
+
+				lp->stats.tx_errors++;
+				lp->stats.tx_aborted_errors++;
+
+				cmd->pa_next = I596_NULL;
+				kfree((unsigned char *)tx_cmd);
+				break;
+			}
+			case CmdMulticastList: {
+				// unsigned short count = *((unsigned short *) (ptr + 1));
+
+				cmd->pa_next = I596_NULL;
+				kfree((unsigned char *)cmd);
+				break;
+			}
+			default: {
+				cmd->pa_next = I596_NULL;
+				break;
+			}
+		}
+	}
+
+	if (lp->scb.command && i596_timeout(dev, "i596_cleanup_cmd", 100))
+		;
+
+	lp->scb.pa_cmd = va_to_pa(lp->cmd_head);
+}
+
+static inline void
+i596_reset(struct device *dev, volatile struct i596_private *lp, int ioaddr) {
+
+	if (lp->scb.command && i596_timeout(dev, "i596_reset", 100))
+		;
+
+	dev->start = 0;
+	dev->tbusy = 1;
+
+	lp->scb.command = CUC_ABORT | RX_ABORT;
+	CA();
+
+	/* wait for shutdown */
+	if (lp->scb.command && i596_timeout(dev, "i596_reset(2)", 400))
+		;
+
+	i596_cleanup_cmd(dev);
+	i596_rx(dev);
+
+	dev->start = 1;
+	dev->tbusy = 0;
+	/*dev_kfree_skb(skb, FREE_WRITE);*/
+	dev->interrupt = 0;
+	init_i596(dev);
+}
+
+static void i596_add_cmd(struct device *dev, struct i596_cmd *cmd) {
+	volatile struct i596_private *lp = (struct i596_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+	unsigned long flags;
+
+	cmd->status = 0;
+	cmd->command |= (CMD_EOL | CMD_INTR);
+	cmd->pa_next = I596_NULL;
+
+	save_flags(flags);
+	cli();
+	if (lp->cmd_head) {
+		lp->cmd_tail->pa_next = va_to_pa(cmd);
+	} else {
+		lp->cmd_head = cmd;
+		if (lp->scb.command && i596_timeout(dev, "i596_add_cmd", 100))
+			;
+		lp->scb.pa_cmd = va_to_pa(cmd);
+		lp->scb.command = CUC_START;
+		CA();
+	}
+	lp->cmd_tail = cmd;
+	lp->cmd_backlog++;
+
+	lp->cmd_head = pa_to_va(lp->scb.pa_cmd);
+	restore_flags(flags);
+
+	if (lp->cmd_backlog > 16) {
+		int tickssofar = jiffies - lp->last_cmd;
+		if (tickssofar < 25) return;
+
+		printk("%s: command unit timed out, status resetting.\n",
+		       dev->name);
+		i596_reset(dev, lp, ioaddr);
+	}
+}
+
+static int
+i596_open(struct device *dev) {
+	int i;
+
+	if (request_irq(dev->irq, &i596_interrupt, SA_SHIRQ, dev->name, dev)) {
+		printk("%s: IRQ %d not free\n", dev->name, dev->irq);
+		return -EAGAIN;
+	}
+
+//	irq2dev_map[dev->irq] = dev;
+
+	if ((i = init_rx_bufs(dev, RX_RING_SIZE)) < RX_RING_SIZE)
+		printk("%s: only able to allocate %d receive buffers\n",
+		       dev->name, i);
+
+	if (i < 4) {
+// release buffers
+		free_irq(dev->irq, dev);
+//		irq2dev_map[dev->irq] = 0;
+		return -EAGAIN;
+	}
+
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
+	MOD_INC_USE_COUNT;
+
+	init_i596(dev);
+
+	return 0;			/* Always succeed */
+}
+
+static int
+i596_start_xmit(struct sk_buff *skb, struct device *dev) {
+	volatile struct i596_private *lp = (struct i596_private *)dev->priv;
+	int ioaddr = dev->base_addr;
+	struct tx_cmd *tx_cmd;
+
+	/* Transmitter timeout, serious problems. */
+	if (dev->tbusy) {
+		int tickssofar = jiffies - dev->trans_start;
+		if (tickssofar < 5) {
+			return 1;
+		}
+		printk("%s: transmit timed out, status resetting.\n",
+		       dev->name);
+		lp->stats.tx_errors++;
+		/* Try to restart the adaptor */
+		if (lp->last_restart == lp->stats.tx_packets) {
+			printk ("Resetting board.\n");
+
+			/* Shutdown and restart */
+			i596_reset(dev,lp, ioaddr);
+		} else {
+			/* Issue a channel attention signal */
+			printk ("Kicking board.\n");
+
+			lp->scb.command = (CUC_START | RX_START);
+			CA(); /*outw(0, ioaddr+4);*/
+
+			lp->last_restart = lp->stats.tx_packets;
+		}
+		dev->tbusy = 0;
+		dev->trans_start = jiffies;
+	}
+
+	/* If some higher level thinks we've missed a tx-done interrupt
+	we are passed NULL. n.b. dev_tint handles the cli()/sti()
+	itself. */
+	if (skb == NULL) {
+		printk("What about dev_tint\n");
+		/*dev_tint(dev);*/
+		return 0;
+	}
+
+	/* shouldn't happen */
+	if (skb->len <= 0) return 0;
+
+	/* Block a timer-based transmit from overlapping.  This could better be
+	done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
+		printk("%s: Transmitter access conflict.\n", dev->name);
+	} else {
+		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+		dev->trans_start = jiffies;
+
+		tx_cmd = (struct tx_cmd *)
+			kmalloc ((sizeof (struct tx_cmd)
+				  + sizeof (struct i596_tbd)), GFP_ATOMIC);
+		if (tx_cmd == NULL) {
+			printk ("%s: i596_xmit Memory squeeze, dropping packet.\n",
+				dev->name);
+			lp->stats.tx_dropped++;
+
+			dev_kfree_skb(skb);
+		} else {
+			struct i596_tbd * tx_cmd_tbd;
+			tx_cmd_tbd = (struct i596_tbd *) (tx_cmd+1);
+			tx_cmd->pa_tbd = va_to_pa(tx_cmd_tbd);
+			tx_cmd_tbd->pa_next = I596_NULL;
+
+			tx_cmd->cmd.command = (CMD_FLEX | CmdTx);
+
+			tx_cmd->pad = 0;
+			tx_cmd->size = 0;
+			tx_cmd_tbd->pad = 0;
+			tx_cmd_tbd->size = (EOF | length);
+
+			tx_cmd_tbd->pa_data = va_to_pa(skb->data);
+			tx_cmd_tbd->skb = skb;
+
+			if (i596_debug & LOG_SRCDST)
+				print_eth(skb->data);
+
+			i596_add_cmd(dev, (struct i596_cmd *)tx_cmd);
+
+			lp->stats.tx_packets++;
+		}
+	}
+
+	dev->tbusy = 0;
+
+	return 0;
+}
+
+static void
+print_eth(char *add) {
+	int i;
+
+	printk ("Dest  ");
+	for (i = 0; i < 6; i++)
+		printk(" %2.2X", (unsigned char) add[i]);
+	printk ("\n");
+
+	printk ("Source");
+	for (i = 0; i < 6; i++)
+		printk(" %2.2X", (unsigned char) add[i+6]);
+	printk ("\n");
+
+	printk ("type %2.2X%2.2X\n",
+		(unsigned char) add[12], (unsigned char) add[13]);
+}
+
+int __init
+lp486e_probe(struct device *dev) {
+	volatile struct i596_private *lp;
+	unsigned char eth_addr[6] = { 0, 0xaa, 0, 0, 0, 0 };
+	unsigned char *bios;
+	int i,j;
+	static int probed = 0;
+
+	if (probed)
+		return -ENODEV;
+	probed++;
+
+	if (check_region(IOADDR, LP486E_TOTAL_SIZE)) {
+		printk("lp486e: IO address 0x%x in use\n", IOADDR);
+		return -ENODEV;
+	}
+
+	/*
+	 * Allocate working memory, 16-byte aligned
+	 */
+	dev->mem_start = (unsigned long)
+		kmalloc(sizeof(struct i596_private) + 0x0f, GFP_KERNEL);
+	if (!dev->mem_start)
+		return -ENOMEM;
+	dev->priv = (void *)((dev->mem_start + 0xf) & 0xfffffff0);
+	lp = (struct i596_private *) dev->priv;
+	memset((void *)lp, 0, sizeof(struct i596_private));
+
+	/*
+	 * Do we really have this thing?
+	 */
+	if (i596_scp_setup(dev)) {
+		kfree ((void *) dev->mem_start);
+		return -ENODEV;
+	}
+
+	request_region(IOADDR, LP486E_TOTAL_SIZE, "lp486e");
+
+	dev->base_addr = IOADDR;
+	dev->irq = IRQ;
+
+	ether_setup(dev);
+
+	/*
+	 * How do we find the ethernet address? I don't know.
+	 * One possibility is to look at the EISA configuration area
+	 * [0xe8000-0xe9fff]. This contains the ethernet address
+	 * but not at a fixed address - things depend on setup options.
+	 *
+	 * If we find no address, or the wrong address, use
+	 *   ifconfig eth0 hw ether a1:a2:a3:a4:a5:a6
+	 * with the value found in the BIOS setup.
+	 */
+	bios = bus_to_virt(0xe8000);
+	for (j = 0; j < 0x2000; j++) {
+		if (bios[j] == 0 && bios[j+1] == 0xaa && bios[j+2] == 0) {
+			printk("%s: maybe address at BIOS 0x%x:",
+			       dev->name, 0xe8000+j);
+			for (i = 0; i < 6; i++) {
+				eth_addr[i] = bios[i+j];
+				printk(" %2.2X", eth_addr[i]);
+			}
+			printk("\n");
+		}
+	}
+
+	printk("%s: lp486e 82596 at %#3x, IRQ %d,", dev->name, IOADDR, IRQ);
+	for (i = 0; i < 6; i++)
+		printk(" %2.2X", dev->dev_addr[i] = eth_addr[i]);
+	printk("\n");
+
+	/* The LP486E-specific entries in the device structure. */
+	dev->open = &i596_open;
+	dev->stop = &i596_close;
+	dev->hard_start_xmit = &i596_start_xmit;
+	dev->get_stats = &i596_get_stats;
+	dev->set_multicast_list = &set_multicast_list;
+
+#if 0
+	/* selftest reports 0x320925ae - don't know what that means */
+	i596_port_do(dev, PORT_SELFTEST, "selftest");
+	i596_port_do(dev, PORT_DUMP, "dump");
+#endif
+	return 0;
+}
+
+static void inline
+i596_handle_CU_completion(struct device *dev,
+			  volatile struct i596_private *lp,
+			  unsigned short status,
+			  unsigned short *ack_cmdp) {
+	volatile struct i596_cmd *cmd;
+	int frames_out = 0;
+	int commands_done = 0;
+	int cmd_val;
+
+	cmd = lp->cmd_head;
+
+	while (lp->cmd_head && (lp->cmd_head->status & CMD_STAT_C)) {
+		cmd = lp->cmd_head;
+
+		lp->cmd_head = pa_to_va(lp->cmd_head->pa_next);
+		lp->cmd_backlog--;
+
+		commands_done++;
+		cmd_val = cmd->command & 0x7;
+#if 0
+		printk("finished CU %s command (%d)\n",
+		       CUcmdnames[cmd_val], cmd_val);
+#endif
+		switch (cmd_val) {
+		case CmdTx:
+		{
+			struct tx_cmd *tx_cmd;
+			struct i596_tbd *tx_cmd_tbd;
+
+			tx_cmd = (struct tx_cmd *) cmd;
+			tx_cmd_tbd = pa_to_va(tx_cmd->pa_tbd);
+
+			frames_out++;
+			if (cmd->status & CMD_STAT_OK) {
+				if (i596_debug)
+					print_eth(pa_to_va(tx_cmd_tbd->pa_data));
+			} else {
+				lp->stats.tx_errors++;
+				if (i596_debug)
+					printk("transmission failure:%04x\n",
+					       cmd->status);
+				if (cmd->status & 0x0020)
+					lp->stats.collisions++;
+				if (!(cmd->status & 0x0040))
+					lp->stats.tx_heartbeat_errors++;
+				if (cmd->status & 0x0400)
+					lp->stats.tx_carrier_errors++;
+				if (cmd->status & 0x0800)
+					lp->stats.collisions++;
+				if (cmd->status & 0x1000)
+					lp->stats.tx_aborted_errors++;
+			}
+			dev_kfree_skb(tx_cmd_tbd->skb);
+
+			cmd->pa_next = I596_NULL;
+			kfree((unsigned char *)tx_cmd);
+			break;
+		}
+
+		case CmdMulticastList:
+			cmd->pa_next = I596_NULL;
+			kfree((unsigned char *)cmd);
+			break;
+
+		case CmdTDR:
+		{
+			unsigned long status = *((unsigned long *) (cmd + 1));
+			if (status & 0x8000) {
+				if (i596_debug)
+					printk("%s: link ok.\n", dev->name);
+			} else {
+				if (status & 0x4000)
+					printk("%s: Transceiver problem.\n",
+					       dev->name);
+				if (status & 0x2000)
+					printk("%s: Termination problem.\n",
+					       dev->name);
+				if (status & 0x1000)
+					printk("%s: Short circuit.\n",
+					       dev->name);
+				printk("%s: Time %ld.\n",
+				       dev->name, status & 0x07ff);
+			}
+		}
+		default:
+			cmd->pa_next = I596_NULL;
+			lp->last_cmd = jiffies;
+			
+		}
+	}
+
+	cmd = lp->cmd_head;
+	while (cmd && (cmd != lp->cmd_tail)) {
+		cmd->command &= 0x1fff;
+		cmd = pa_to_va(cmd->pa_next);
+	}
+
+	if (lp->cmd_head && dev->start)
+		*ack_cmdp |= CUC_START;
+	lp->scb.pa_cmd = va_to_pa(lp->cmd_head);
+}
+
+static void
+i596_interrupt (int irq, void *dev_instance, struct pt_regs *regs) {
+	struct device *dev = (struct device *) dev_instance;
+	volatile struct i596_private *lp;
+	unsigned short status, ack_cmd = 0;
+	int frames_in = 0;
+
+	if (dev == NULL) {
+		printk ("i596_interrupt(): irq %d for unknown device.\n", irq);
+		return;
+	}
+
+	if (dev->interrupt)
+		printk("%s: Re-entering the interrupt handler.\n", dev->name);
+	dev->interrupt = 1;
+
+	lp = (struct i596_private *) dev->priv;
+
+	/*
+	 * The 82596 examines the command, performs the required action,
+	 * and then clears the SCB command word.
+	 */
+	if (lp->scb.command && i596_timeout(dev, "interrupt", 40))
+		;
+
+	/*
+	 * The status word indicates the status of the 82596.
+	 * It is modified only by the 82596.
+	 *
+	 * [So, we must not clear it. I find often status 0xffff,
+	 *  which is not one of the values allowed by the docs.]
+	 */
+	status = lp->scb.status;
+#if 0
+	if (i596_debug) {
+		printk("%s: i596 interrupt, ", dev->name);
+		i596_out_status(status);
+	}
+#endif
+	/* Impossible, but it happens - perhaps when we get
+	   a receive interrupt but scb.pa_rfd is I596_NULL. */
+	if (status == 0xffff) {
+		printk("%s: i596_interrupt: got status 0xffff\n", dev->name);
+		goto out;
+	}
+
+	ack_cmd = (status & STAT_ACK);
+
+	if (status & (STAT_CX | STAT_CNA))
+		i596_handle_CU_completion(dev, lp, status, &ack_cmd);
+
+	if (status & (STAT_FR | STAT_RNR)) {
+		/* Restart the receive unit when it got inactive somehow */
+		if ((status & STAT_RNR) && dev->start)
+			ack_cmd |= RX_START;
+
+		if (status & STAT_FR) {
+			frames_in = i596_rx(dev);
+			if (!frames_in)
+				printk("receive frame reported, but no frames\n");
+		}
+	}
+
+	/* acknowledge the interrupt */
+	/*
+	if ((lp->scb.pa_cmd != I596_NULL) && dev->start)
+		ack_cmd |= CUC_START;
+	*/
+
+	if (lp->scb.command && i596_timeout(dev, "i596 interrupt", 100))
+		;
+
+	lp->scb.command = ack_cmd;
+
+	CLEAR_INT();
+	CA();
+
+ out:
+	dev->interrupt = 0;
+	return;
+}
+
+static int i596_close(struct device *dev) {
+	volatile struct i596_private *lp = (struct i596_private *)dev->priv;
+
+	dev->start = 0;
+	dev->tbusy = 1;
+
+	if (i596_debug)
+		printk("%s: Shutting down ethercard, status was %4.4x.\n",
+		       dev->name, lp->scb.status);
+
+	lp->scb.command = (CUC_ABORT | RX_ABORT);
+	CA();
+
+	i596_cleanup_cmd(dev);
+
+	if (lp->scb.command && i596_timeout(dev, "i596_close", 200))
+		;
+
+	free_irq(dev->irq, dev);
+	remove_rx_bufs(dev);
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+static struct enet_statistics * i596_get_stats(struct device *dev) {
+	struct i596_private *lp = (struct i596_private *)dev->priv;
+
+	return &lp->stats;
+}
+
+/*
+*	Set or clear the multicast filter for this adaptor.
+*/
+
+static void set_multicast_list(struct device *dev) {
+	volatile struct i596_private *lp = (struct i596_private *)dev->priv;
+	struct i596_cmd *cmd;
+
+	if (i596_debug > 1)
+		printk ("%s: set multicast list %d\n",
+			dev->name, dev->mc_count);
+
+	if (dev->mc_count > 0) {
+		struct dev_mc_list *dmi;
+		char *cp;
+		cmd = (struct i596_cmd *)
+			kmalloc(sizeof(struct i596_cmd)+2+dev->mc_count*6,
+				GFP_ATOMIC);
+		if (cmd == NULL) {
+			printk ("%s: set_multicast Memory squeeze.\n",
+				dev->name);
+			return;
+		}
+		cmd->command = CmdMulticastList;
+		*((unsigned short *) (cmd + 1)) = dev->mc_count * 6;
+		cp = ((char *)(cmd + 1))+2;
+		for (dmi = dev->mc_list; dmi != NULL; dmi = dmi->next) {
+			memcpy(cp, dmi,6);
+			cp += 6;
+		}
+		if (i596_debug & LOG_SRCDST)
+			print_eth (((char *)(cmd + 1)) + 2);
+		i596_add_cmd(dev, cmd);
+	} else {
+		if (lp->set_conf.pa_next != I596_NULL) {
+			return;
+		}
+		if (dev->mc_count == 0 &&
+		    !(dev->flags & (IFF_PROMISC | IFF_ALLMULTI))) {
+			if (dev->flags & IFF_ALLMULTI)
+				dev->flags |= IFF_PROMISC;
+			lp->i596_config[8] &= ~0x01;
+		} else {
+			lp->i596_config[8] |= 0x01;
+		}
+
+		i596_add_cmd(dev, (struct i596_cmd *) &lp->set_conf);
+	}
+}
+
+#ifdef HAVE_DEVLIST
+static unsigned int lp486e_portlist[] = {0xcb0, 0};
+struct netdev_entry lp486e_drv = {
+	"lp486e",
+	lp486e_probe,
+	LP486E_TOTAL_SIZE,
+	lp486e_portlist
+};
+#endif
+
+#ifdef MODULE
+MODULE_AUTHOR("Ard van Breemen <ard@cstmel.nl.eu.org>");
+MODULE_DESCRIPTION("Intel Panther onboard i82596 driver");
+MODULE_PARM(debug, "i");
+//MODULE_PARM(max_interrupt_work, "i");
+//MODULE_PARM(reverse_probe, "i");
+//MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+
+static char devicename[9] = { 0, };
+static struct device dev_lp486e = {
+	devicename, /* device name inserted by /linux/drivers/net/net_init.c */
+	0, 0, 0, 0,
+	IOADDR, IRQ,
+	0, 0, 0, NULL, NULL
+};
+
+static int full_duplex;
+static int options;
+static int io = IOADDR;
+static int irq = IRQ;
+
+int init_module(void) {
+	struct device *dev = &dev_lp486e;
+	dev->name = devicename;
+	dev->irq = irq;
+	dev->base_addr = io;
+	dev->init = lp486e_probe;
+	if (register_netdev(dev) != 0) {
+		return -EIO;
+	}
+	full_duplex = 0;
+	options = 0;
+	return 0;
+}
+
+void cleanup_module(void) {
+	unregister_netdev(&dev_lp486e);
+	kfree((void *)dev_lp486e.mem_start);
+	dev_lp486e.priv = NULL;
+	/* If we don't do this, we can't re-insmod it later. */
+	release_region(dev_lp486e.base_addr, LP486E_TOTAL_SIZE);
+}
+#endif /* MODULE */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/ne2k-pci.c linux.19p18/drivers/net/ne2k-pci.c
--- linux.vanilla/drivers/net/ne2k-pci.c	Fri Apr 21 12:46:19 2000
+++ linux.19p18/drivers/net/ne2k-pci.c	Tue Jan  9 12:03:38 2001
@@ -12,19 +12,30 @@
 	This software may be used and distributed according to the terms
 	of the GNU Public License, incorporated herein by reference.
 
-	The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
-	Center of Excellence in Space Data and Information Sciences
-	Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+	Drivers based on or derived from this code fall under the GPL and must
+	retain the authorship, copyright and license notice.  This file is not
+	a complete program and may only be used when the entire operating
+	system is licensed under the GPL.
+
+	The author may be reached as becker@scyld.com, or C/O
+	Scyld Computing Corporation
+	410 Severn Ave., Suite 210
+	Annapolis MD 21403
 
+	Issues remaining:
 	People are making PCI ne2000 clones! Oh the horror, the horror...
+	Limited full-duplex support.
 
-	Issues remaining:
-	No full-duplex support.
+	ChangeLog:
+
+	12/15/2000 Merged Scyld v1.02 into 2.2.18
+									J.A. Magallon <jamagallon@able.es>
 */
 
-/* Our copyright info must remain in the binary. */
-static const char *version =
-"ne2k-pci.c:vpre-1.00e 5/27/99 D. Becker/P. Gortmaker http://cesdis.gsfc.nasa.gov/linux/drivers/ne2k-pci.html\n";
+/* These identify the driver base version and may not be removed. */
+static const char* version =
+"ne2k-pci.c: v1.02 for Linux 2.2, 10/19/2000, D. Becker/P. Gortmaker,"
+" http://www.scyld.com/network/ne2k-pci.html";
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -49,7 +60,18 @@
 #endif
 
 /* Set statically or when loading the driver module. */
-static int debug = 1;
+static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */
+/* More are supported, limit only on options */
+#define MAX_UNITS 6
+/* Used to pass the full-duplex flag, etc. */
+static int full_duplex[MAX_UNITS] = {0, };
+static int options[MAX_UNITS] = {0, };
+
+MODULE_AUTHOR("Donald Becker / Paul Gortmaker");
+MODULE_DESCRIPTION("PCI NE2000 clone driver");
+MODULE_PARM(debug, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
 
 /* Some defines that people can play with if so inclined. */
 
@@ -62,12 +84,13 @@
 /* Do we have a non std. amount of memory? (in units of 256 byte pages) */
 /* #define PACKETBUF_MEMSIZE	0x40 */
 
-#define ne2k_flags reg0			/* Rename an existing field to store flags! */
-
-/* Only the low 8 bits are usable for non-init-time flags! */
+/* Flags.  We rename an existing ei_status field to store flags! */
+/* Thus only the low 8 bits are usable for non-init-time flags. */
+#define ne2k_flags reg0
 enum {
-	HOLTEK_FDX=1, 		/* Full duplex -> set 0x80 at offset 0x20. */
-	ONLY_16BIT_IO=2, ONLY_32BIT_IO=4,	/* Chip can do only 16/32-bit xfers. */
+	ONLY_16BIT_IO=8, ONLY_32BIT_IO=4,   /* Chip can do only 16/32-bit xfers. */
+	FORCE_FDX=0x20,                     /* User override. */
+	REALTEK_FDX=0x40, HOLTEK_FDX=0x80,
 	STOP_PG_0x60=0x100,
 };
 
@@ -79,18 +102,17 @@
 	int flags;
 }
 pci_clone_list[] __initdata = {
-	{0x10ec, 0x8029, "RealTek RTL-8029", 0},
-	{0x1050, 0x0940, "Winbond 89C940", 0},
-	{0x11f6, 0x1401, "Compex RL2000", 0},
-	{0x8e2e, 0x3000, "KTI ET32P2", 0},
-	{0x4a14, 0x5000, "NetVin NV5000SC", 0},
-	{0x1106, 0x0926, "Via 86C926", ONLY_16BIT_IO},
-	{0x10bd, 0x0e34, "SureCom NE34", 0},
-	{0x1050, 0x5a5a, "Winbond", 0},
-	{0x12c3, 0x0058, "Holtek HT80232", ONLY_16BIT_IO | HOLTEK_FDX},
-	{0x12c3, 0x5598, "Holtek HT80229",
-	 ONLY_32BIT_IO | HOLTEK_FDX | STOP_PG_0x60 },
-	{0,}
+{0x10ec, 0x8029, "RealTek RTL-8029", REALTEK_FDX},
+{0x1050, 0x0940, "Winbond 89C940", 0},
+{0x1050, 0x5a5a, "Winbond w89c940", 0},
+{0x8e2e, 0x3000, "KTI ET32P2", 0},
+{0x4a14, 0x5000, "NetVin NV5000SC", 0},
+{0x1106, 0x0926, "Via 86C926", ONLY_16BIT_IO},
+{0x10bd, 0x0e34, "SureCom NE34", 0},
+{0x12c3, 0x0058, "Holtek HT80232", ONLY_16BIT_IO|HOLTEK_FDX},
+{0x12c3, 0x5598, "Holtek HT80229", ONLY_32BIT_IO|HOLTEK_FDX|STOP_PG_0x60 },
+{0x11f6, 0x1401, "Compex RL2000", 0},
+{0,}
 };
 
 /* ---- No user-serviceable parts below ---- */
@@ -119,7 +141,7 @@
 static void ne2k_pci_block_output(struct device *dev, const int count,
 		const unsigned char *buf, const int start_page);
 
-
+
 
 /* No room in the standard 8390 structure for extra info we need. */
 struct ne2k_pci_card {
@@ -136,8 +158,7 @@
 init_module(void)
 {
 	/* We must emit version information. */
-	if (debug)
-		printk(KERN_INFO "%s", version);
+	printk(KERN_INFO "%s\n", version);
 
 	if (ne2k_pci_probe(0)) {
 		printk(KERN_NOTICE "ne2k-pci.c: No useable cards found, driver NOT installed.\n");
@@ -220,7 +241,7 @@
 		{
 			static unsigned version_printed = 0;
 			if (version_printed++ == 0)
-				printk(KERN_INFO "%s", version);
+				printk(KERN_INFO "%s\n", version);
 		}
 #endif
 
@@ -263,8 +284,8 @@
 	return cards_found ? 0 : -ENODEV;
 }
 
-__initfunc (static struct device *ne2k_pci_probe1(struct device *dev, long ioaddr, int irq,
-									  int chip_idx))
+__initfunc (static struct device *ne2k_pci_probe1(struct device *dev,
+			long ioaddr, int irq, int chip_idx))
 {
 	int i;
 	unsigned char SA_prom[32];
@@ -291,6 +312,8 @@
 
 	dev = init_etherdev(dev, 0);
 
+	if (!dev) return 0;
+
 	/* Reset card. Who knows what dain-bramaged state it was left in. */
 	{
 		unsigned long reset_start_time = jiffies;
@@ -342,7 +365,7 @@
 	/* Note: all PCI cards have at least 16 bit access, so we don't have
 	   to check for 8 bit cards.  Most cards permit 32 bit access. */
 	if (pci_clone_list[chip_idx].flags & ONLY_32BIT_IO) {
-		for (i = 0; i < 4 ; i++)
+		for (i = 0; i < 8 ; i++)
 			((u32 *)SA_prom)[i] = le32_to_cpu(inl(ioaddr + NE_DATAPORT));
 	} else
 		for(i = 0; i < 32 /*sizeof(SA_prom)*/; i++)
@@ -379,6 +402,10 @@
 	ei_status.stop_page = stop_page;
 	ei_status.word16 = 1;
 	ei_status.ne2k_flags = pci_clone_list[chip_idx].flags;
+	if (chip_idx < MAX_UNITS) {
+		if (full_duplex[chip_idx]  ||  (options[chip_idx] & FORCE_FDX))
+			ei_status.ne2k_flags |= FORCE_FDX;
+	}
 
 	ei_status.rx_start_page = start_page + TX_PAGES;
 #ifdef PACKETBUF_MEMSIZE
@@ -401,8 +428,17 @@
 {
 	if (request_irq(dev->irq, ei_interrupt, SA_SHIRQ, dev->name, dev))
 		return -EAGAIN;
-	ei_open(dev);
 	MOD_INC_USE_COUNT;
+	/* Set full duplex for the chips that we know about. */
+	if (ei_status.ne2k_flags & FORCE_FDX) {
+		long ioaddr = dev->base_addr;
+		if (ei_status.ne2k_flags & REALTEK_FDX) {
+			outb(0xC0 + E8390_NODMA, ioaddr + NE_CMD); /* Page 3 */
+			outb(inb(ioaddr + 0x20) | 0x80, ioaddr + 0x20);
+		} else if (ei_status.ne2k_flags & HOLTEK_FDX)
+			outb(inb(ioaddr + 0x20) | 0x80, ioaddr + 0x20);
+	}
+	ei_open(dev);
 	return 0;
 }
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/sis900.c linux.19p18/drivers/net/sis900.c
--- linux.vanilla/drivers/net/sis900.c	Mon Dec 11 22:12:49 2000
+++ linux.19p18/drivers/net/sis900.c	Sat Mar 10 23:14:04 2001
@@ -1,6 +1,6 @@
 /* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux.
    Copyright 1999 Silicon Integrated System Corporation 
-   Revision:	1.06.05	Aug 24 2000
+   Revision:	1.06.07	Jan. 8 2001
 
    Modified from the driver which is originally written by Donald Becker.
    
@@ -18,6 +18,8 @@
    preliminary Rev. 1.0 Jan. 18, 1998
    http://www.sis.com.tw/support/databook.htm
 
+   Rev 1.06.07 Jan.  8 2001 Lei-Chun Chang added RTL8201 PHY support
+   Rev 1.06.06 Sep.  6 2000 Lei-Chun Chang added ICS1893 PHY support
    Rev 1.06.05 Aug. 22 2000 Lei-Chun Chang (lcchang@sis.com.tw) modified 630E equalier workaroung rule
    Rev 1.06.03 Dec. 23 1999 Ollie Lho Third release
    Rev 1.06.02 Nov. 23 1999 Ollie Lho bug in mac probing fixed
@@ -51,7 +53,7 @@
 #include "sis900.h"
 
 static const char *version =
-"sis900.c: v1.06.05  08/24/00\n";
+"sis900.c: v1.06.07  01/08/01\n";
 
 static int max_interrupt_work = 20;
 static int multicast_filter_limit = 128;
@@ -82,6 +84,8 @@
 
 static void sis900_read_mode(struct device *net_dev, int phy_addr, int *speed, int *duplex);
 static void amd79c901_read_mode(struct device *net_dev, int phy_addr, int *speed, int *duplex);
+static void ics1893_read_mode(struct device *net_dev, int phy_addr, int *speed, int *duplex);
+static void rtl8201_read_mode(struct device *net_dev, int phy_addr, int *speed, int *duplex);
 
 static struct mii_chip_info {
 	const char * name;
@@ -93,6 +97,8 @@
 	{"SiS 7014 Physical Layer Solution", 0x0016, 0xf830,sis900_read_mode},
 	{"AMD 79C901 10BASE-T PHY",  0x0000, 0x35b9, amd79c901_read_mode},
 	{"AMD 79C901 HomePNA PHY",   0x0000, 0x35c8, amd79c901_read_mode},
+	{"ICS 1893 Integrated PHYceiver"   , 0x0015, 0xf441,ics1893_read_mode},
+	{"RTL 8201 10/100Mbps Phyceiver"   , 0x0000, 0x8201,rtl8201_read_mode},
 	{0,},
 };
 
@@ -299,12 +305,10 @@
 		return NULL;
 
 	pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision);
-	if (revision == SIS630E_REV)
+	if (revision == SIS630E_REV || revision == SIS630EA1_REV)
 		ret = sis630e_get_mac_addr(pci_dev, net_dev);
-	else if (revision == SIS630EA1_REV) {
+	else if (revision == SIS630S_REV)
 		ret = sis630e_get_mac_addr(pci_dev, net_dev);
-		printk(KERN_INFO "using 630ea1\n");
-	}
 	else
 		ret = sis900_get_mac_addr(pci_dev, net_dev);
 
@@ -381,7 +385,8 @@
 
 		/* search our mii table for the current mii */ 
 		for (i = 0; mii_chip_table[i].phy_id1; i++)
-			if (phy_id0 == mii_chip_table[i].phy_id0) {
+			if (phy_id0 == mii_chip_table[i].phy_id0 &&
+			    phy_id1 == mii_chip_table[i].phy_id1) {
 				struct mii_phy * mii_phy;
 
 				printk(KERN_INFO
@@ -956,6 +961,71 @@
 			printk(KERN_INFO "%s: Media Link Off\n", net_dev->name);
 	}
 }
+/* ICS1893 PHY use Quick Poll Detailed Status Register to get its status */
+static void ics1893_read_mode(struct device *net_dev, int phy_addr, int *speed, int *duplex)
+{
+	int i = 0;
+	u32 status;
+
+	/* MII_QPDSTS is Latched, read twice in succession will reflect the current state */
+	for (i = 0; i < 2; i++)
+		status = mdio_read(net_dev, phy_addr, MII_QPDSTS);
+
+	if (status & MII_STSICS_SPD)
+		*speed = HW_SPEED_100_MBPS;
+	else
+		*speed = HW_SPEED_10_MBPS;
+
+	if (status & MII_STSICS_DPLX)
+		*duplex = FDX_CAPABLE_FULL_SELECTED;
+	else
+		*duplex = FDX_CAPABLE_HALF_SELECTED;
+
+	if (status & MII_STSICS_LINKSTS)
+		printk(KERN_INFO "%s: Media Link On %s %s-duplex \n",
+		       net_dev->name,
+		       *speed == HW_SPEED_100_MBPS ?
+		       "100mbps" : "10mbps",
+		       *duplex == FDX_CAPABLE_FULL_SELECTED ?
+		       "full" : "half");
+	else
+		printk(KERN_INFO "%s: Media Link Off\n", net_dev->name);
+}
+
+static void rtl8201_read_mode(struct device *net_dev, int phy_addr, int *speed, int *duplex)
+{
+	u32 status;
+
+	status = mdio_read(net_dev, phy_addr, MII_STATUS);
+
+	if (status & MII_STAT_CAN_TX_FDX) {
+		*speed = HW_SPEED_100_MBPS;
+		*duplex = FDX_CAPABLE_FULL_SELECTED;
+	}
+	else if (status & MII_STAT_CAN_TX) {
+		*speed = HW_SPEED_100_MBPS;
+		*duplex = FDX_CAPABLE_HALF_SELECTED;
+	}
+	else if (status & MII_STAT_CAN_T_FDX) {
+		*speed = HW_SPEED_10_MBPS;
+		*duplex = FDX_CAPABLE_FULL_SELECTED;
+	}
+	else if (status & MII_STAT_CAN_T) {
+		*speed = HW_SPEED_10_MBPS;
+		*duplex = FDX_CAPABLE_HALF_SELECTED;
+	}
+
+	if (status & MII_STAT_LINK)
+		printk(KERN_INFO "%s: Media Link On %s %s-duplex \n",
+		       net_dev->name,
+		       *speed == HW_SPEED_100_MBPS ?
+		       "100mbps" : "10mbps",
+		       *duplex == FDX_CAPABLE_FULL_SELECTED ?
+		       "full" : "half");
+	else
+		printk(KERN_INFO "%s: Media Link Off\n", net_dev->name);
+}
+
 static void sis900_tx_timeout(struct device *net_dev)
 {
 	struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/sis900.h linux.19p18/drivers/net/sis900.h
--- linux.vanilla/drivers/net/sis900.h	Mon Dec 11 22:12:49 2000
+++ linux.19p18/drivers/net/sis900.h	Thu Feb  1 14:54:10 2001
@@ -168,6 +168,12 @@
 	MII_MASK    = 0x0013, MII_RESV    = 0x0014
 };
 
+/* mii registers specific to ICS 1893 */
+enum ics_mii_registers {
+	MII_EXTCTRL  = 0x0010, MII_QPDSTS = 0x0011, MII_10BTOP = 0x0012,
+	MII_EXTCTRL2 = 0x0013
+};
+
 /* mii registers specific to AMD 79C901 */
 enum amd_mii_registers {
 	MII_STATUS_SUMMARY = 0x0018
@@ -212,13 +218,19 @@
 	MII_STSOUT_SPD       = 0x0080, MII_STSOUT_DPLX = 0x0040
 };
 
+enum mii_stsics_register_bits {
+	MII_STSICS_SPD  = 0x8000, MII_STSICS_DPLX = 0x4000,
+	MII_STSICS_LINKSTS = 0x0001
+};
+
 enum mii_stssum_register_bits {
 	MII_STSSUM_LINK = 0x0008, MII_STSSUM_DPLX = 0x0004,
 	MII_STSSUM_AUTO = 0x0002, MII_STSSUM_SPD  = 0x0001
 };
 
 enum sis630_revision_id {
-	SIS630E_REV = 0x81, SIS630EA1_REV = 0x83
+	SIS630E_REV = 0x81, SIS630EA1_REV = 0x83,
+	SIS630S_REV = 0x82
 };
 
 #define FDX_CAPABLE_DUPLEX_UNKNOWN      0
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/slhc.c linux.19p18/drivers/net/slhc.c
--- linux.vanilla/drivers/net/slhc.c	Sat Sep  9 18:42:40 2000
+++ linux.19p18/drivers/net/slhc.c	Tue Feb 20 13:24:49 2001
@@ -82,8 +82,6 @@
 #include <net/checksum.h>
 #include <asm/unaligned.h>
 
-int last_retran;
-
 static unsigned char *encode(unsigned char *cp, unsigned short n);
 static long decode(unsigned char **cpp);
 static unsigned char * put16(unsigned char *cp, unsigned short x);
@@ -257,8 +255,7 @@
 	ip = (struct iphdr *) icp;
 
 	/* Bail if this packet isn't TCP, or is an IP fragment */
-	if(ip->protocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x1fff) ||
-				       (ip->frag_off & 32)){
+	if (ip->protocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x3fff)) {
 		/* Send as regular IP */
 		if(ip->protocol != IPPROTO_TCP)
 			comp->sls_o_nontcp++;
@@ -352,10 +349,9 @@
 	 */
 	oth = &cs->cs_tcp;
 
-	if(last_retran
-	 || ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl
+	if(ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl
 	 || ip->tos != cs->cs_ip.tos
-	 || (ip->frag_off & 64) != (cs->cs_ip.frag_off & 64)
+	 || (ip->frag_off & htons(0x4000)) != (cs->cs_ip.frag_off & htons(0x4000))
 	 || ip->ttl != cs->cs_ip.ttl
 	 || th->doff != cs->cs_tcp.doff
 	 || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/starfire.c linux.19p18/drivers/net/starfire.c
--- linux.vanilla/drivers/net/starfire.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/net/starfire.c	Sat Mar 10 23:12:48 2001
@@ -0,0 +1,1854 @@
+/* starfire.c: Linux device driver for the Adaptec Starfire network adapter. */
+/*
+	Written 1998-2000 by Donald Becker.
+
+	This software may be used and distributed according to the terms of
+	the GNU General Public License (GPL), incorporated herein by reference.
+	Drivers based on or derived from this code fall under the GPL and must
+	retain the authorship, copyright and license notice.  This file is not
+	a complete program and may only be used when the entire operating
+	system is licensed under the GPL.
+
+	The author may be reached as becker@scyld.com, or C/O
+	Scyld Computing Corporation
+	410 Severn Ave., Suite 210
+	Annapolis MD 21403
+
+	Support and updates available at
+	http://www.scyld.com/network/starfire.html
+
+	-----------------------------------------------------------
+
+	Linux kernel-specific changes:
+
+	LK1.1.1 (jgarzik):
+	- Use PCI driver interface
+	- Fix MOD_xxx races
+	- softnet fixups
+
+	LK1.1.2 (jgarzik):
+	- Merge Becker version 0.15
+
+	LK1.1.3 (Andrew Morton)
+	- Timer cleanups
+
+	LK1.1.4 (jgarzik):
+	- Merge Becker version 1.03
+
+	LK1.2.1 (Ion Badulescu <ionut@cs.columbia.edu>)
+	- Support hardware Rx/Tx checksumming
+	- Use the GFP firmware taken from Adaptec's Netware driver
+
+	LK1.2.2 (Ion Badulescu)
+	- Backported to 2.2.x
+
+	LK1.2.3 (Ion Badulescu)
+	- Fix the flaky mdio interface
+	- More compat clean-ups
+
+	LK1.2.4 (Ion Badulescu)
+	- More 2.2.x initialization fixes
+
+	LK1.2.5 (Ion Badulescu)
+	- Several fixes from Manfred Spraul
+
+	LK1.2.6 (Ion Badulescu)
+	- Fixed ifup/ifdown/ifup problem in 2.4.x
+
+	LK1.2.7 (Ion Badulescu)
+	- Removed unused code
+	- Made more functions static and __init
+
+	LK1.2.8 (Ion Badulescu)
+	- Quell bogus error messages, inform about the Tx threshold
+	- Removed #ifdef CONFIG_PCI, this driver is PCI only
+
+TODO:
+	- implement tx_timeout() properly
+	- support ethtool
+*/
+
+/* These identify the driver base version and may not be removed. */
+static const char version1[] =
+"starfire.c:v1.03 7/26/2000  Written by Donald Becker <becker@scyld.com>\n";
+static const char version2[] =
+" Updates and info at http://www.scyld.com/network/starfire.html\n";
+
+static const char version3[] =
+" (unofficial 2.2.x kernel port, version 1.2.8, March 7, 2001)\n";
+
+/* The user-configurable values.
+   These may be modified when a driver module is loaded.*/
+
+/*
+ * Adaptec's license for their Novell drivers (which is where I got the
+ * firmware files) does not allow to redistribute them. Thus, we can't
+ * include them with this driver.
+ *
+ * However, an end-user is allowed to download and use them, after
+ * converting them to C header files using starfire_firmware.pl.
+ * Once that's done, the #undef must be changed into a #define
+ * for this driver to really use the firmware. Note that Rx/Tx
+ * hardware TCP checksumming is not possible without the firmware.
+ *
+ * I'm currently [Feb 2001] talking to Adaptec about this redistribution
+ * issue. Stay tuned...
+ */
+#undef HAS_FIRMWARE
+/*
+ * The current frame processor firmware fails to checksum a fragment
+ * of length 1. If and when this is fixed, the #define below can be removed.
+ */
+#define HAS_BROKEN_FIRMWARE
+
+/* Used for tuning interrupt latency vs. overhead. */
+static int interrupt_mitigation = 0x0;
+
+static int debug = 1;			/* 1 normal messages, 0 quiet .. 7 verbose. */
+static int max_interrupt_work = 20;
+static int mtu = 0;
+/* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
+   The Starfire has a 512 element hash table based on the Ethernet CRC. */
+static int multicast_filter_limit = 32;
+
+#define PKT_BUF_SZ	1536		/* Size of each temporary Rx buffer.*/
+/*
+ * Set the copy breakpoint for the copy-only-tiny-frames scheme.
+ * Setting to > 1518 effectively disables this feature.
+ *
+ * NOTE:
+ * The ia64 doesn't allow for unaligned loads even of integers being
+ * misaligned on a 2 byte boundary. Thus always force copying of
+ * packets as the starfire doesn't allow for misaligned DMAs ;-(
+ * 23/10/2000 - Jes
+ *
+ * Neither does the Alpha. -Ion
+ */
+#if defined(__ia64__) || defined(__alpha__)
+static int rx_copybreak = PKT_BUF_SZ;
+#else
+static int rx_copybreak = 0;
+#endif
+
+/* Used to pass the media type, etc.
+   Both 'options[]' and 'full_duplex[]' exist for driver interoperability.
+   The media type is usually passed in 'options[]'.
+*/
+#define MAX_UNITS 8		/* More are supported, limit only on options */
+static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+
+/* Operational parameters that are set at compile time. */
+
+/* The "native" ring sizes are either 256 or 2048.
+   However in some modes a descriptor may be marked to wrap the ring earlier.
+   The driver allocates a single page for each descriptor ring, constraining
+   the maximum size in an architecture-dependent way.
+*/
+#define RX_RING_SIZE	256
+#define TX_RING_SIZE	32
+/* The completion queues are fixed at 1024 entries i.e. 4K or 8KB. */
+#define DONE_Q_SIZE	1024
+
+/* Operational parameters that usually are not changed. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT	(2*HZ)
+
+#define skb_first_frag_len(skb)	(skb->len)
+
+#if !defined(__OPTIMIZE__)
+#warning  You must compile this file with the correct options!
+#warning  See the last lines of the source file.
+#error You must compile this driver with "-O".
+#endif
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <asm/processor.h>		/* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+#ifdef HAS_FIRMWARE
+#include "starfire_firmware.h"
+#endif /* HAS_FIRMWARE */
+
+MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
+MODULE_DESCRIPTION("Adaptec Starfire Ethernet driver");
+MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(mtu, "i");
+MODULE_PARM(debug, "i");
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(interrupt_mitigation, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+
+/*
+				Theory of Operation
+
+I. Board Compatibility
+
+This driver is for the Adaptec 6915 "Starfire" 64 bit PCI Ethernet adapter.
+
+II. Board-specific settings
+
+III. Driver operation
+
+IIIa. Ring buffers
+
+The Starfire hardware uses multiple fixed-size descriptor queues/rings.  The
+ring sizes are set fixed by the hardware, but may optionally be wrapped
+earlier by the END bit in the descriptor.
+This driver uses that hardware queue size for the Rx ring, where a large
+number of entries has no ill effect beyond increases the potential backlog.
+The Tx ring is wrapped with the END bit, since a large hardware Tx queue
+disables the queue layer priority ordering and we have no mechanism to
+utilize the hardware two-level priority queue.  When modifying the
+RX/TX_RING_SIZE pay close attention to page sizes and the ring-empty warning
+levels.
+
+IIIb/c. Transmit/Receive Structure
+
+See the Adaptec manual for the many possible structures, and options for
+each structure.  There are far too many to document here.
+
+For transmit this driver uses type 0/1 transmit descriptors (depending
+on the presence of the zerocopy patches), and relies on automatic
+minimum-length padding.  It does not use the completion queue
+consumer index, but instead checks for non-zero status entries.
+
+For receive this driver uses type 0 receive descriptors.  The driver
+allocates full frame size skbuffs for the Rx ring buffers, so all frames
+should fit in a single descriptor.  The driver does not use the completion
+queue consumer index, but instead checks for non-zero status entries.
+
+When an incoming frame is less than RX_COPYBREAK bytes long, a fresh skbuff
+is allocated and the frame is copied to the new skbuff.  When the incoming
+frame is larger, the skbuff is passed directly up the protocol stack.
+Buffers consumed this way are replaced by newly allocated skbuffs in a later
+phase of receive.
+
+A notable aspect of operation is that unaligned buffers are not permitted by
+the Starfire hardware.  The IP header at offset 14 in an ethernet frame thus
+isn't longword aligned, which may cause problems on some machine
+e.g. Alphas and IA64. For these architectures, the driver is forced to copy
+the frame into a new skbuff unconditionally. Copied frames are put into the
+skbuff at an offset of "+2", thus 16-byte aligning the IP header.
+
+IIId. Synchronization
+
+The driver runs as two independent, single-threaded flows of control.  One
+is the send-packet routine, which enforces single-threaded use by the
+dev->tbusy flag.  The other thread is the interrupt handler, which is single
+threaded by the hardware and interrupt handling software.
+
+The send packet thread has partial control over the Tx ring and 'dev->tbusy'
+flag.  It sets the tbusy flag whenever it's queuing a Tx packet. If the next
+queue slot is empty, it clears the tbusy flag when finished otherwise it sets
+the 'lp->tx_full' flag.
+
+The interrupt handler has exclusive control over the Rx ring and records stats
+from the Tx ring.  After reaping the stats, it marks the Tx queue entry as
+empty by incrementing the dirty_tx mark. Iff the 'lp->tx_full' flag is set, it
+clears both the tx_full and tbusy flags.
+
+IV. Notes
+
+IVb. References
+
+The Adaptec Starfire manuals, available only from Adaptec.
+http://www.scyld.com/expert/100mbps.html
+http://www.scyld.com/expert/NWay.html
+
+IVc. Errata
+
+*/
+
+
+
+/* 2.2.x compatibility code */
+#if LINUX_VERSION_CODE < 0x20300
+#include <linux/kcomp.h>
+
+static LIST_HEAD(pci_drivers);
+
+struct pci_driver_mapping {
+	struct pci_dev *dev;
+	struct pci_driver *drv;
+	void *driver_data;
+};
+
+struct pci_device_id {
+	unsigned int vendor, device;
+	unsigned int subvendor, subdevice;
+	unsigned int class, class_mask;
+	unsigned long driver_data;
+};
+
+struct pci_driver {
+	struct list_head node;
+	struct pci_dev *dev;
+	char *name;
+	const struct pci_device_id *id_table;	/* NULL if wants all devices */
+	int (*probe)(struct pci_dev *dev, const struct pci_device_id *id);		/* New device inserted */
+	void (*remove)(struct pci_dev *dev);	/* Device removed (NULL if not a hot-plug capable driver) */
+	void (*suspend)(struct pci_dev *dev);	/* Device suspended */
+	void (*resume)(struct pci_dev *dev);	/* Device woken up */
+};
+
+#define PCI_MAX_MAPPINGS 16
+static struct pci_driver_mapping drvmap [PCI_MAX_MAPPINGS] = { { NULL, } , };
+
+#define __devinit			__init
+#define __devinitdata			__initdata
+#define __devexit
+#define MODULE_DEVICE_TABLE(foo,bar)
+#define SET_MODULE_OWNER(dev)
+#define COMPAT_MOD_INC_USE_COUNT	MOD_INC_USE_COUNT
+#define COMPAT_MOD_DEC_USE_COUNT	MOD_DEC_USE_COUNT
+#define PCI_ANY_ID (~0)
+#define IORESOURCE_MEM			2
+#define PCI_DMA_FROMDEVICE		0
+#define PCI_DMA_TODEVICE		0
+
+#define request_mem_region(addr, size, name)	((void *)1)
+#define release_mem_region(addr, size)
+#define del_timer_sync(timer)	del_timer(timer)
+
+static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+					 dma_addr_t *dma_handle)
+{
+	void *virt_ptr;
+
+	virt_ptr = kmalloc(size, GFP_KERNEL);
+	*dma_handle = virt_to_bus(virt_ptr);
+	return virt_ptr;
+}
+#define pci_free_consistent(cookie, size, ptr, dma_ptr)	kfree(ptr)
+#define pci_map_single(cookie, address, size, dir)	virt_to_bus(address)
+#define pci_unmap_single(cookie, address, size, dir)
+#define pci_dma_sync_single(cookie, address, size, dir)
+#undef	pci_resource_flags
+#define pci_resource_flags(dev, i) \
+  ((dev->base_address[i] & IORESOURCE_IO) ? IORESOURCE_IO : IORESOURCE_MEM)
+
+static void * pci_get_drvdata (struct pci_dev *dev)
+{
+	int i;
+
+	for (i = 0; i < PCI_MAX_MAPPINGS; i++)
+		if (drvmap[i].dev == dev)
+			return drvmap[i].driver_data;
+
+	return NULL;
+}
+
+static void pci_set_drvdata (struct pci_dev *dev, void *driver_data)
+{
+	int i;
+
+	for (i = 0; i < PCI_MAX_MAPPINGS; i++)
+		if (drvmap[i].dev == dev) {
+			drvmap[i].driver_data = driver_data;
+			return;
+		}
+}
+
+static const struct pci_device_id * __init
+pci_compat_match_device(const struct pci_device_id *ids, struct pci_dev *dev)
+{
+	u16 subsystem_vendor, subsystem_device;
+
+	pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor);
+	pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &subsystem_device);
+
+	while (ids->vendor || ids->subvendor || ids->class_mask) {
+		if ((ids->vendor == PCI_ANY_ID || ids->vendor == dev->vendor) &&
+			(ids->device == PCI_ANY_ID || ids->device == dev->device) &&
+			(ids->subvendor == PCI_ANY_ID || ids->subvendor == subsystem_vendor) &&
+			(ids->subdevice == PCI_ANY_ID || ids->subdevice == subsystem_device) &&
+			!((ids->class ^ dev->class) & ids->class_mask))
+			return ids;
+		ids++;
+	}
+	return NULL;
+}
+
+static int __init
+pci_announce_device(struct pci_driver *drv, struct pci_dev *dev)
+{
+	const struct pci_device_id *id;
+	int found, i;
+
+	if (drv->id_table) {
+		id = pci_compat_match_device(drv->id_table, dev);
+		if (!id)
+			return 0;
+	} else
+		id = NULL;
+
+	found = 0;
+	for (i = 0; i < PCI_MAX_MAPPINGS; i++)
+		if (!drvmap[i].dev) {
+			drvmap[i].dev = dev;
+			drvmap[i].drv = drv;
+			found = 1;
+			break;
+		}
+
+	if (!found)
+		return 0;
+
+	if (drv->probe(dev, id) >= 0)
+		return 1;
+
+	/* clean up */
+	drvmap[i].dev = NULL;
+	return 0;
+}
+
+static int __init
+pci_register_driver(struct pci_driver *drv)
+{
+	struct pci_dev *dev;
+	int count = 0, found, i;
+	list_add_tail(&drv->node, &pci_drivers);
+	for (dev = pci_devices; dev; dev = dev->next) {
+		found = 0;
+		for (i = 0; i < PCI_MAX_MAPPINGS && !found; i++)
+			if (drvmap[i].dev == dev)
+				found = 1;
+		if (!found)
+			count += pci_announce_device(drv, dev);
+	}
+	return count;
+}
+
+static void
+pci_unregister_driver(struct pci_driver *drv)
+{
+	struct pci_dev *dev;
+	int i, found;
+	list_del(&drv->node);
+	for (dev = pci_devices; dev; dev = dev->next) {
+		found = 0;
+		for (i = 0; i < PCI_MAX_MAPPINGS; i++)
+			if (drvmap[i].dev == dev) {
+				found = 1;
+				break;
+			}
+		if (found) {
+			if (drv->remove)
+				drv->remove(dev);
+			drvmap[i].dev = NULL;
+		}
+	}
+}
+
+static inline int pci_module_init(struct pci_driver *drv)
+{
+	if (pci_register_driver(drv))
+		return 0;
+	return -ENODEV;
+}
+
+static struct pci_driver starfire_driver;
+
+int __init starfire_probe(struct net_device *dev)
+{
+	static int __initdata probed = 0;
+
+	if (probed)
+		return -ENODEV;
+	probed++;
+
+	return pci_module_init(&starfire_driver);
+}
+
+#define init_tx_timer(dev, func, timeout)
+#define kick_tx_timer(dev, func, timeout) \
+	if (netif_queue_stopped(dev)) { \
+		/* If this happens network layer tells us we're broken. */ \
+		if (jiffies - dev->trans_start > timeout) \
+			func(dev); \
+	}
+
+#define netif_start_if(dev)	dev->start = 1
+#define netif_stop_if(dev)	dev->start = 0
+
+#else  /* LINUX_VERSION_CODE > 0x20300 */
+
+#define COMPAT_MOD_INC_USE_COUNT
+#define COMPAT_MOD_DEC_USE_COUNT
+
+#define init_tx_timer(dev, func, timeout) \
+	dev->tx_timeout = func; \
+	dev->watchdog_timeo = timeout;
+#define kick_tx_timer(dev, func, timeout)
+
+#define netif_start_if(dev)
+#define netif_stop_if(dev)
+
+#endif /* LINUX_VERSION_CODE > 0x20300 */
+/* end of compatibility code */
+
+
+enum chip_capability_flags {CanHaveMII=1, };
+#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR0)
+#define MEM_ADDR_SZ 0x80000		/* And maps in 0.5MB(!).  */
+
+#if 0
+#define ADDR_64BITS 1			/* This chip uses 64 bit addresses. */
+#endif
+
+#define HAS_IP_COPYSUM 1
+
+enum chipset {
+	CH_6915 = 0,
+};
+
+static struct pci_device_id starfire_pci_tbl[] __devinitdata = {
+	{ 0x9004, 0x6915, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_6915 },
+	{ 0, }
+};
+MODULE_DEVICE_TABLE(pci, starfire_pci_tbl);
+
+/* A chip capabilities table, matching the CH_xxx entries in xxx_pci_tbl[] above. */
+static struct chip_info {
+	const char *name;
+	int io_size;
+	int drv_flags;
+} netdrv_tbl[] __devinitdata = {
+	{ "Adaptec Starfire 6915", MEM_ADDR_SZ, CanHaveMII },
+};
+
+
+/* Offsets to the device registers.
+   Unlike software-only systems, device drivers interact with complex hardware.
+   It's not useful to define symbolic names for every register bit in the
+   device.  The name can only partially document the semantics and make
+   the driver longer and more difficult to read.
+   In general, only the important configuration values or bits changed
+   multiple times should be defined symbolically.
+*/
+enum register_offsets {
+	PCIDeviceConfig=0x50040, GenCtrl=0x50070, IntrTimerCtrl=0x50074,
+	IntrClear=0x50080, IntrStatus=0x50084, IntrEnable=0x50088,
+	MIICtrl=0x52000, StationAddr=0x50120, EEPROMCtrl=0x51000,
+	TxDescCtrl=0x50090,
+	TxRingPtr=0x50098, HiPriTxRingPtr=0x50094, /* Low and High priority. */
+	TxRingHiAddr=0x5009C,		/* 64 bit address extension. */
+	TxProducerIdx=0x500A0, TxConsumerIdx=0x500A4,
+	TxThreshold=0x500B0,
+	CompletionHiAddr=0x500B4, TxCompletionAddr=0x500B8,
+	RxCompletionAddr=0x500BC, RxCompletionQ2Addr=0x500C0,
+	CompletionQConsumerIdx=0x500C4, RxDMACtrl=0x500D0,
+	RxDescQCtrl=0x500D4, RxDescQHiAddr=0x500DC, RxDescQAddr=0x500E0,
+	RxDescQIdx=0x500E8, RxDMAStatus=0x500F0, RxFilterMode=0x500F4,
+	TxMode=0x55000, TxGfpMem=0x58000, RxGfpMem=0x5a000,
+};
+
+/* Bits in the interrupt status/mask registers. */
+enum intr_status_bits {
+	IntrLinkChange=0xf0000000, IntrStatsMax=0x08000000,
+	IntrAbnormalSummary=0x02000000, IntrGeneralTimer=0x01000000,
+	IntrSoftware=0x800000, IntrRxComplQ1Low=0x400000,
+	IntrTxComplQLow=0x200000, IntrPCI=0x100000,
+	IntrDMAErr=0x080000, IntrTxDataLow=0x040000,
+	IntrRxComplQ2Low=0x020000, IntrRxDescQ1Low=0x010000,
+	IntrNormalSummary=0x8000, IntrTxDone=0x4000,
+	IntrTxDMADone=0x2000, IntrTxEmpty=0x1000,
+	IntrEarlyRxQ2=0x0800, IntrEarlyRxQ1=0x0400,
+	IntrRxQ2Done=0x0200, IntrRxQ1Done=0x0100,
+	IntrRxGFPDead=0x80, IntrRxDescQ2Low=0x40,
+	IntrNoTxCsum=0x20, IntrTxBadID=0x10,
+	IntrHiPriTxBadID=0x08, IntrRxGfp=0x04,
+	IntrTxGfp=0x02, IntrPCIPad=0x01,
+	/* not quite bits */
+	IntrRxDone=IntrRxQ2Done | IntrRxQ1Done,
+	IntrRxEmpty=IntrRxDescQ1Low | IntrRxDescQ2Low,
+	IntrNormalMask=0xf0, IntrAbnormalMask=0x3f0e,
+};
+
+/* Bits in the RxFilterMode register. */
+enum rx_mode_bits {
+	AcceptBroadcast=0x04, AcceptAllMulticast=0x02, AcceptAll=0x01,
+	AcceptMulticast=0x10, AcceptMyPhys=0xE040,
+};
+
+/* Bits in the TxDescCtrl register. */
+enum tx_ctrl_bits {
+	TxDescSpaceUnlim=0x00, TxDescSpace32=0x10, TxDescSpace64=0x20,
+	TxDescSpace128=0x30, TxDescSpace256=0x40,
+	TxDescType0=0x00, TxDescType1=0x01, TxDescType2=0x02,
+	TxDescType3=0x03, TxDescType4=0x04,
+	TxNoDMACompletion=0x08, TxDescQ64bit=0x80,
+	TxHiPriFIFOThreshShift=24, TxPadLenShift=16,
+	TxDMABurstSizeShift=8,
+};
+
+/* Bits in the RxDescQCtrl register. */
+enum rx_ctrl_bits {
+	RxBufferLenShift=16, RxMinDescrThreshShift=0,
+	RxPrefetchMode=0x8000, Rx2048QEntries=0x4000,
+	RxVariableQ=0x2000, RxDesc64bit=0x1000,
+	RxDescQAddr64bit=0x0100,
+	RxDescSpace4=0x000, RxDescSpace8=0x100,
+	RxDescSpace16=0x200, RxDescSpace32=0x300,
+	RxDescSpace64=0x400, RxDescSpace128=0x500,
+	RxConsumerWrEn=0x80,
+};
+
+/* Bits in the RxCompletionAddr register */
+enum rx_compl_bits {
+	RxComplQAddr64bit=0x80, TxComplProducerWrEn=0x40,
+	RxComplType0=0x00, RxComplType1=0x10,
+	RxComplType2=0x20, RxComplType3=0x30,
+	RxComplThreshShift=0,
+};
+
+/* The Rx and Tx buffer descriptors. */
+struct starfire_rx_desc {
+	u32 rxaddr;			/* Optionally 64 bits. */
+};
+enum rx_desc_bits {
+	RxDescValid=1, RxDescEndRing=2,
+};
+
+/* Completion queue entry.
+   You must update the page allocation, init_ring and the shift count in rx()
+   if using a larger format. */
+#ifdef HAS_FIRMWARE
+#define csum_rx_status
+#endif /* HAS_FIRMWARE */
+struct rx_done_desc {
+	u32 status;			/* Low 16 bits is length. */
+#ifdef csum_rx_status
+	u32 status2;			/* Low 16 bits is csum */
+#endif /* csum_rx_status */
+#ifdef full_rx_status
+	u32 status2;
+	u16 vlanid;
+	u16 csum;			/* partial checksum */
+	u32 timestamp;
+#endif /* full_rx_status */
+};
+enum rx_done_bits {
+	RxOK=0x20000000, RxFIFOErr=0x10000000, RxBufQ2=0x08000000,
+};
+
+/* Type 1 Tx descriptor. */
+struct starfire_tx_desc {
+	u32 status;			/* Upper bits are status, lower 16 length. */
+	u32 first_addr;
+};
+enum tx_desc_bits {
+	TxDescID=0xB0000000,
+	TxCRCEn=0x01000000, TxDescIntr=0x08000000,
+	TxRingWrap=0x04000000, TxCalTCP=0x02000000,
+};
+struct tx_done_report {
+	u32 status;			/* timestamp, index. */
+#if 0
+	u32 intrstatus;			/* interrupt status */
+#endif
+};
+
+struct rx_ring_info {
+	struct sk_buff *skb;
+	dma_addr_t mapping;
+};
+struct tx_ring_info {
+	struct sk_buff *skb;
+	dma_addr_t first_mapping;
+};
+
+#define MII_CNT		2
+struct netdev_private {
+	/* Descriptor rings first for alignment. */
+	struct starfire_rx_desc *rx_ring;
+	struct starfire_tx_desc *tx_ring;
+	dma_addr_t rx_ring_dma;
+	dma_addr_t tx_ring_dma;
+	/* The addresses of rx/tx-in-place skbuffs. */
+	struct rx_ring_info rx_info[RX_RING_SIZE];
+	struct tx_ring_info tx_info[TX_RING_SIZE];
+	/* Pointers to completion queues (full pages).  I should cache line pad..*/
+	u8 pad0[100];
+	struct rx_done_desc *rx_done_q;
+	dma_addr_t rx_done_q_dma;
+	unsigned int rx_done;
+	struct tx_done_report *tx_done_q;
+	unsigned int tx_done;
+	dma_addr_t tx_done_q_dma;
+	struct net_device_stats stats;
+	struct timer_list timer;	/* Media monitoring timer. */
+	struct pci_dev *pci_dev;
+	/* Frequently used values: keep some adjacent for cache effect. */
+	unsigned int cur_rx, dirty_rx;	/* Producer/consumer ring indices */
+	unsigned int cur_tx, dirty_tx;
+	unsigned int rx_buf_sz;		/* Based on MTU+slack. */
+	unsigned int tx_full:1;		/* The Tx queue is full. */
+	/* These values are keep track of the transceiver/media in use. */
+	unsigned int full_duplex:1,	/* Full-duplex operation requested. */
+		medialock:1,		/* Xcvr set to fixed speed/duplex. */
+		rx_flowctrl:1,
+		tx_flowctrl:1;		/* Use 802.3x flow control. */
+	unsigned int default_port:4;	/* Last dev->if_port value. */
+	u32 tx_mode;
+	u8 tx_threshold;
+	/* MII transceiver section. */
+	int mii_cnt;			/* MII device addresses. */
+	u16 advertising;		/* NWay media advertisement */
+	unsigned char phys[MII_CNT];	/* MII device addresses. */
+};
+
+static int	mdio_read(struct net_device *dev, int phy_id, int location);
+static void	mdio_write(struct net_device *dev, int phy_id, int location, int value);
+static int	netdev_open(struct net_device *dev);
+static void	check_duplex(struct net_device *dev, int startup);
+static void	netdev_timer(unsigned long data);
+static void	tx_timeout(struct net_device *dev);
+static void	init_ring(struct net_device *dev);
+static int	start_tx(struct sk_buff *skb, struct net_device *dev);
+static void	intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
+static void	netdev_error(struct net_device *dev, int intr_status);
+static int	netdev_rx(struct net_device *dev);
+static void	netdev_error(struct net_device *dev, int intr_status);
+static void	set_rx_mode(struct net_device *dev);
+static struct net_device_stats *get_stats(struct net_device *dev);
+static int	mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int	netdev_close(struct net_device *dev);
+
+
+
+static int __devinit starfire_init_one(struct pci_dev *pdev,
+				       const struct pci_device_id *ent)
+{
+	struct netdev_private *np;
+	int i, irq, option, chip_idx = ent->driver_data;
+	struct net_device *dev;
+	static int card_idx = -1;
+	static int printed_version = 0;
+	long ioaddr;
+	int drv_flags, io_size;
+	int boguscnt;
+
+	card_idx++;
+	option = card_idx < MAX_UNITS ? options[card_idx] : 0;
+
+	if (!printed_version++)
+		printk(KERN_INFO "%s" KERN_INFO "%s" KERN_INFO "%s",
+			   version1, version2, version3);
+
+	if (pci_enable_device (pdev))
+		return -EIO;
+
+	ioaddr = pci_resource_start (pdev, 0);
+	io_size = pci_resource_len (pdev, 0);
+	if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_MEM) == 0)) {
+		printk (KERN_ERR "starfire %d: no PCI MEM resources, aborting\n", card_idx);
+		return -ENODEV;
+	}
+
+	dev = init_etherdev(NULL, sizeof(*np));
+	if (!dev) {
+		printk (KERN_ERR "starfire %d: cannot alloc etherdev, aborting\n", card_idx);
+		return -ENOMEM;
+	}
+	SET_MODULE_OWNER(dev);
+
+	irq = pdev->irq;
+
+	if (request_mem_region (ioaddr, io_size, dev->name) == NULL) {
+		printk (KERN_ERR "starfire %d: resource 0x%x @ 0x%lx busy, aborting\n",
+			card_idx, io_size, ioaddr);
+		goto err_out_free_netdev;
+	}
+
+	ioaddr = (long) ioremap (ioaddr, io_size);
+	if (!ioaddr) {
+		printk (KERN_ERR "starfire %d: cannot remap 0x%x @ 0x%lx, aborting\n",
+			card_idx, io_size, ioaddr);
+		goto err_out_free_res;
+	}
+
+	pci_set_master (pdev);
+
+	printk(KERN_INFO "%s: %s at 0x%lx, ",
+		   dev->name, netdrv_tbl[chip_idx].name, ioaddr);
+
+	/* Serial EEPROM reads are hidden by the hardware. */
+	for (i = 0; i < 6; i++)
+		dev->dev_addr[i] = readb(ioaddr + EEPROMCtrl + 20-i);
+	for (i = 0; i < 5; i++)
+		printk("%2.2x:", dev->dev_addr[i]);
+	printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
+
+#if ! defined(final_version) /* Dump the EEPROM contents during development. */
+	if (debug > 4)
+		for (i = 0; i < 0x20; i++)
+			printk("%2.2x%s",
+			       (unsigned int)readb(ioaddr + EEPROMCtrl + i),
+			       i % 16 != 15 ? " " : "\n");
+#endif
+
+	/* Issue soft reset */
+	writel(0x8000, ioaddr + TxMode);
+	udelay(1000);
+	writel(0, ioaddr + TxMode);
+
+	/* Reset the chip to erase previous misconfiguration. */
+	writel(1, ioaddr + PCIDeviceConfig);
+	boguscnt = 1000;
+	while (--boguscnt > 0) {
+		udelay(10);
+		if ((readl(ioaddr + PCIDeviceConfig) & 1) == 0)
+			break;
+	}
+	if (boguscnt == 0)
+		printk("%s: chipset reset never completed!\n", dev->name);
+	/* wait a little longer */
+	udelay(1000);
+
+	dev->base_addr = ioaddr;
+	dev->irq = irq;
+
+	np = dev->priv;
+	pci_set_drvdata(pdev, dev);
+
+	np->pci_dev = pdev;
+	drv_flags = netdrv_tbl[chip_idx].drv_flags;
+
+	if (dev->mem_start)
+		option = dev->mem_start;
+
+	/* The lower four bits are the media type. */
+	if (option > 0) {
+		if (option & 0x200)
+			np->full_duplex = 1;
+		np->default_port = option & 15;
+		if (np->default_port)
+			np->medialock = 1;
+	}
+	if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0)
+		np->full_duplex = 1;
+
+	if (np->full_duplex)
+		np->medialock = 1;
+
+	/* The chip-specific entries in the device structure. */
+	dev->open = &netdev_open;
+	dev->hard_start_xmit = &start_tx;
+	init_tx_timer(dev, tx_timeout, TX_TIMEOUT);
+	dev->stop = &netdev_close;
+	dev->get_stats = &get_stats;
+	dev->set_multicast_list = &set_rx_mode;
+	dev->do_ioctl = &mii_ioctl;
+
+	if (mtu)
+		dev->mtu = mtu;
+
+	if (drv_flags & CanHaveMII) {
+		int phy, phy_idx = 0;
+		int mii_status;
+		for (phy = 0; phy < 32 && phy_idx < MII_CNT; phy++) {
+			mdio_write(dev, phy, 0, 0x8000);
+			udelay(500);
+			boguscnt = 1000;
+			while (--boguscnt > 0)
+				if ((mdio_read(dev, phy, 0) & 0x8000) == 0)
+					break;
+			if (boguscnt == 0) {
+				printk("%s: PHY reset never completed!\n", dev->name);
+				continue;
+			}
+			mii_status = mdio_read(dev, phy, 1);
+			if (mii_status != 0x0000) {
+				np->phys[phy_idx++] = phy;
+				np->advertising = mdio_read(dev, phy, 4);
+				printk(KERN_INFO "%s: MII PHY found at address %d, status "
+					   "0x%4.4x advertising %4.4x.\n",
+					   dev->name, phy, mii_status, np->advertising);
+				/* there can be only one PHY on-board */
+				break;
+			}
+		}
+		np->mii_cnt = phy_idx;
+	}
+
+	return 0;
+
+err_out_free_res:
+	release_mem_region (ioaddr, io_size);
+err_out_free_netdev:
+	unregister_netdev (dev);
+	kfree (dev);
+	return -ENODEV;
+}
+
+
+/* Read the MII Management Data I/O (MDIO) interfaces. */
+
+static int mdio_read(struct net_device *dev, int phy_id, int location)
+{
+	long mdio_addr = dev->base_addr + MIICtrl + (phy_id<<7) + (location<<2);
+	int result, boguscnt=1000;
+	/* ??? Should we add a busy-wait here? */
+	do
+		result = readl(mdio_addr);
+	while ((result & 0xC0000000) != 0x80000000 && --boguscnt > 0);
+	if (boguscnt == 0)
+		return 0;
+	if ((result & 0xffff) == 0xffff)
+		return 0;
+	return result & 0xffff;
+}
+
+static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
+{
+	long mdio_addr = dev->base_addr + MIICtrl + (phy_id<<7) + (location<<2);
+	writel(value, mdio_addr);
+	/* The busy-wait will occur before a read. */
+	return;
+}
+
+
+static int netdev_open(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	long ioaddr = dev->base_addr;
+	int i, retval;
+
+	/* Do we ever need to reset the chip??? */
+
+	COMPAT_MOD_INC_USE_COUNT;
+
+	retval = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev);
+	if (retval) {
+		COMPAT_MOD_DEC_USE_COUNT;
+		return retval;
+	}
+
+	/* Disable the Rx and Tx, and reset the chip. */
+	writel(0, ioaddr + GenCtrl);
+	writel(1, ioaddr + PCIDeviceConfig);
+	if (debug > 1)
+		printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",
+		       dev->name, dev->irq);
+	/* Allocate the various queues, failing gracefully. */
+	if (np->tx_done_q == 0)
+		np->tx_done_q = pci_alloc_consistent(np->pci_dev, PAGE_SIZE, &np->tx_done_q_dma);
+	if (np->rx_done_q == 0)
+		np->rx_done_q = pci_alloc_consistent(np->pci_dev, sizeof(struct rx_done_desc) * DONE_Q_SIZE, &np->rx_done_q_dma);
+	if (np->tx_ring == 0)
+		np->tx_ring = pci_alloc_consistent(np->pci_dev, PAGE_SIZE, &np->tx_ring_dma);
+	if (np->rx_ring == 0)
+		np->rx_ring = pci_alloc_consistent(np->pci_dev, PAGE_SIZE, &np->rx_ring_dma);
+	if (np->tx_done_q == 0 || np->rx_done_q == 0
+		|| np->rx_ring == 0 || np->tx_ring == 0) {
+		if (np->tx_done_q)
+			pci_free_consistent(np->pci_dev, PAGE_SIZE,
+					    np->tx_done_q, np->tx_done_q_dma);
+		if (np->rx_done_q)
+			pci_free_consistent(np->pci_dev, sizeof(struct rx_done_desc) * DONE_Q_SIZE,
+					    np->rx_done_q, np->rx_done_q_dma);
+		if (np->tx_ring)
+			pci_free_consistent(np->pci_dev, PAGE_SIZE,
+					    np->tx_ring, np->tx_ring_dma);
+		if (np->rx_ring)
+			pci_free_consistent(np->pci_dev, PAGE_SIZE,
+					    np->rx_ring, np->rx_ring_dma);
+		COMPAT_MOD_DEC_USE_COUNT;
+		return -ENOMEM;
+	}
+
+	init_ring(dev);
+	/* Set the size of the Rx buffers. */
+	writel((np->rx_buf_sz << RxBufferLenShift) |
+	       (0 << RxMinDescrThreshShift) |
+	       RxPrefetchMode | RxVariableQ |
+	       RxDescSpace4,
+	       ioaddr + RxDescQCtrl);
+
+	/* Set Tx descriptor to type 1 and padding to 0 bytes. */
+	writel((2 << TxHiPriFIFOThreshShift) |
+	       (0 << TxPadLenShift) |
+	       (4 << TxDMABurstSizeShift) |
+	       TxDescSpaceUnlim | TxDescType1,
+	       ioaddr + TxDescCtrl);
+
+#if defined(ADDR_64BITS) && defined(__alpha__)
+	/* XXX We really need a 64-bit PCI dma interfaces too... -DaveM */
+	writel(np->rx_ring_dma >> 32, ioaddr + RxDescQHiAddr);
+	writel(np->tx_ring_dma >> 32, ioaddr + TxRingHiAddr);
+#else
+	writel(0, ioaddr + RxDescQHiAddr);
+	writel(0, ioaddr + TxRingHiAddr);
+	writel(0, ioaddr + CompletionHiAddr);
+#endif
+	writel(np->rx_ring_dma, ioaddr + RxDescQAddr);
+	writel(np->tx_ring_dma, ioaddr + TxRingPtr);
+
+	writel(np->tx_done_q_dma, ioaddr + TxCompletionAddr);
+#ifdef full_rx_status
+	writel(np->rx_done_q_dma |
+	       RxComplType3 |
+	       (0 << RxComplThreshShift),
+	       ioaddr + RxCompletionAddr);
+#else  /* not full_rx_status */
+#ifdef csum_rx_status
+	writel(np->rx_done_q_dma |
+	       RxComplType2 |
+	       (0 << RxComplThreshShift),
+	       ioaddr + RxCompletionAddr);
+#else  /* not csum_rx_status */
+	writel(np->rx_done_q_dma |
+	       RxComplType0 |
+	       (0 << RxComplThreshShift),
+	       ioaddr + RxCompletionAddr);
+#endif /* not csum_rx_status */
+#endif /* not full_rx_status */
+
+	if (debug > 1)
+		printk(KERN_DEBUG "%s: Filling in the station address.\n", dev->name);
+
+	/* Fill both the unused Tx SA register and the Rx perfect filter. */
+	for (i = 0; i < 6; i++)
+		writeb(dev->dev_addr[i], ioaddr + StationAddr + 5-i);
+	for (i = 0; i < 16; i++) {
+		u16 *eaddrs = (u16 *)dev->dev_addr;
+		long setup_frm = ioaddr + 0x56000 + i*16;
+		writew(cpu_to_be16(eaddrs[2]), setup_frm); setup_frm += 4;
+		writew(cpu_to_be16(eaddrs[1]), setup_frm); setup_frm += 4;
+		writew(cpu_to_be16(eaddrs[0]), setup_frm); setup_frm += 8;
+	}
+
+	/* Initialize other registers. */
+	/* Configure the PCI bus bursts and FIFO thresholds. */
+	np->tx_mode = 0;			/* Initialized when TxMode set. */
+	np->tx_threshold = 4;
+	writel(np->tx_threshold, ioaddr + TxThreshold);
+	writel(interrupt_mitigation, ioaddr + IntrTimerCtrl);
+
+	if (dev->if_port == 0)
+		dev->if_port = np->default_port;
+
+	netif_start_if(dev);
+	netif_start_queue(dev);
+
+	if (debug > 1)
+		printk(KERN_DEBUG "%s: Setting the Rx and Tx modes.\n", dev->name);
+	set_rx_mode(dev);
+
+	np->advertising = mdio_read(dev, np->phys[0], 4);
+	check_duplex(dev, 1);
+
+	/* Set the interrupt mask and enable PCI interrupts. */
+	writel(IntrRxDone | IntrRxEmpty | IntrDMAErr |
+	       IntrTxDone | IntrStatsMax | IntrLinkChange |
+	       IntrNormalSummary | IntrAbnormalSummary |
+	       IntrRxGFPDead | IntrNoTxCsum | IntrTxBadID,
+	       ioaddr + IntrEnable);
+	writel(0x00800000 | readl(ioaddr + PCIDeviceConfig),
+	       ioaddr + PCIDeviceConfig);
+
+#ifdef HAS_FIRMWARE
+	/* Load Rx/Tx firmware into the frame processors */
+	for (i = 0; i < FIRMWARE_RX_SIZE * 2; i++)
+		writel(cpu_to_le32(firmware_rx[i]), ioaddr + RxGfpMem + i * 4);
+	for (i = 0; i < FIRMWARE_TX_SIZE * 2; i++)
+		writel(cpu_to_le32(firmware_tx[i]), ioaddr + TxGfpMem + i * 4);
+	/* Enable the Rx and Tx units, and the Rx/Tx frame processors. */
+	writel(0x003F, ioaddr + GenCtrl);
+#else  /* not HAS_FIRMWARE */
+	/* Enable the Rx and Tx units only. */
+	writel(0x000F, ioaddr + GenCtrl);
+#endif /* not HAS_FIRMWARE */
+
+	if (debug > 2)
+		printk(KERN_DEBUG "%s: Done netdev_open().\n",
+		       dev->name);
+
+	/* Set the timer to check for link beat. */
+	init_timer(&np->timer);
+	np->timer.expires = jiffies + 3*HZ;
+	np->timer.data = (unsigned long)dev;
+	np->timer.function = &netdev_timer;				/* timer handler */
+	add_timer(&np->timer);
+
+	return 0;
+}
+
+static void check_duplex(struct net_device *dev, int startup)
+{
+	struct netdev_private *np = dev->priv;
+	long ioaddr = dev->base_addr;
+	int new_tx_mode ;
+
+	new_tx_mode = 0x0C04 | (np->tx_flowctrl ? 0x0800:0)
+		| (np->rx_flowctrl ? 0x0400:0);
+	if (np->medialock) {
+		if (np->full_duplex)
+			new_tx_mode |= 2;
+	} else {
+		int mii_reg5 = mdio_read(dev, np->phys[0], 5);
+		int negotiated =  mii_reg5 & np->advertising;
+		int duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
+		if (duplex)
+			new_tx_mode |= 2;
+		if (np->full_duplex != duplex) {
+			np->full_duplex = duplex;
+			if (debug > 1)
+				printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d"
+				       " negotiated capability %4.4x.\n", dev->name,
+				       duplex ? "full" : "half", np->phys[0], negotiated);
+		}
+	}
+	if (new_tx_mode != np->tx_mode) {
+		np->tx_mode = new_tx_mode;
+		writel(np->tx_mode | 0x8000, ioaddr + TxMode);
+		writel(np->tx_mode, ioaddr + TxMode);
+	}
+}
+
+static void netdev_timer(unsigned long data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct netdev_private *np = dev->priv;
+	long ioaddr = dev->base_addr;
+	int next_tick = 60*HZ;		/* Check before driver release. */
+
+	if (debug > 3) {
+		printk(KERN_DEBUG "%s: Media selection timer tick, status %8.8x.\n",
+		       dev->name, (int)readl(ioaddr + IntrStatus));
+	}
+	check_duplex(dev, 0);
+#if ! defined(final_version)
+	/* This is often falsely triggered. */
+	if (readl(ioaddr + IntrStatus) & 1) {
+		int new_status = readl(ioaddr + IntrStatus);
+		/* Bogus hardware IRQ: Fake an interrupt handler call. */
+		if (new_status & 1) {
+			printk(KERN_ERR "%s: Interrupt blocked, status %8.8x/%8.8x.\n",
+			       dev->name, new_status, (int)readl(ioaddr + IntrStatus));
+			intr_handler(dev->irq, dev, 0);
+		}
+	}
+#endif
+
+	np->timer.expires = jiffies + next_tick;
+	add_timer(&np->timer);
+}
+
+static void tx_timeout(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	long ioaddr = dev->base_addr;
+
+	printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
+	       " resetting...\n", dev->name, (int)readl(ioaddr + IntrStatus));
+
+#ifndef __alpha__
+	{
+		int i;
+		printk(KERN_DEBUG "  Rx ring %p: ", np->rx_ring);
+		for (i = 0; i < RX_RING_SIZE; i++)
+			printk(" %8.8x", (unsigned int)le32_to_cpu(np->rx_ring[i].rxaddr));
+		printk("\n"KERN_DEBUG"  Tx ring %p: ", np->tx_ring);
+		for (i = 0; i < TX_RING_SIZE; i++)
+			printk(" %4.4x", le32_to_cpu(np->tx_ring[i].status));
+		printk("\n");
+	}
+#endif
+
+	/* Perhaps we should reinitialize the hardware here. */
+	dev->if_port = 0;
+	/* Stop and restart the chip's Tx processes . */
+
+	/* Trigger an immediate transmit demand. */
+
+	dev->trans_start = jiffies;
+	np->stats.tx_errors++;
+	netif_wake_queue(dev);
+}
+
+
+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+static void init_ring(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	int i;
+
+	np->tx_full = 0;
+	np->cur_rx = np->cur_tx = 0;
+	np->dirty_rx = np->rx_done = np->dirty_tx = np->tx_done = 0;
+
+	np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
+
+	/* Fill in the Rx buffers.  Handle allocation failure gracefully. */
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz);
+		np->rx_info[i].skb = skb;
+		if (skb == NULL)
+			break;
+		np->rx_info[i].mapping = pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+		skb->dev = dev;			/* Mark as being used by this device. */
+		/* Grrr, we cannot offset to correctly align the IP header. */
+		np->rx_ring[i].rxaddr = cpu_to_le32(np->rx_info[i].mapping | RxDescValid);
+	}
+	writew(i - 1, dev->base_addr + RxDescQIdx);
+	np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
+
+	/* Clear the remainder of the Rx buffer ring. */
+	for (  ; i < RX_RING_SIZE; i++) {
+		np->rx_ring[i].rxaddr = 0;
+		np->rx_info[i].skb = NULL;
+		np->rx_info[i].mapping = 0;
+	}
+	/* Mark the last entry as wrapping the ring. */
+	np->rx_ring[i-1].rxaddr |= cpu_to_le32(RxDescEndRing);
+
+	/* Clear the completion rings. */
+	for (i = 0; i < DONE_Q_SIZE; i++) {
+		np->rx_done_q[i].status = 0;
+		np->tx_done_q[i].status = 0;
+	}
+
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		np->tx_info[i].skb = NULL;
+		np->tx_info[i].first_mapping = 0;
+		np->tx_ring[i].status = 0;
+	}
+	return;
+}
+
+static int start_tx(struct sk_buff *skb, struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	unsigned int entry;
+
+	kick_tx_timer(dev, tx_timeout, TX_TIMEOUT);
+
+	/* Caution: the write order is important here, set the field
+	   with the "ownership" bits last. */
+
+	/* Calculate the next Tx descriptor entry. */
+	entry = np->cur_tx % TX_RING_SIZE;
+
+	np->tx_info[entry].skb = skb;
+	np->tx_info[entry].first_mapping =
+		pci_map_single(np->pci_dev, skb->data, skb_first_frag_len(skb), PCI_DMA_TODEVICE);
+
+	np->tx_ring[entry].first_addr = cpu_to_le32(np->tx_info[entry].first_mapping);
+	/* Add "| TxDescIntr" to generate Tx-done interrupts. */
+	np->tx_ring[entry].status = cpu_to_le32(skb->len | TxDescID | TxCRCEn | 1 << 16);
+
+	if (entry >= TX_RING_SIZE-1)		 /* Wrap ring */
+		np->tx_ring[entry].status |= cpu_to_le32(TxRingWrap | TxDescIntr);
+
+	if (debug > 5) {
+		printk(KERN_DEBUG "%s: Tx #%d slot %d status %8.8x.\n",
+		       dev->name, np->cur_tx, entry,
+		       le32_to_cpu(np->tx_ring[entry].status));
+	}
+
+	np->cur_tx++;
+
+	if (entry >= TX_RING_SIZE-1)		 /* Wrap ring */
+		entry = -1;
+	entry++;
+
+	/* Non-x86: explicitly flush descriptor cache lines here. */
+	/* Ensure everything is written back above before the transmit is
+	   initiated. - Jes */
+	wmb();
+
+	/* Update the producer index. */
+	writel(entry * (sizeof(struct starfire_tx_desc) / 8), dev->base_addr + TxProducerIdx);
+
+	if (np->cur_tx - np->dirty_tx >= TX_RING_SIZE - 1) {
+		np->tx_full = 1;
+		netif_stop_queue(dev);
+	}
+
+	dev->trans_start = jiffies;
+
+	return 0;
+}
+
+/* The interrupt handler does all of the Rx thread work and cleans up
+   after the Tx thread. */
+static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
+{
+	struct net_device *dev = (struct net_device *)dev_instance;
+	struct netdev_private *np;
+	long ioaddr;
+	int boguscnt = max_interrupt_work;
+	int consumer;
+	int tx_status;
+
+#ifndef final_version			/* Can never occur. */
+	if (dev == NULL) {
+		printk (KERN_ERR "Netdev interrupt handler(): IRQ %d for unknown device.\n", irq);
+		return;
+	}
+#endif
+
+	ioaddr = dev->base_addr;
+	np = dev->priv;
+
+	do {
+		u32 intr_status = readl(ioaddr + IntrClear);
+
+		if (debug > 4)
+			printk(KERN_DEBUG "%s: Interrupt status %4.4x.\n",
+			       dev->name, intr_status);
+
+		if (intr_status == 0)
+			break;
+
+		if (intr_status & IntrRxDone)
+			netdev_rx(dev);
+
+		/* Scavenge the skbuff list based on the Tx-done queue.
+		   There are redundant checks here that may be cleaned up
+		   after the driver has proven to be reliable. */
+		consumer = readl(ioaddr + TxConsumerIdx);
+		if (debug > 4)
+			printk(KERN_DEBUG "%s: Tx Consumer index is %d.\n",
+			       dev->name, consumer);
+#if 0
+		if (np->tx_done >= 250 || np->tx_done == 0)
+			printk(KERN_DEBUG "%s: Tx completion entry %d is %8.8x, %d is %8.8x.\n",
+			       dev->name, np->tx_done,
+			       le32_to_cpu(np->tx_done_q[np->tx_done].status),
+			       (np->tx_done+1) & (DONE_Q_SIZE-1),
+			       le32_to_cpu(np->tx_done_q[(np->tx_done+1)&(DONE_Q_SIZE-1)].status));
+#endif
+
+		while ((tx_status = le32_to_cpu(np->tx_done_q[np->tx_done].status)) != 0) {
+			if (debug > 4)
+				printk(KERN_DEBUG "%s: Tx completion entry %d is %8.8x.\n",
+				       dev->name, np->tx_done, tx_status);
+			if ((tx_status & 0xe0000000) == 0xa0000000) {
+				np->stats.tx_packets++;
+			} else if ((tx_status & 0xe0000000) == 0x80000000) {
+				struct sk_buff *skb;
+				u16 entry = tx_status;		/* Implicit truncate */
+				entry /= sizeof(struct starfire_tx_desc);
+
+				skb = np->tx_info[entry].skb;
+				np->tx_info[entry].skb = NULL;
+				pci_unmap_single(np->pci_dev,
+						 np->tx_info[entry].first_mapping,
+						 skb_first_frag_len(skb),
+						 PCI_DMA_TODEVICE);
+				np->tx_info[entry].first_mapping = 0;
+
+				/* Scavenge the descriptor. */
+				dev_kfree_skb_irq(skb);
+
+				np->dirty_tx++;
+			}
+			np->tx_done_q[np->tx_done].status = 0;
+			np->tx_done = (np->tx_done+1) & (DONE_Q_SIZE-1);
+		}
+		writew(np->tx_done, ioaddr + CompletionQConsumerIdx + 2);
+
+		if (np->tx_full && np->cur_tx - np->dirty_tx < TX_RING_SIZE - 4) {
+			/* The ring is no longer full, wake the queue. */
+			np->tx_full = 0;
+			netif_wake_queue(dev);
+		}
+
+		/* Abnormal error summary/uncommon events handlers. */
+		if (intr_status & IntrAbnormalSummary)
+			netdev_error(dev, intr_status);
+
+		if (--boguscnt < 0) {
+			printk(KERN_WARNING "%s: Too much work at interrupt, "
+			       "status=0x%4.4x.\n",
+			       dev->name, intr_status);
+			break;
+		}
+	} while (1);
+
+	if (debug > 4)
+		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
+		       dev->name, (int)readl(ioaddr + IntrStatus));
+
+#ifndef final_version
+	/* Code that should never be run!  Remove after testing.. */
+	{
+		static int stopit = 10;
+		if (!netif_running(dev) && --stopit < 0) {
+			printk(KERN_ERR "%s: Emergency stop, looping startup interrupt.\n",
+			       dev->name);
+			free_irq(irq, dev);
+		}
+	}
+#endif
+}
+
+/* This routine is logically part of the interrupt handler, but separated
+   for clarity and better register allocation. */
+static int netdev_rx(struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
+	u32 desc_status;
+
+	if (np->rx_done_q == 0) {
+		printk(KERN_ERR "%s:  rx_done_q is NULL!  rx_done is %d. %p.\n",
+		       dev->name, np->rx_done, np->tx_done_q);
+		return 0;
+	}
+
+	/* If EOP is set on the next entry, it's a new packet. Send it up. */
+	while ((desc_status = le32_to_cpu(np->rx_done_q[np->rx_done].status)) != 0) {
+		struct sk_buff *skb;
+		u16 pkt_len;
+		int entry;
+
+		if (debug > 4)
+			printk(KERN_DEBUG "  netdev_rx() status of %d was %8.8x.\n", np->rx_done, desc_status);
+		if (--boguscnt < 0)
+			break;
+		if ( ! (desc_status & RxOK)) {
+			/* There was a error. */
+			if (debug > 2)
+				printk(KERN_DEBUG "  netdev_rx() Rx error was %8.8x.\n", desc_status);
+			np->stats.rx_errors++;
+			if (desc_status & RxFIFOErr)
+				np->stats.rx_fifo_errors++;
+			goto next_rx;
+		}
+
+		pkt_len = desc_status;	/* Implicitly Truncate */
+		entry = (desc_status >> 16) & 0x7ff;
+
+#ifndef final_version
+		if (debug > 4)
+			printk(KERN_DEBUG "  netdev_rx() normal Rx pkt length %d, bogus_cnt %d.\n", pkt_len, boguscnt);
+#endif
+		/* Check if the packet is long enough to accept without copying
+		   to a minimally-sized skbuff. */
+		if (pkt_len < rx_copybreak
+		    && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
+			skb->dev = dev;
+			skb_reserve(skb, 2);	/* 16 byte align the IP header */
+			pci_dma_sync_single(np->pci_dev,
+					    np->rx_info[entry].mapping,
+					    pkt_len, PCI_DMA_FROMDEVICE);
+#if HAS_IP_COPYSUM			/* Call copy + cksum if available. */
+			eth_copy_and_sum(skb, np->rx_info[entry].skb->tail, pkt_len, 0);
+			skb_put(skb, pkt_len);
+#else
+			memcpy(skb_put(skb, pkt_len), np->rx_info[entry].skb->tail, pkt_len);
+#endif
+		} else {
+			char *temp;
+
+			pci_unmap_single(np->pci_dev, np->rx_info[entry].mapping, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+			skb = np->rx_info[entry].skb;
+			temp = skb_put(skb, pkt_len);
+			np->rx_info[entry].skb = NULL;
+			np->rx_info[entry].mapping = 0;
+		}
+#ifndef final_version			/* Remove after testing. */
+		/* You will want this info for the initial debug. */
+		if (debug > 5)
+			printk(KERN_DEBUG "  Rx data %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:"
+			       "%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x "
+			       "%d.%d.%d.%d.\n",
+			       skb->data[0], skb->data[1], skb->data[2], skb->data[3],
+			       skb->data[4], skb->data[5], skb->data[6], skb->data[7],
+			       skb->data[8], skb->data[9], skb->data[10],
+			       skb->data[11], skb->data[12], skb->data[13],
+			       skb->data[14], skb->data[15], skb->data[16],
+			       skb->data[17]);
+#endif
+		skb->protocol = eth_type_trans(skb, dev);
+#if defined(full_rx_status) || defined(csum_rx_status)
+		if (le32_to_cpu(np->rx_done_q[np->rx_done].status2) & 0x01000000) {
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
+		}
+		/*
+		 * This feature doesn't seem to be working, at least
+		 * with the two firmware versions I have. If the GFP sees
+		 * a fragment, it either ignores it completely, or reports
+		 * "bad checksum" on it.
+		 *
+		 * Maybe I missed something -- corrections are welcome.
+		 * Until then, the printk stays. :-) -Ion
+		 */
+		else if (le32_to_cpu(np->rx_done_q[np->rx_done].status2) & 0x00400000) {
+			skb->ip_summed = CHECKSUM_HW;
+			skb->csum = le32_to_cpu(np->rx_done_q[np->rx_done].status2) & 0xffff;
+			printk(KERN_DEBUG "%s: checksum_hw, status2 = %x\n", dev->name, np->rx_done_q[np->rx_done].status2);
+		}
+#endif
+		netif_rx(skb);
+		dev->last_rx = jiffies;
+		np->stats.rx_packets++;
+
+next_rx:
+		np->cur_rx++;
+		np->rx_done_q[np->rx_done].status = 0;
+		np->rx_done = (np->rx_done + 1) & (DONE_Q_SIZE-1);
+	}
+	writew(np->rx_done, dev->base_addr + CompletionQConsumerIdx);
+
+	/* Refill the Rx ring buffers. */
+	for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) {
+		struct sk_buff *skb;
+		int entry = np->dirty_rx % RX_RING_SIZE;
+		if (np->rx_info[entry].skb == NULL) {
+			skb = dev_alloc_skb(np->rx_buf_sz);
+			np->rx_info[entry].skb = skb;
+			if (skb == NULL)
+				break;	/* Better luck next round. */
+			np->rx_info[entry].mapping =
+				pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+			skb->dev = dev;	/* Mark as being used by this device. */
+			np->rx_ring[entry].rxaddr =
+				cpu_to_le32(np->rx_info[entry].mapping | RxDescValid);
+		}
+		if (entry == RX_RING_SIZE - 1)
+			np->rx_ring[entry].rxaddr |= cpu_to_le32(RxDescEndRing);
+		/* We could defer this until later... */
+		writew(entry, dev->base_addr + RxDescQIdx);
+	}
+
+	if (debug > 5
+	    || memcmp(np->pad0, np->pad0 + 1, sizeof(np->pad0) -1))
+		printk(KERN_DEBUG "  exiting netdev_rx() status of %d was %8.8x %d.\n",
+		       np->rx_done, desc_status,
+		       memcmp(np->pad0, np->pad0 + 1, sizeof(np->pad0) -1));
+
+	/* Restart Rx engine if stopped. */
+	return 0;
+}
+
+static void netdev_error(struct net_device *dev, int intr_status)
+{
+	struct netdev_private *np = dev->priv;
+
+	if (intr_status & IntrLinkChange) {
+		printk(KERN_NOTICE "%s: Link changed: Autonegotiation advertising"
+		       " %4.4x, partner %4.4x.\n", dev->name,
+		       mdio_read(dev, np->phys[0], 4),
+		       mdio_read(dev, np->phys[0], 5));
+		check_duplex(dev, 0);
+	}
+	if (intr_status & IntrStatsMax) {
+		get_stats(dev);
+	}
+	/* Came close to underrunning the Tx FIFO, increase threshold. */
+	if (intr_status & IntrTxDataLow) {
+		writel(++np->tx_threshold, dev->base_addr + TxThreshold);
+		printk(KERN_NOTICE "%s: Increasing Tx FIFO threshold to %d bytes\n",
+		       np->tx_threshold * 16);
+	}
+	if ((intr_status & ~(IntrNormalMask | IntrAbnormalSummary | IntrLinkChange | IntrStatsMax | IntrTxDataLow | IntrPCIPad)) && debug)
+		printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
+		       dev->name, intr_status);
+	/* Hmmmmm, it's not clear how to recover from DMA faults. */
+	if (intr_status & IntrDMAErr)
+		np->stats.tx_fifo_errors++;
+}
+
+static struct net_device_stats *get_stats(struct net_device *dev)
+{
+	long ioaddr = dev->base_addr;
+	struct netdev_private *np = dev->priv;
+
+	/* This adapter architecture needs no SMP locks. */
+	np->stats.tx_bytes = readl(ioaddr + 0x57010);
+	np->stats.rx_bytes = readl(ioaddr + 0x57044);
+	np->stats.tx_packets = readl(ioaddr + 0x57000);
+	np->stats.tx_aborted_errors =
+		readl(ioaddr + 0x57024) + readl(ioaddr + 0x57028);
+	np->stats.tx_window_errors = readl(ioaddr + 0x57018);
+	np->stats.collisions =
+		readl(ioaddr + 0x57004) + readl(ioaddr + 0x57008);
+
+	/* The chip only need report frame silently dropped. */
+	np->stats.rx_dropped += readw(ioaddr + RxDMAStatus);
+	writew(0, ioaddr + RxDMAStatus);
+	np->stats.rx_crc_errors = readl(ioaddr + 0x5703C);
+	np->stats.rx_frame_errors = readl(ioaddr + 0x57040);
+	np->stats.rx_length_errors = readl(ioaddr + 0x57058);
+	np->stats.rx_missed_errors = readl(ioaddr + 0x5707C);
+
+	return &np->stats;
+}
+
+/* The little-endian AUTODIN II ethernet CRC calculations.
+   A big-endian version is also available.
+   This is slow but compact code.  Do not use this routine for bulk data,
+   use a table-based routine instead.
+   This is common code and should be moved to net/core/crc.c.
+   Chips may use the upper or lower CRC bits, and may reverse and/or invert
+   them.  Select the endian-ness that results in minimal calculations.
+*/
+static unsigned const ethernet_polynomial_le = 0xedb88320U;
+static inline unsigned ether_crc_le(int length, unsigned char *data)
+{
+	unsigned int crc = 0xffffffff;	/* Initial value. */
+	while(--length >= 0) {
+		unsigned char current_octet = *data++;
+		int bit;
+		for (bit = 8; --bit >= 0; current_octet >>= 1) {
+			if ((crc ^ current_octet) & 1) {
+				crc >>= 1;
+				crc ^= ethernet_polynomial_le;
+			} else
+				crc >>= 1;
+		}
+	}
+	return crc;
+}
+
+static void set_rx_mode(struct net_device *dev)
+{
+	long ioaddr = dev->base_addr;
+	u32 rx_mode;
+	struct dev_mc_list *mclist;
+	int i;
+
+	if (dev->flags & IFF_PROMISC) {	/* Set promiscuous. */
+		/* Unconditionally log net taps. */
+		printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
+		rx_mode = AcceptBroadcast|AcceptAllMulticast|AcceptAll|AcceptMyPhys;
+	} else if ((dev->mc_count > multicast_filter_limit)
+		   || (dev->flags & IFF_ALLMULTI)) {
+		/* Too many to match, or accept all multicasts. */
+		rx_mode = AcceptBroadcast|AcceptAllMulticast|AcceptMyPhys;
+	} else if (dev->mc_count <= 15) {
+		/* Use the 16 element perfect filter. */
+		long filter_addr = ioaddr + 0x56000 + 1*16;
+		for (i = 1, mclist = dev->mc_list; mclist && i <= dev->mc_count;
+		     i++, mclist = mclist->next) {
+			u16 *eaddrs = (u16 *)mclist->dmi_addr;
+			writew(cpu_to_be16(eaddrs[2]), filter_addr); filter_addr += 4;
+			writew(cpu_to_be16(eaddrs[1]), filter_addr); filter_addr += 4;
+			writew(cpu_to_be16(eaddrs[0]), filter_addr); filter_addr += 8;
+		}
+		while (i++ < 16) {
+			writew(0xffff, filter_addr); filter_addr += 4;
+			writew(0xffff, filter_addr); filter_addr += 4;
+			writew(0xffff, filter_addr); filter_addr += 8;
+		}
+		rx_mode = AcceptBroadcast | AcceptMyPhys;
+	} else {
+		/* Must use a multicast hash table. */
+		long filter_addr;
+		u16 mc_filter[32] __attribute__ ((aligned(sizeof(long))));	/* Multicast hash filter */
+
+		memset(mc_filter, 0, sizeof(mc_filter));
+		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+		     i++, mclist = mclist->next) {
+			set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 23, mc_filter);
+		}
+		/* Clear the perfect filter list. */
+		filter_addr = ioaddr + 0x56000 + 1*16;
+		for (i = 1; i < 16; i++) {
+			writew(0xffff, filter_addr); filter_addr += 4;
+			writew(0xffff, filter_addr); filter_addr += 4;
+			writew(0xffff, filter_addr); filter_addr += 8;
+		}
+		for (filter_addr=ioaddr + 0x56100, i=0; i < 32; filter_addr+= 16, i++)
+			writew(mc_filter[i], filter_addr);
+		rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+	}
+	writel(rx_mode, ioaddr + RxFilterMode);
+}
+
+static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct netdev_private *np = dev->priv;
+	u16 *data = (u16 *)&rq->ifr_data;
+
+	switch(cmd) {
+	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
+		data[0] = np->phys[0] & 0x1f;
+		/* Fall Through */
+	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
+		data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
+		return 0;
+	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		if (data[0] == np->phys[0]) {
+			u16 value = data[2];
+			switch (data[1]) {
+			case 0:
+				if (value & 0x9000)	/* Autonegotiation. */
+					np->medialock = 0;
+				else {
+					np->full_duplex = (value & 0x0100) ? 1 : 0;
+					np->medialock = 1;
+				}
+				break;
+			case 4: np->advertising = value; break;
+			}
+			check_duplex(dev, 0);
+		}
+		mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
+		return 0;
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static int netdev_close(struct net_device *dev)
+{
+	long ioaddr = dev->base_addr;
+	struct netdev_private *np = dev->priv;
+	int i;
+
+	netif_stop_queue(dev);
+	netif_stop_if(dev);
+
+	del_timer_sync(&np->timer);
+
+	if (debug > 1) {
+		printk(KERN_DEBUG "%s: Shutting down ethercard, Intr status %4.4x.\n",
+			   dev->name, (int)readl(ioaddr + IntrStatus));
+		printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d,  Rx %d / %d.\n",
+			   dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx);
+	}
+
+	/* Disable interrupts by clearing the interrupt mask. */
+	writel(0, ioaddr + IntrEnable);
+
+	/* Stop the chip's Tx and Rx processes. */
+
+#ifdef __i386__
+	if (debug > 2) {
+		printk("\n"KERN_DEBUG"  Tx ring at %8.8x:\n",
+			   np->tx_ring_dma);
+		for (i = 0; i < 8 /* TX_RING_SIZE is huge! */; i++)
+			printk(KERN_DEBUG " #%d desc. %8.8x %8.8x -> %8.8x.\n",
+			       i, le32_to_cpu(np->tx_ring[i].status),
+			       le32_to_cpu(np->tx_ring[i].first_addr),
+			       le32_to_cpu(np->tx_done_q[i].status));
+		printk(KERN_DEBUG "  Rx ring at %8.8x -> %p:\n",
+		       np->rx_ring_dma, np->rx_done_q);
+		if (np->rx_done_q)
+			for (i = 0; i < 8 /* RX_RING_SIZE */; i++) {
+				printk(KERN_DEBUG " #%d desc. %8.8x -> %8.8x\n",
+				       i, le32_to_cpu(np->rx_ring[i].rxaddr), le32_to_cpu(np->rx_done_q[i].status));
+		}
+	}
+#endif /* __i386__ debugging only */
+
+	free_irq(dev->irq, dev);
+
+	/* Free all the skbuffs in the Rx queue. */
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		np->rx_ring[i].rxaddr = cpu_to_le32(0xBADF00D0); /* An invalid address. */
+		if (np->rx_info[i].skb != NULL) {
+			pci_unmap_single(np->pci_dev, np->rx_info[i].mapping, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+			dev_kfree_skb(np->rx_info[i].skb);
+		}
+		np->rx_info[i].skb = NULL;
+		np->rx_info[i].mapping = 0;
+	}
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		struct sk_buff *skb = np->tx_info[i].skb;
+		if (skb == NULL)
+			continue;
+		pci_unmap_single(np->pci_dev,
+				 np->tx_info[i].first_mapping,
+				 skb_first_frag_len(skb), PCI_DMA_TODEVICE);
+		np->tx_info[i].first_mapping = 0;
+		dev_kfree_skb(skb);
+		np->tx_info[i].skb = NULL;
+	}
+
+	COMPAT_MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+
+static void __devexit starfire_remove_one (struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct netdev_private *np;
+
+	if (!dev)
+		BUG();
+
+	np = dev->priv;
+
+	unregister_netdev(dev);
+	iounmap((char *)dev->base_addr);
+
+	release_mem_region(pci_resource_start (pdev, 0),
+			   pci_resource_len (pdev, 0));
+
+	if (np->tx_done_q)
+		pci_free_consistent(np->pci_dev, PAGE_SIZE,
+				    np->tx_done_q, np->tx_done_q_dma);
+	if (np->rx_done_q)
+		pci_free_consistent(np->pci_dev, PAGE_SIZE,
+				    np->rx_done_q, np->rx_done_q_dma);
+	if (np->tx_ring)
+		pci_free_consistent(np->pci_dev, PAGE_SIZE,
+				    np->tx_ring, np->tx_ring_dma);
+	if (np->rx_ring)
+		pci_free_consistent(np->pci_dev, PAGE_SIZE,
+				    np->rx_ring, np->rx_ring_dma);
+
+	kfree(dev);
+}
+
+
+static struct pci_driver starfire_driver = {
+	name:		"starfire",
+	probe:		starfire_init_one,
+	remove:		starfire_remove_one,
+	id_table:	starfire_pci_tbl,
+};
+
+
+static int __init starfire_init (void)
+{
+	return pci_module_init (&starfire_driver);
+}
+
+
+static void __exit starfire_cleanup (void)
+{
+	pci_unregister_driver (&starfire_driver);
+}
+
+
+module_init(starfire_init);
+module_exit(starfire_cleanup);
+
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c starfire.c"
+ *  simple-compile-command: "gcc -DMODULE -O6 -c starfire.c"
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/starfire_firmware.pl linux.19p18/drivers/net/starfire_firmware.pl
--- linux.vanilla/drivers/net/starfire_firmware.pl	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/net/starfire_firmware.pl	Mon Feb 12 14:59:32 2001
@@ -0,0 +1,31 @@
+#!/usr/bin/perl
+
+# This script can be used to generate a new starfire_firmware.h
+# from GFP_RX.DAT and GFP_TX.DAT, files included with the DDK
+# and also with the Novell drivers.
+
+open FW, "GFP_RX.DAT" || die;
+open FWH, ">starfire_firmware.h" || die;
+
+printf(FWH "static u32 firmware_rx[] = {\n");
+$counter = 0;
+while ($foo = <FW>) {
+  chomp;
+  printf(FWH "  0x%s, 0x0000%s,\n", substr($foo, 4, 8), substr($foo, 0, 4));
+  $counter++;
+}
+
+close FW;
+open FW, "GFP_TX.DAT" || die;
+
+printf(FWH "};\t/* %d Rx instructions */\n#define FIRMWARE_RX_SIZE %d\n\nstatic u32 firmware_tx[] = {\n", $counter, $counter);
+$counter = 0;
+while ($foo = <FW>) {
+  chomp;
+  printf(FWH "  0x%s, 0x0000%s,\n", substr($foo, 4, 8), substr($foo, 0, 4));
+  $counter++;
+}
+
+close FW;
+printf(FWH "};\t/* %d Tx instructions */\n#define FIRMWARE_TX_SIZE %d\n", $counter, $counter);
+close(FWH);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/strip.c linux.19p18/drivers/net/strip.c
--- linux.vanilla/drivers/net/strip.c	Fri Apr 21 12:46:20 2000
+++ linux.19p18/drivers/net/strip.c	Wed Dec 13 22:28:39 2000
@@ -14,7 +14,7 @@
  *		for kernel-based devices like TTY.  It interfaces between a
  *		raw TTY, and the kernel's INET protocol layers (via DDI).
  *
- * Version:	@(#)strip.c	1.3	July 1997
+ * Version:	@(#)strip.c	1.4	September 2000
  *
  * Author:	Stuart Cheshire <cheshire@cs.stanford.edu>
  *
@@ -66,12 +66,15 @@
  *              It is no longer necessarily to manually set the radio's
  *              rate permanently to 115200 -- the driver handles setting
  *              the rate automatically.
+ *
+ *              v1.4 September 2000 (AB)
+ *              Added support for long serial numbers.
  */
 
 #ifdef MODULE
-static const char StripVersion[] = "1.3-STUART.CHESHIRE-MODULAR";
+static const char StripVersion[] = "1.4-STUART.CHESHIRE-MODULAR";
 #else
-static const char StripVersion[] = "1.3-STUART.CHESHIRE";
+static const char StripVersion[] = "1.4-STUART.CHESHIRE";
 #endif
 
 #define TICKLE_TIMERS 0
@@ -897,20 +900,37 @@
  * Convert a string to a Metricom Address.
  */
 
-#define IS_RADIO_ADDRESS(p) (                                                 \
+#define IS_RADIO_ADDRESS_1(p) (                                               \
   isdigit((p)[0]) && isdigit((p)[1]) && isdigit((p)[2]) && isdigit((p)[3]) && \
   (p)[4] == '-' &&                                                            \
   isdigit((p)[5]) && isdigit((p)[6]) && isdigit((p)[7]) && isdigit((p)[8])    )
 
+#define IS_RADIO_ADDRESS_2(p) (                                               \
+  isdigit((p)[0]) && isdigit((p)[1]) &&                                       \
+  (p)[2] == '-' &&                                                            \
+  isdigit((p)[3]) && isdigit((p)[4]) && isdigit((p)[5]) && isdigit((p)[6]) && \
+  (p)[7] == '-' &&                                                            \
+  isdigit((p)[8]) && isdigit((p)[9]) && isdigit((p)[10]) && isdigit((p)[11])  )
+
 static int string_to_radio_address(MetricomAddress *addr, __u8 *p)
 {
-    if (!IS_RADIO_ADDRESS(p)) return(1);
+    if (IS_RADIO_ADDRESS_2(p))
+    {
+        addr->c[0] = 0;
+        addr->c[1] = (READHEX(p[0]) << 4 | READHEX(p[1])) ^ 0xFF;
+        addr->c[2] = READHEX(p[3]) << 4 | READHEX(p[4]);
+        addr->c[3] = READHEX(p[5]) << 4 | READHEX(p[6]);
+        addr->c[4] = READHEX(p[8]) << 4 | READHEX(p[9]);
+        addr->c[5] = READHEX(p[10]) << 4 | READHEX(p[11]);
+    }else{
+        if(!IS_RADIO_ADDRESS_1(p)) return(1);
     addr->c[0] = 0;
     addr->c[1] = 0;
     addr->c[2] = READHEX(p[0]) << 4 | READHEX(p[1]);
     addr->c[3] = READHEX(p[2]) << 4 | READHEX(p[3]);
     addr->c[4] = READHEX(p[5]) << 4 | READHEX(p[6]);
     addr->c[5] = READHEX(p[7]) << 4 | READHEX(p[8]);
+    }
     return(0);
 }
 
@@ -920,6 +940,9 @@
 
 static __u8 *radio_address_to_string(const MetricomAddress *addr, MetricomAddressString *p)
 {
+    if(addr->c[1])
+        sprintf(p->c, "%02X-%02X%02X-%02X%02X", addr->c[1] ^ 0xFF, addr->c[2], addr->c[3], addr->c[4], addr->c[5]);
+    else
     sprintf(p->c, "%02X%02X-%02X%02X", addr->c[2], addr->c[3], addr->c[4], addr->c[5]);
     return(p->c);
 }
@@ -1481,6 +1504,12 @@
 
     *ptr++ = 0x0D;
     *ptr++ = '*';
+    if(haddr.c[1])
+    {
+        *ptr++ = hextable[(haddr.c[1] >> 4) ^ 0xF];
+        *ptr++ = hextable[(haddr.c[1] & 0xF) ^ 0xF];
+        *ptr++ = '-';
+    }
     *ptr++ = hextable[haddr.c[2] >> 4];
     *ptr++ = hextable[haddr.c[2] & 0xF];
     *ptr++ = hextable[haddr.c[3] >> 4];
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/sunhme.c linux.19p18/drivers/net/sunhme.c
--- linux.vanilla/drivers/net/sunhme.c	Sat Sep  9 18:42:40 2000
+++ linux.19p18/drivers/net/sunhme.c	Tue Feb 20 13:28:55 2001
@@ -3523,6 +3523,7 @@
 	struct linux_sbus_device *sdev = 0;
 	static int called = 0;
 	int cards = 0, v;
+	char model[128];
 
 	if(called)
 		return ENODEV;
@@ -3534,7 +3535,13 @@
 				dev = NULL;
 			if(!strcmp(sdev->prom_name, "SUNW,hme")) {
 				cards++;
-				if((v = happy_meal_ether_init(dev, sdev, 0)))
+				prom_getstring(sdev->prom_node, "model",
+					       model, sizeof(model));
+				if (!strcmp(model, "SUNW,sbus-qfe"))
+					v = happy_meal_ether_init(dev, sdev, 1);
+				else
+					v = happy_meal_ether_init(dev, sdev, 0);
+				if(v)
 					return v;
 			} else if(!strcmp(sdev->prom_name, "qfe") ||
 				  !strcmp(sdev->prom_name, "SUNW,qfe")) {
@@ -3582,11 +3589,20 @@
 cleanup_module(void)
 {
 	struct happy_meal *sunshine;
+	struct quattro *last_seen_qfe = NULL;
 
 	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
 	while (root_happy_dev) {
 		struct happy_meal *hp = root_happy_dev;
 		sunshine = root_happy_dev->next_module;
+
+		if (!(hp->happy_flags & HFLAG_PCI) &&
+		    (hp->happy_flags & HFLAG_QUATTRO)) {
+			if (hp->qfe_parent != last_seen_qfe) {
+				free_irq(hp->dev->irq, hp->qfe_parent);
+				last_seen_qfe = hp->qfe_parent;
+			}
+		}
 
 		sparc_free_io(hp->gregs, sizeof(struct hmeal_gregs));
 		sparc_free_io(hp->etxregs, sizeof(struct hmeal_etxregs));
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/tulip.c linux.19p18/drivers/net/tulip.c
--- linux.vanilla/drivers/net/tulip.c	Mon Dec 11 22:12:50 2000
+++ linux.19p18/drivers/net/tulip.c	Thu Feb 15 16:20:05 2001
@@ -15,10 +15,14 @@
 
 	Support and updates available at
 	http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html
-	
+
 	This driver also contains updates by Wolfgang Walter and others.
 	For this specific driver variant please use linux-kernel for 
 	bug reports.
+
+	Updated 12/17/2000 by Jim McQuillan <jam@McQuil.com> to
+	include support for the Linksys LNE100TX card based on the
+	Admtek 985 Centaur-P chipset.
 */
 
 #define SMP_CHECK
@@ -26,9 +30,6 @@
 
 /* A few user-configurable values. */
 
-/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 25;
-
 #define MAX_UNITS 8
 /* Used to pass the full-duplex flag, etc. */
 static int full_duplex[MAX_UNITS] = {0, };
@@ -139,7 +140,6 @@
 MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
 MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver");
 MODULE_PARM(debug, "i");
-MODULE_PARM(max_interrupt_work, "i");
 MODULE_PARM(reverse_probe, "i");
 MODULE_PARM(rx_copybreak, "i");
 MODULE_PARM(csr0, "i");
@@ -149,10 +149,6 @@
 
 #define RUN_AT(x) (jiffies + (x))
 
-#if (LINUX_VERSION_CODE >= 0x20100)
-static char kernel_version[] = UTS_RELEASE;
-#endif
-
 #if LINUX_VERSION_CODE < 0x20123
 #define hard_smp_processor_id() smp_processor_id()
 #define test_and_set_bit(val, addr) set_bit(val, addr)
@@ -398,6 +394,8 @@
 	HAS_MII | HAS_NWAY143 | HAS_8023X, t21142_timer },
   { "ADMtek Comet", 256, 0x0001abef,
 	MC_HASH_ONLY, comet_timer },
+  { "ADMtek Centaur-P", 256, 0x0001abef,
+  	MC_HASH_ONLY, comet_timer },
   { "Compex 9881 PMAC", 128, 0x0001ebef,
 	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer },
   { "Intel DS21145 Tulip", 128, 0x0801fbff,
@@ -411,8 +409,8 @@
 /* This matches the table above.  Note 21142 == 21143. */
 enum chips {
 	DC21040=0, DC21041=1, DC21140=2, DC21142=3, DC21143=3,
-	LC82C168, MX98713, MX98715, MX98725, AX88140, PNIC2, COMET, COMPEX9881,
-	I21145,
+	LC82C168, MX98713, MX98715, MX98725, AX88140, PNIC2, COMET, COMET5,
+        COMPEX9881, I21145, XIRCOM,
 };
 
 /* A full-duplex map for media types. */
@@ -750,7 +748,7 @@
 			put_unaligned(le16_to_cpu(value), ((u16*)dev->dev_addr) + i);
 			sum += value & 0xffff;
 		}
-	} else if (chip_idx == COMET) {
+	} else if ((chip_idx == COMET) || (chip_idx == COMET5)) {
 		/* No need to read the EEPROM. */
 		put_unaligned(inl(ioaddr + 0xA4), (u32 *)dev->dev_addr);
 		put_unaligned(inl(ioaddr + 0xA8), (u16 *)(dev->dev_addr + 4));
@@ -993,6 +991,7 @@
 		outl(0x00001000, ioaddr + CSR12);
 		break;
 	case COMET:
+	case COMET5:
 		/* No initialization necessary. */
 		break;
 	}
@@ -1310,7 +1309,7 @@
 		return 0xffff;
 	}
 
-	if (tp->chip_id == COMET) {
+	if ((tp->chip_id == COMET) || (tp->chip_id == COMET5)) {
 		if (phy_id == 1) {
 			if (location < 7)
 				return inl(ioaddr + 0xB4 + (location<<2));
@@ -1367,7 +1366,7 @@
 		return;
 	}
 
-	if (tp->chip_id == COMET) {
+	if ((tp->chip_id == COMET) || (tp->chip_id == COMET5)) {
 		if (phy_id != 1)
 			return;
 		if (location < 7)
@@ -1457,7 +1456,7 @@
 			outl(addr_low,  ioaddr + CSR14);
 			outl(1, ioaddr + CSR13);
 			outl(addr_high, ioaddr + CSR14);
-		} else if (tp->chip_id == COMET) {
+		} else if ((tp->chip_id == COMET) || (tp->chip_id == COMET5)) {
 			outl(addr_low,  ioaddr + 0xA4);
 			outl(addr_high, ioaddr + 0xA8);
 			outl(0, ioaddr + 0xAC);
@@ -1572,7 +1571,7 @@
 		outl(0x0000, ioaddr + CSR13);
 		outl(0x0000, ioaddr + CSR14);
 		outl(0x0008, ioaddr + CSR15);
-	} else if (tp->chip_id == COMET) {
+	} else if ((tp->chip_id == COMET) || (tp->chip_id == COMET5)) {
 		dev->if_port = 0;
 		tp->csr6 = 0x00040000;
 	} else if (tp->chip_id == AX88140) {
@@ -3012,7 +3011,7 @@
 			data[0] = phy;
 		else if (tp->flags & HAS_NWAY143)
 			data[0] = 32;
-		else if (tp->chip_id == COMET)
+		else if ((tp->chip_id == COMET) || (tp->chip_id == COMET5))
 			data[0] = 1;
 		else
 			return -ENODEV;
@@ -3139,7 +3138,9 @@
 				outl(mc_filter[0], ioaddr + CSR14);
 				outl(3, ioaddr + CSR13);
 				outl(mc_filter[1], ioaddr + CSR14);
-			} else if (tp->chip_id == COMET) { /* Has a simple hash filter. */
+
+			/* Has a simple hash filter. */
+			} else if ((tp->chip_id == COMET) || (tp->chip_id == COMET5)) {
 				outl(mc_filter[0], ioaddr + 0xAC);
 				outl(mc_filter[1], ioaddr + 0xB0);
 			}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/net/via-rhine.c linux.19p18/drivers/net/via-rhine.c
--- linux.vanilla/drivers/net/via-rhine.c	Mon Dec 11 22:12:50 2000
+++ linux.19p18/drivers/net/via-rhine.c	Tue Jan  9 11:51:10 2001
@@ -1,35 +1,44 @@
 /* via-rhine.c: A Linux Ethernet device driver for VIA Rhine family chips. */
 /*
-	Written 1998-1999 by Donald Becker.
+	Written 1998-2000 by Donald Becker.
 
-	This software may be used and distributed according to the terms
-	of the GNU Public License (GPL), incorporated herein by reference.
-	Drivers derived from this code also fall under the GPL and must retain
-	this authorship and copyright notice.
+	This software may be used and distributed according to the terms of
+	the GNU General Public License (GPL), incorporated herein by reference.
+	Drivers based on or derived from this code fall under the GPL and must
+	retain the authorship, copyright and license notice.  This file is not
+	a complete program and may only be used when the entire operating
+	system is licensed under the GPL.
 
 	This driver is designed for the VIA VT86c100A Rhine-II PCI Fast Ethernet
 	controller.  It also works with the older 3043 Rhine-I chip.
 
-	The author may be reached as becker@cesdis.edu, or
-	Donald Becker
-	312 Severn Ave. #W302
+	The author may be reached as becker@scyld.com, or C/O
+	Scyld Computing Corporation
+	410 Severn Ave., Suite 210
 	Annapolis MD 21403
 
 	Support and updates available at
-	http://cesdis.gsfc.nasa.gov/linux/drivers/via-rhine.html
+	http://www.scyld.com/network/via-rhine.html
+
+
+	Linux kernel version history:
+
+	LK1.0.0:
+	- Urban Widmark: merges from Beckers 1.08b version and 2.4.0 (VT6102)
 */
 
-static const char *versionA =
-"via-rhine.c:v1.01 2/27/99  Written by Donald Becker\n";
-static const char *versionB =
-"  http://cesdis.gsfc.nasa.gov/linux/drivers/via-rhine.html\n";
+/* These identify the driver base version and may not be removed. */
+static const char version1[] =
+"via-rhine.c:v1.08b-LK1.0.0 12/14/2000  Written by Donald Becker\n";
+static const char version2[] =
+"  http://www.scyld.com/network/via-rhine.html\n";
 
-/* A few user-configurable values.   These may be modified when a driver
-   module is loaded.*/
+/* The user-configurable values.
+   These may be modified when a driver module is loaded.*/
 
 static int debug = 1;			/* 1 normal messages, 0 quiet .. 7 verbose. */
 static int max_interrupt_work = 20;
-static int min_pci_latency = 64;
+static int min_pci_latency = 32;
 
 /* Set the copy breakpoint for the copy-only-tiny-frames scheme.
    Setting to > 1518 effectively disables this feature. */
@@ -55,7 +64,8 @@
    Making the Tx ring too large decreases the effectiveness of channel
    bonding and packet priority.
    There are no ill effects from too-large receive rings. */
-#define TX_RING_SIZE	8
+#define TX_RING_SIZE	16
+#define TX_QUEUE_LEN	10		/* Limit ring entries actually used.  */
 #define RX_RING_SIZE	16
 
 /* Operational parameters that usually are not changed. */
@@ -64,9 +74,16 @@
 
 #define PKT_BUF_SZ		1536			/* Size of each temporary Rx buffer.*/
 
+
+#if !defined(__OPTIMIZE__)
+#warning  You must compile this file with the correct options!
+#warning  See the last lines of the source file.
+#error  You must compile this driver with "-O".
+#endif
+
+#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/version.h>
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/errno.h>
@@ -82,15 +99,17 @@
 #include <asm/bitops.h>
 #include <asm/io.h>
 
-/* This driver was written to use PCI memory space, however some x86
-   motherboards only configure I/O space accesses correctly. */
-#if defined(__i386__)  &&  !defined(VIA_USE_MEMORY)
-#define VIA_USE_IO
-#endif
-#if defined(__alpha__)
-#define VIA_USE_IO
-#endif
-#ifdef VIA_USE_IO
+/* Condensed bus+endian portability operations. */
+#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr))
+#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr))
+
+/* This driver was written to use PCI memory space, however most versions
+   of the Rhine only work correctly with I/O space accesses. */
+#if defined(VIA_USE_MEMORY)
+#warning Many adapters using the VIA Rhine chip are not configured to work
+#warning with PCI memory space accesses.
+#else
+#define USE_IO_OPS
 #undef readb
 #undef readw
 #undef readl
@@ -105,21 +124,7 @@
 #define writel outl
 #endif
 
-/* Kernel compatibility defines, some common to David Hind's PCMCIA package.
-   This is only in the support-all-kernels source code. */
-
-#define RUN_AT(x) (jiffies + (x))
-
-#if (LINUX_VERSION_CODE >= 0x20100)
-static char kernel_version[] = UTS_RELEASE;
-#else
-#ifndef __alpha__
-#define ioremap vremap
-#define iounmap vfree
-#endif
-#endif
-#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
-MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("VIA Rhine PCI Fast Ethernet driver");
 MODULE_PARM(max_interrupt_work, "i");
 MODULE_PARM(min_pci_latency, "i");
@@ -127,28 +132,6 @@
 MODULE_PARM(rx_copybreak, "i");
 MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
-#endif
-#if LINUX_VERSION_CODE < 0x20123
-#define test_and_set_bit(val, addr) set_bit(val, addr)
-#endif
-#if LINUX_VERSION_CODE <= 0x20139
-#define	net_device_stats enet_statistics
-#else
-#define NETSTATS_VER2
-#endif
-#if LINUX_VERSION_CODE < 0x20155  ||  defined(CARDBUS)
-/* Grrrr, the PCI code changed, but did not consider CardBus... */
-#include <linux/bios32.h>
-#define PCI_SUPPORT_VER1
-#else
-#define PCI_SUPPORT_VER2
-#endif
-#if LINUX_VERSION_CODE < 0x20159
-#define dev_free_skb(skb) dev_kfree_skb(skb, FREE_WRITE);
-#else
-#define dev_free_skb(skb) dev_kfree_skb(skb);
-#endif
-
 
 /*
 				Theory of Operation
@@ -226,13 +209,13 @@
 IVb. References
 
 Preliminary VT86C100A manual from http://www.via.com.tw/
-http://cesdis.gsfc.nasa.gov/linux/misc/100mbps.html
-http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
+http://www.scyld.com/expert/100mbps.html
+http://www.scyld.com/expert/NWay.html
 
 IVc. Errata
 
 The VT86C100A manual is not reliable information.
-The chip does not handle unaligned transmit or receive buffers, resulting
+The 3043 chip does not handle unaligned transmit or receive buffers, resulting
 in significant performance degradation for bounce buffer copies on transmit
 and unaligned IP headers on receive.
 The chip does not pad to minimum transmit length.
@@ -250,6 +233,15 @@
 	PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
 	PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
 };
+
+#if defined(VIA_USE_MEMORY)
+#define RHINE_IOTYPE (PCI_USES_MEM | PCI_USES_MASTER | PCI_ADDR0)
+#define RHINEII_IOSIZE 4096
+#else
+#define RHINE_IOTYPE (PCI_USES_IO  | PCI_USES_MASTER | PCI_ADDR1)
+#define RHINEII_IOSIZE 256
+#endif
+
 struct pci_id_info {
 	const char *name;
 	u16	vendor_id, device_id, device_id_mask, flags;
@@ -264,34 +256,41 @@
 
 static struct pci_id_info pci_tbl[] __initdata = {
 	{ "VIA VT86C100A Rhine-II", 0x1106, 0x6100, 0xffff,
-	  PCI_USES_MEM|PCI_USES_IO|PCI_USES_MEM|PCI_USES_MASTER, 128, via_probe1},
+	  RHINE_IOTYPE, 128, via_probe1},
+	{ "VIA VT6102 Rhine-II", 0x1106, 0x3065, 0xffff,
+	  RHINE_IOTYPE, RHINEII_IOSIZE, via_probe1},
 	{ "VIA VT3043 Rhine", 0x1106, 0x3043, 0xffff,
-	  PCI_USES_IO|PCI_USES_MEM|PCI_USES_MASTER, 128, via_probe1},
+	  RHINE_IOTYPE, 128, via_probe1},
 	{0,},						/* 0 terminated list. */
 };
 
 
 /* A chip capabilities table, matching the entries in pci_tbl[] above. */
-enum chip_capability_flags {CanHaveMII=1, };
+enum chip_capability_flags {
+	CanHaveMII=1, HasESIPhy=2, HasDavicomPhy=4,
+	ReqTxAlign=0x10, HasWOL=0x20,
+};
+
 struct chip_info {
 	int io_size;
 	int flags;
 } static cap_tbl[] __initdata = {
-	{128, CanHaveMII, },
-	{128, CanHaveMII, },
+	{128, CanHaveMII | ReqTxAlign, },
+	{128, CanHaveMII | HasWOL, },
+	{128, CanHaveMII | ReqTxAlign, },
 };
 
 
-/* Offsets to the device registers.
-*/
+/* Offsets to the device registers. */
 enum register_offsets {
 	StationAddr=0x00, RxConfig=0x06, TxConfig=0x07, ChipCmd=0x08,
 	IntrStatus=0x0C, IntrEnable=0x0E,
 	MulticastFilter0=0x10, MulticastFilter1=0x14,
 	RxRingPtr=0x18, TxRingPtr=0x1C,
-	MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIConfig=0x6E,
+	MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIBusConfig=0x6E,
 	MIICmd=0x70, MIIRegAddr=0x71, MIIData=0x72,
-	Config=0x78, RxMissed=0x7C, RxCRCErrs=0x7E,
+	Config=0x78, ConfigA=0x7A, RxMissed=0x7C, RxCRCErrs=0x7E,
+	StickyHW=0x83, WOLcrClr=0xA4, WOLcgClr=0xA7, PwrcsrClr=0xAC,
 };
 
 /* Bits in the interrupt status/mask registers. */
@@ -303,21 +302,18 @@
 	IntrRxOverflow=0x0400, IntrRxDropped=0x0800, IntrRxNoBuf=0x1000,
 	IntrTxAborted=0x2000, IntrLinkChange=0x4000,
 	IntrRxWakeUp=0x8000,
-	IntrNormalSummary=0x0003, IntrAbnormalSummary=0x8260,
+	IntrNormalSummary=0x0003, IntrAbnormalSummary=0xC260,
 };
 
-
 /* The Rx and Tx buffer descriptors. */
 struct rx_desc {
-	u16 rx_status;
-	u16 rx_length;
+	s32 rx_status;
 	u32 desc_length;
 	u32 addr;
 	u32 next_desc;
 };
 struct tx_desc {
-	u16 tx_status;
-	u16 tx_own;
+	s32 tx_status;
 	u32 desc_length;
 	u32 addr;
 	u32 next_desc;
@@ -325,9 +321,10 @@
 
 /* Bits in *_desc.status */
 enum rx_status_bits {
-	RxDescOwn=0x80000000, RxOK=0x8000, RxWholePkt=0x0300, RxErr=0x008F};
+	RxOK=0x8000, RxWholePkt=0x0300, RxErr=0x008F
+};
 enum desc_status_bits {
-	DescOwn=0x8000, DescEndPacket=0x4000, DescIntr=0x1000,
+	DescOwn=0x80000000, DescEndPacket=0x4000, DescIntr=0x1000,
 };
 
 /* Bits in ChipCmd. */
@@ -338,6 +335,7 @@
 	CmdNoTxPoll=0x0800, CmdReset=0x8000,
 };
 
+#define PRIV_ALIGN	15	/* Required alignment mask */
 struct netdev_private {
 	/* Descriptor rings first for alignment. */
 	struct rx_desc rx_ring[RX_RING_SIZE];
@@ -349,12 +347,12 @@
 	unsigned char *tx_buf[TX_RING_SIZE];	/* Tx bounce buffers */
 	unsigned char *tx_bufs;				/* Tx bounce buffer region. */
 	struct device *next_module;			/* Link for devices of this type. */
+	void *priv_addr;					/* Unaligned address for kfree */
 	struct net_device_stats stats;
 	struct timer_list timer;	/* Media monitoring timer. */
 	unsigned char pci_bus, pci_devfn;
 	/* Frequently used values: keep some adjacent for cache effect. */
-	int chip_id;
-	long in_interrupt;			/* Word-long for SMP locks. */
+	int chip_id, drv_flags;
 	struct rx_desc *rx_head_desc;
 	unsigned int cur_rx, dirty_rx;		/* Producer/consumer ring indices */
 	unsigned int cur_tx, dirty_tx;
@@ -388,6 +386,7 @@
 static struct net_device_stats *get_stats(struct device *dev);
 static int mii_ioctl(struct device *dev, struct ifreq *rq, int cmd);
 static int  netdev_close(struct device *dev);
+static inline void clear_tally_counters(long ioaddr);
 
 
 
@@ -432,30 +431,13 @@
 			continue;
 
 		{
-#if defined(PCI_SUPPORT_VER2)
 			struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
-#ifdef VIA_USE_IO
+#ifdef USE_IO_OPS
 			pciaddr = pdev->base_address[0];
 #else
 			pciaddr = pdev->base_address[1];
 #endif
 			irq = pdev->irq;
-#else
-			u32 pci_memaddr;
-			u8 pci_irq_line;
-			pcibios_read_config_byte(pci_bus, pci_device_fn,
-									 PCI_INTERRUPT_LINE, &pci_irq_line);
-#ifdef VIA_USE_IO
-			pcibios_read_config_dword(pci_bus, pci_device_fn,
-									  PCI_BASE_ADDRESS_0, &pci_memaddr);
-			pciaddr = pci_memaddr;
-#else
-			pcibios_read_config_dword(pci_bus, pci_device_fn,
-									  PCI_BASE_ADDRESS_1, &pci_memaddr);
-			pciaddr = pci_memaddr;
-#endif
-			irq = pci_irq_line;
-#endif
 		}
 
 		if (debug > 2)
@@ -511,7 +493,7 @@
 {
 	static int did_version = 0;
 	if (!did_version++)
-		printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
+		printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
 	return pci_etherdev_probe(dev, pci_tbl);
 }
 #endif
@@ -521,6 +503,7 @@
 								 int chip_id, int card_idx)
 {
 	struct netdev_private *np;
+	void *priv_mem;
 	int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0;
 
 	dev = init_etherdev(dev, 0);
@@ -528,14 +511,20 @@
 	printk(KERN_INFO "%s: %s at 0x%lx, ",
 		   dev->name, pci_tbl[chip_id].name, ioaddr);
 
-	/* Ideally we would be read the EEPROM but access may be locked. */
-	for (i = 0; i <6; i++)
+	/* We would prefer to read the EEPROM but access may be locked. */
+	for (i = 0; i < 6; i++)
 		dev->dev_addr[i] = readb(ioaddr + StationAddr + i);
 	for (i = 0; i < 5; i++)
 			printk("%2.2x:", dev->dev_addr[i]);
 	printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
 
-#ifdef VIA_USE_IO
+	/* Allocate driver private memory for descriptor lists.
+	   Check for the very unlikely case of no memory. */
+	priv_mem = kmalloc(sizeof(*np) + PRIV_ALIGN, GFP_KERNEL);
+	if (priv_mem == NULL)
+		return NULL;
+
+#ifdef USE_IO_OPS
 	request_region(ioaddr, pci_tbl[chip_id].io_size, dev->name);
 #endif
 
@@ -546,9 +535,9 @@
 	dev->irq = irq;
 
 	/* Make certain the descriptor lists are cache-aligned. */
-	np = (void *)(((long)kmalloc(sizeof(*np), GFP_KERNEL) + 31) & ~31);
+	dev->priv = np = (void *)(((long)priv_mem + PRIV_ALIGN) & ~PRIV_ALIGN);
 	memset(np, 0, sizeof(*np));
-	dev->priv = np;
+	np->priv_addr = priv_mem;
 
 	np->next_module = root_net_dev;
 	root_net_dev = dev;
@@ -556,6 +545,7 @@
 	np->pci_bus = pci_bus;
 	np->pci_devfn = pci_devfn;
 	np->chip_id = chip_id;
+	np->drv_flags = cap_tbl[chip_id].flags;
 
 	if (dev->mem_start)
 		option = dev->mem_start;
@@ -582,7 +572,7 @@
 	dev->set_multicast_list = &set_rx_mode;
 	dev->do_ioctl = &mii_ioctl;
 
-	if (cap_tbl[np->chip_id].flags & CanHaveMII) {
+	if (np->drv_flags & CanHaveMII) {
 		int phy, phy_idx = 0;
 		np->phys[0] = 1;		/* Standard for this chip. */
 		for (phy = 1; phy < 32 && phy_idx < 4; phy++) {
@@ -625,9 +615,23 @@
 
 static void mdio_write(struct device *dev, int phy_id, int regnum, int value)
 {
+	struct netdev_private *np = (struct netdev_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 	int boguscnt = 1024;
 
+	if (phy_id == np->phys[0]) {
+		switch (regnum) {
+		case 0:					/* Is user forcing speed/duplex? */
+			if (value & 0x9000)	/* Autonegotiation. */
+				np->duplex_lock = 0;
+			else
+				np->full_duplex = (value & 0x0100) ? 1 : 0;
+			break;
+		case 4:
+			np->advertising = value;
+			break;
+		}
+	}
 	/* Wait for a previous command to complete. */
 	while ((readb(ioaddr + MIICmd) & 0x60) && --boguscnt > 0)
 		;
@@ -649,15 +653,17 @@
 	/* Reset the chip. */
 	writew(CmdReset, ioaddr + ChipCmd);
 
-	if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev))
+	MOD_INC_USE_COUNT;
+
+	if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev)) {
+		MOD_DEC_USE_COUNT;
 		return -EAGAIN;
+	}
 
 	if (debug > 1)
 		printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",
 			   dev->name, dev->irq);
 
-	MOD_INC_USE_COUNT;
-
 	init_ring(dev);
 
 	writel(virt_to_bus(np->rx_ring), ioaddr + RxRingPtr);
@@ -667,7 +673,7 @@
 		writeb(dev->dev_addr[i], ioaddr + StationAddr + i);
 
 	/* Initialize other registers. */
-	writew(0x0006, ioaddr + PCIConfig);	/* Tune configuration??? */
+	writew(0x0006, ioaddr + PCIBusConfig);	/* Tune configuration??? */
 	/* Configure the FIFO thresholds. */
 	writeb(0x20, ioaddr + TxConfig);	/* Initial threshold 32 bytes */
 	np->tx_thresh = 0x20;
@@ -678,7 +684,6 @@
 
 	dev->tbusy = 0;
 	dev->interrupt = 0;
-	np->in_interrupt = 0;
 
 	set_rx_mode(dev);
 
@@ -696,6 +701,11 @@
 	writew(np->chip_cmd, ioaddr + ChipCmd);
 
 	check_duplex(dev);
+	/* The LED outputs of various MII xcvrs should be configured.  */
+	/* For NS or Mison phys, turn on bit 1 in register 0x17 */
+	/* For ESI phys, turn on bit 7 in register 0x17. */
+	mdio_write(dev, np->phys[0], 0x17, mdio_read(dev, np->phys[0], 0x17) |
+			   (np->drv_flags & HasESIPhy) ? 0x0080 : 0x0001);
 
 	if (debug > 2)
 		printk(KERN_DEBUG "%s: Done netdev_open(), status %4.4x "
@@ -705,7 +715,7 @@
 
 	/* Set the timer to check for link beat. */
 	init_timer(&np->timer);
-	np->timer.expires = RUN_AT(1);
+	np->timer.expires = jiffies + 2;
 	np->timer.data = (unsigned long)dev;
 	np->timer.function = &netdev_timer;				/* timer handler */
 	add_timer(&np->timer);
@@ -718,11 +728,12 @@
 	struct netdev_private *np = (struct netdev_private *)dev->priv;
 	long ioaddr = dev->base_addr;
 	int mii_reg5 = mdio_read(dev, np->phys[0], 5);
+	int negotiated = mii_reg5 & np->advertising;
 	int duplex;
 
 	if (np->duplex_lock  ||  mii_reg5 == 0xffff)
 		return;
-	duplex = (mii_reg5 & 0x0100) || (mii_reg5 & 0x01C0) == 0x0040;
+	duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
 	if (np->full_duplex != duplex) {
 		np->full_duplex = duplex;
 		if (debug)
@@ -748,9 +759,14 @@
 		printk(KERN_DEBUG "%s: VIA Rhine monitor tick, status %4.4x.\n",
 			   dev->name, readw(ioaddr + IntrStatus));
 	}
+	if (test_bit(0, (void*)&dev->tbusy) != 0
+		&& np->cur_tx - np->dirty_tx > 1
+		&& jiffies - dev->trans_start > TX_TIMEOUT)
+		tx_timeout(dev);
+
 	check_duplex(dev);
 
-	np->timer.expires = RUN_AT(next_tick);
+	np->timer.expires = jiffies + next_tick;
 	add_timer(&np->timer);
 }
 
@@ -764,15 +780,15 @@
 		   dev->name, readw(ioaddr + IntrStatus),
 		   mdio_read(dev, np->phys[0], 1));
 
-  /* Perhaps we should reinitialize the hardware here. */
-  dev->if_port = 0;
-  /* Stop and restart the chip's Tx processes . */
-
-  /* Trigger an immediate transmit demand. */
-
-  dev->trans_start = jiffies;
-  np->stats.tx_errors++;
-  return;
+	/* Perhaps we should reinitialize the hardware here. */
+	dev->if_port = 0;
+	/* Stop and restart the chip's Tx processes . */
+
+	/* Trigger an immediate transmit demand. */
+
+	dev->trans_start = jiffies;
+	np->stats.tx_errors++;
+	return;
 }
 
 
@@ -791,35 +807,33 @@
 
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		np->rx_ring[i].rx_status = 0;
-		np->rx_ring[i].rx_length = 0;
-		np->rx_ring[i].desc_length = np->rx_buf_sz;
-		np->rx_ring[i].next_desc = virt_to_bus(&np->rx_ring[i+1]);
+		np->rx_ring[i].desc_length = cpu_to_le32(np->rx_buf_sz);
+		np->rx_ring[i].next_desc = virt_to_le32desc(&np->rx_ring[i+1]);
 		np->rx_skbuff[i] = 0;
 	}
 	/* Mark the last entry as wrapping the ring. */
-	np->rx_ring[i-1].next_desc = virt_to_bus(&np->rx_ring[0]);
+	np->rx_ring[i-1].next_desc = virt_to_le32desc(&np->rx_ring[0]);
 
-	/* Fill in the Rx buffers. */
+	/* Fill in the Rx buffers.  Handle allocation failure gracefully. */
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz);
 		np->rx_skbuff[i] = skb;
 		if (skb == NULL)
 			break;
 		skb->dev = dev;			/* Mark as being used by this device. */
-		np->rx_ring[i].addr = virt_to_bus(skb->tail);
-		np->rx_ring[i].rx_status = 0;
-		np->rx_ring[i].rx_length = DescOwn;
+		np->rx_ring[i].addr = virt_to_le32desc(skb->tail);
+		np->rx_ring[i].rx_status = cpu_to_le32(DescOwn);
 	}
 	np->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
 
 	for (i = 0; i < TX_RING_SIZE; i++) {
 		np->tx_skbuff[i] = 0;
-		np->tx_ring[i].tx_own = 0;
-		np->tx_ring[i].desc_length = 0x00e08000;
-		np->tx_ring[i].next_desc = virt_to_bus(&np->tx_ring[i+1]);
+		np->tx_ring[i].tx_status = 0;
+		np->tx_ring[i].desc_length = cpu_to_le32(0x00e08000);
+		np->tx_ring[i].next_desc = virt_to_le32desc(&np->tx_ring[i+1]);
 		np->tx_buf[i] = kmalloc(PKT_BUF_SZ, GFP_KERNEL);
 	}
-	np->tx_ring[i-1].next_desc = virt_to_bus(&np->tx_ring[0]);
+	np->tx_ring[i-1].next_desc = virt_to_le32desc(&np->tx_ring[0]);
 
 	return;
 }
@@ -832,41 +846,45 @@
 	/* Block a timer-based transmit from overlapping.  This could better be
 	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
 	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
-		if (jiffies - dev->trans_start < TX_TIMEOUT)
-			return 1;
-		tx_timeout(dev);
+		/* This watchdog code is redundant with the media monitor timer. */
+		if (jiffies - dev->trans_start > TX_TIMEOUT)
+			tx_timeout(dev);
 		return 1;
 	}
 
-	/* Caution: the write order is important here, set the field
-	   with the "ownership" bits last. */
+	/* Explicitly flush packet data cache lines here. */
+
+	/* Caution: the write order is important here, set the descriptor word
+	   with the "ownership" bit last.  No SMP locking is needed if the
+	   cur_tx is incremented after the descriptor is consistent.  */
 
 	/* Calculate the next Tx descriptor entry. */
 	entry = np->cur_tx % TX_RING_SIZE;
 
 	np->tx_skbuff[entry] = skb;
 
-	if ((long)skb->data & 3) {			/* Must use alignment buffer. */
+	if ((np->drv_flags & ReqTxAlign)  && ((long)skb->data & 3)) {
+		/* Must use alignment buffer. */
 		if (np->tx_buf[entry] == NULL &&
 			(np->tx_buf[entry] = kmalloc(PKT_BUF_SZ, GFP_KERNEL)) == NULL)
 			return 1;
 		memcpy(np->tx_buf[entry], skb->data, skb->len);
-		np->tx_ring[entry].addr = virt_to_bus(np->tx_buf[entry]);
+		np->tx_ring[entry].addr = virt_to_le32desc(np->tx_buf[entry]);
 	} else
-		np->tx_ring[entry].addr = virt_to_bus(skb->data);
+		np->tx_ring[entry].addr = virt_to_le32desc(skb->data);
 
-	np->tx_ring[entry].desc_length = 0x00E08000 |
-		(skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN);
-	np->tx_ring[entry].tx_own = DescOwn;
+	np->tx_ring[entry].desc_length =
+		cpu_to_le32(0x00E08000 | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
+	np->tx_ring[entry].tx_status = cpu_to_le32(DescOwn);
 
 	np->cur_tx++;
 
-	/* Non-x86 Todo: explicitly flush cache lines here. */
+	/* Explicitly flush descriptor cache lines here. */
 
 	/* Wake the potentially-idle transmit channel. */
 	writew(CmdTxDemand | np->chip_cmd, dev->base_addr + ChipCmd);
 
-	if (np->cur_tx - np->dirty_tx < TX_RING_SIZE - 1)
+	if (np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 1)
 		clear_bit(0, (void*)&dev->tbusy);		/* Typical path */
 	else
 		np->tx_full = 1;
@@ -884,26 +902,9 @@
 static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
 {
 	struct device *dev = (struct device *)dev_instance;
-	struct netdev_private *np;
-	long ioaddr, boguscnt = max_interrupt_work;
-
-	ioaddr = dev->base_addr;
-	np = (struct netdev_private *)dev->priv;
-#if defined(__i386__)
-	/* A lock to prevent simultaneous entry bug on Intel SMP machines. */
-	if (test_and_set_bit(0, (void*)&dev->interrupt)) {
-		printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n",
-			   dev->name);
-		dev->interrupt = 0;	/* Avoid halting machine. */
-		return;
-	}
-#else
-	if (dev->interrupt) {
-		printk(KERN_ERR "%s: Re-entering the interrupt handler.\n", dev->name);
-		return;
-	}
-	dev->interrupt = 1;
-#endif
+	struct netdev_private *np = (void *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int boguscnt = max_interrupt_work;
 
 	do {
 		u32 intr_status = readw(ioaddr + IntrStatus);
@@ -924,10 +925,9 @@
 
 		for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
 			int entry = np->dirty_tx % TX_RING_SIZE;
-			int txstatus;
-			if (np->tx_ring[entry].tx_own)
+			int txstatus = le32_to_cpu(np->tx_ring[entry].tx_status);
+			if (txstatus & DescOwn)
 				break;
-			txstatus = np->tx_ring[entry].tx_status;
 			if (debug > 6)
 				printk(KERN_DEBUG " Tx scavenge %d status %4.4x.\n",
 					   entry, txstatus);
@@ -951,16 +951,16 @@
 #endif
 				np->stats.collisions += (txstatus >> 3) & 15;
 #if defined(NETSTATS_VER2)
-				np->stats.tx_bytes += np->tx_ring[entry].desc_length & 0x7ff;
+				np->stats.tx_bytes += np->tx_skbuff[entry]->len;
 #endif
 				np->stats.tx_packets++;
 			}
 			/* Free the original skb. */
-			dev_free_skb(np->tx_skbuff[entry]);
+			dev_kfree_skb(np->tx_skbuff[entry]);
 			np->tx_skbuff[entry] = 0;
 		}
 		if (np->tx_full && dev->tbusy
-			&& np->cur_tx - np->dirty_tx < TX_RING_SIZE - 4) {
+			&& np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) {
 			/* The ring is no longer full, clear tbusy. */
 			np->tx_full = 0;
 			clear_bit(0, (void*)&dev->tbusy);
@@ -984,11 +984,6 @@
 		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
 			   dev->name, readw(ioaddr + IntrStatus));
 
-#if defined(__i386__)
-	clear_bit(0, (void*)&dev->interrupt);
-#else
-	dev->interrupt = 0;
-#endif
 	return;
 }
 
@@ -1001,15 +996,15 @@
 	int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
 
 	if (debug > 4) {
-		printk(KERN_DEBUG " In netdev_rx(), entry %d status %4.4x.\n",
-			   entry, np->rx_head_desc->rx_length);
+		printk(KERN_DEBUG " In netdev_rx(), entry %d status %8.8x.\n",
+			   entry, np->rx_head_desc->rx_status);
 	}
 
 	/* If EOP is set on the next entry, it's a new packet. Send it up. */
-	while ( ! (np->rx_head_desc->rx_length & DescOwn)) {
+	while ( ! (np->rx_head_desc->rx_status & cpu_to_le32(DescOwn))) {
 		struct rx_desc *desc = np->rx_head_desc;
-		int data_size = desc->rx_length;
-		u16 desc_status = desc->rx_status;
+		u32 desc_status = le32_to_cpu(desc->rx_status);
+		int data_size = desc_status >> 16;
 
 		if (debug > 4)
 			printk(KERN_DEBUG "  netdev_rx() status is %4.4x.\n",
@@ -1039,7 +1034,7 @@
 		} else {
 			struct sk_buff *skb;
 			/* Length should omit the CRC */
-			u16 pkt_len = data_size - 4;
+			int pkt_len = data_size - 4;
 
 			/* Check if the packet is long enough to accept without copying
 			   to a minimally-sized skbuff. */
@@ -1047,21 +1042,23 @@
 				&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
 				skb->dev = dev;
 				skb_reserve(skb, 2);	/* 16 byte align the IP header */
-#if ! defined(__alpha__) || USE_IP_COPYSUM		/* Avoid misaligned on Alpha */
-				eth_copy_and_sum(skb, bus_to_virt(desc->addr),
-								 pkt_len, 0);
+#if HAS_IP_COPYSUM			/* Call copy + cksum if available. */
+				eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0);
 				skb_put(skb, pkt_len);
 #else
-				memcpy(skb_put(skb,pkt_len), bus_to_virt(desc->addr), pkt_len);
+				memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail,
+					   pkt_len);
 #endif
 			} else {
 				skb_put(skb = np->rx_skbuff[entry], pkt_len);
 				np->rx_skbuff[entry] = NULL;
 			}
 			skb->protocol = eth_type_trans(skb, dev);
-			np->stats.rx_bytes+=skb->len;
 			netif_rx(skb);
 			dev->last_rx = jiffies;
+#if defined(NETSTATS_VER2)
+			np->stats.rx_bytes += skb->len;
+#endif
 			np->stats.rx_packets++;
 		}
 		entry = (++np->cur_rx) % RX_RING_SIZE;
@@ -1078,10 +1075,9 @@
 			if (skb == NULL)
 				break;			/* Better luck next round. */
 			skb->dev = dev;			/* Mark as being used by this device. */
-			np->rx_ring[entry].addr = virt_to_bus(skb->tail);
+			np->rx_ring[entry].addr = virt_to_le32desc(skb->tail);
 		}
-		np->rx_ring[entry].rx_status = 0;
-		np->rx_ring[entry].rx_length = DescOwn;
+		np->rx_ring[entry].rx_status = cpu_to_le32(DescOwn);
 	}
 
 	/* Pre-emptively restart Rx engine. */
@@ -1095,10 +1091,11 @@
 	long ioaddr = dev->base_addr;
 
 	if (intr_status & (IntrMIIChange | IntrLinkChange)) {
-		if (readb(ioaddr + MIIStatus) & 0x02)
+		if (readb(ioaddr + MIIStatus) & 0x02) {
 			/* Link failed, restart autonegotiation. */
-			mdio_write(dev, np->phys[0], 0, 0x3300);
-		else
+			if (np->drv_flags & HasDavicomPhy)
+				mdio_write(dev, np->phys[0], 0, 0x3300);
+		} else
 			check_duplex(dev);
 		if (debug)
 			printk(KERN_ERR "%s: MII status changed: Autonegotiation "
@@ -1109,7 +1106,7 @@
 	if (intr_status & IntrStatsMax) {
 		np->stats.rx_crc_errors	+= readw(ioaddr + RxCRCErrs);
 		np->stats.rx_missed_errors	+= readw(ioaddr + RxMissed);
-		writel(0, RxMissed);
+		clear_tally_counters(ioaddr);
 	}
 	if (intr_status & IntrTxAbort) {
 		/* Stats counted in Tx-done handler, just restart Tx. */
@@ -1122,7 +1119,8 @@
 			printk(KERN_INFO "%s: Transmitter underrun, increasing Tx "
 				   "threshold setting to %2.2x.\n", dev->name, np->tx_thresh);
 	}
-	if ((intr_status & ~(IntrLinkChange|IntrStatsMax|IntrTxAbort)) && debug) {
+	if ((intr_status & ~(IntrLinkChange | IntrStatsMax |
+						 IntrTxAbort|IntrTxAborted))  &&  debug) {
 		printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
 			   dev->name, intr_status);
 		/* Recovery for other fault sources not known. */
@@ -1140,28 +1138,39 @@
 	   non-critical. */
 	np->stats.rx_crc_errors	+= readw(ioaddr + RxCRCErrs);
 	np->stats.rx_missed_errors	+= readw(ioaddr + RxMissed);
-	writel(0, RxMissed);
+	clear_tally_counters(ioaddr);
 
 	return &np->stats;
 }
 
+/* Clears the "tally counters" for CRC errors and missed frames(?).
+   It has been reported that some chips need a write of 0 to clear
+   these, for others the counters are set to 1 when written to and
+   instead cleared when read. So we clear them both ways ... */
+static inline void clear_tally_counters(const long ioaddr)
+{
+	writel(0, ioaddr + RxMissed);
+	readw(ioaddr + RxCRCErrs);
+	readw(ioaddr + RxMissed);
+}
+
 /* The big-endian AUTODIN II ethernet CRC calculation.
    N.B. Do not use for bulk data, use a table-based routine instead.
    This is common code and should be moved to net/core/crc.c */
 static unsigned const ethernet_polynomial = 0x04c11db7U;
 static inline u32 ether_crc(int length, unsigned char *data)
 {
-    int crc = -1;
+	int crc = -1;
 
-    while(--length >= 0) {
+	while(--length >= 0) {
 		unsigned char current_octet = *data++;
 		int bit;
 		for (bit = 0; bit < 8; bit++, current_octet >>= 1) {
 			crc = (crc << 1) ^
 				((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
 		}
-    }
-    return crc;
+	}
+	return crc;
 }
 
 static void set_rx_mode(struct device *dev)
@@ -1178,6 +1187,8 @@
 	} else if ((dev->mc_count > multicast_filter_limit)
 			   ||  (dev->flags & IFF_ALLMULTI)) {
 		/* Too many to match, or accept all multicasts. */
+		writel(0xffffffff, ioaddr + MulticastFilter0);
+		writel(0xffffffff, ioaddr + MulticastFilter1);
 		rx_mode = 0x0C;
 	} else {
 		struct dev_mc_list *mclist;
@@ -1190,7 +1201,7 @@
 		}
 		writel(mc_filter[0], ioaddr + MulticastFilter0);
 		writel(mc_filter[1], ioaddr + MulticastFilter1);
-		rx_mode = 0x08;
+		rx_mode = 0x0C;
 	}
 	writeb(np->rx_thresh | rx_mode, ioaddr + RxConfig);
 }
@@ -1207,7 +1218,7 @@
 		data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
 		return 0;
 	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
-		if (!suser())
+		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
 		mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
 		return 0;
@@ -1229,32 +1240,39 @@
 		printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n",
 			   dev->name, readw(ioaddr + ChipCmd));
 
+	del_timer(&np->timer);
+
+	/* Switch to loopback mode to avoid hardware races. */
+	writeb(np->tx_thresh | 0x01, ioaddr + TxConfig);
+
 	/* Disable interrupts by clearing the interrupt mask. */
 	writew(0x0000, ioaddr + IntrEnable);
 
 	/* Stop the chip's Tx and Rx processes. */
 	writew(CmdStop, ioaddr + ChipCmd);
 
-	del_timer(&np->timer);
-
 	free_irq(dev->irq, dev);
 
 	/* Free all the skbuffs in the Rx queue. */
 	for (i = 0; i < RX_RING_SIZE; i++) {
-		np->rx_ring[i].rx_length = 0;
+		np->rx_ring[i].rx_status = 0;
 		np->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */
 		if (np->rx_skbuff[i]) {
 #if LINUX_VERSION_CODE < 0x20100
 			np->rx_skbuff[i]->free = 1;
 #endif
-			dev_free_skb(np->rx_skbuff[i]);
+			dev_kfree_skb(np->rx_skbuff[i]);
 		}
 		np->rx_skbuff[i] = 0;
 	}
 	for (i = 0; i < TX_RING_SIZE; i++) {
 		if (np->tx_skbuff[i])
-			dev_free_skb(np->tx_skbuff[i]);
+			dev_kfree_skb(np->tx_skbuff[i]);
 		np->tx_skbuff[i] = 0;
+		if (np->tx_buf[i]) {
+			kfree(np->tx_buf[i]);
+			np->tx_buf[i] = 0;
+		}
 	}
 
 	MOD_DEC_USE_COUNT;
@@ -1267,37 +1285,28 @@
 int init_module(void)
 {
 	if (debug)					/* Emit version even if no cards detected. */
-		printk(KERN_INFO "%s" KERN_INFO "%s", versionA, versionB);
-#ifdef CARDBUS
-	register_driver(&etherdev_ops);
-	return 0;
-#else
+		printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
 	return pci_etherdev_probe(NULL, pci_tbl);
-#endif
 }
 
 void cleanup_module(void)
 {
-
-#ifdef CARDBUS
-	unregister_driver(&etherdev_ops);
-#endif
+	struct device *next_dev;
 
 	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
 	while (root_net_dev) {
-		struct netdev_private *np =
-			(struct netdev_private *)(root_net_dev->priv);
+		struct netdev_private *np = (void *)(root_net_dev->priv);
 		unregister_netdev(root_net_dev);
-#ifdef VIA_USE_IO
+#ifdef USE_IO_OPS
 		release_region(root_net_dev->base_addr, pci_tbl[np->chip_id].io_size);
 #else
 		iounmap((char *)(root_net_dev->base_addr));
 #endif
+		next_dev = np->next_module;
+		if (np->priv_addr)
+			kfree(np->priv_addr);
 		kfree(root_net_dev);
-		root_net_dev = np->next_module;
-#if 0
-		kfree(np);				/* Assumption: no struct realignment. */
-#endif
+		root_net_dev = next_dev;
 	}
 }
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/Config.in linux.19p18/drivers/s390/Config.in
--- linux.vanilla/drivers/s390/Config.in	Mon Dec 11 22:12:51 2000
+++ linux.19p18/drivers/s390/Config.in	Mon Feb 19 18:37:07 2001
@@ -53,7 +53,7 @@
   if [ "$CONFIG_NETDEVICES" = "y" ]; then
     comment 'S390 Network devices'
     tristate 'CTC device support' CONFIG_CTC
-    bool 'IUCV device support (VM only)' CONFIG_IUCV
+    tristate 'IUCV device support (VM only)' CONFIG_IUCV
     tristate 'Dummy net driver support' CONFIG_DUMMY
     bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET
     bool 'Token Ring driver support' CONFIG_TR
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/Makefile linux.19p18/drivers/s390/Makefile
--- linux.vanilla/drivers/s390/Makefile	Mon Dec 11 22:12:51 2000
+++ linux.19p18/drivers/s390/Makefile	Mon Feb 19 18:33:37 2001
@@ -11,12 +11,13 @@
 
 CFLAGS += 
 O_TARGET := io.o
-O_OBJS   := ccwcache.o idals.o
+O_OBJS   := idals.o
+OX_OBJS  := ccwcache.o
 M_OBJS   :=
 
 SUBDIRS := $(SUBDIRS) arch/s390/drivers/block arch/s390/drivers/char \
 	arch/s390/drivers/misc  arch/s390/drivers/net
-MOD_SUB_DIRS += ./net ./block
+MOD_SUB_DIRS += ./net ./block ./char
 
 O_OBJS += block/s390-block.o \
   char/s390-char.o \
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/block/Makefile linux.19p18/drivers/s390/block/Makefile
--- linux.vanilla/drivers/s390/block/Makefile	Mon Dec 11 22:12:51 2000
+++ linux.19p18/drivers/s390/block/Makefile	Tue Feb 20 13:26:25 2001
@@ -4,10 +4,11 @@
 O_TARGET := s390-block.o
 O_OBJS   := 
 M_OBJS   :=
-D_OBJS   :=
+MI_OBJS  :=
+MIX_OBJS :=
 
 ifeq ($(CONFIG_DASD),y)
-  O_OBJS += dasd.o
+  OX_OBJS += dasd.o
   ifeq ($(CONFIG_DASD_ECKD),y)
    O_OBJS += dasd_eckd.o  dasd_3990_erp.o dasd_9343_erp.o
   endif 
@@ -17,26 +18,20 @@
   ifeq ($(CONFIG_DASD_MDSK),y)
    O_OBJS += dasd_diag.o
   endif 
-#  ifeq ($(CONFIG_DASD_CKD),y)
-#   O_OBJS += dasd_ckd.o
-#  endif 
 endif
 
 ifeq ($(CONFIG_DASD),m)
   M_OBJS += dasd_mod.o
-  D_OBJS += dasd.o 
+  MIX_OBJS += dasd.o 
   ifeq ($(CONFIG_DASD_ECKD),y)
-   D_OBJS += dasd_eckd.o  dasd_3990_erp.o dasd_9343_erp.o
+   MI_OBJS += dasd_eckd.o  dasd_3990_erp.o dasd_9343_erp.o
   endif 
   ifeq ($(CONFIG_DASD_FBA),y)
-   D_OBJS += dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o
+   MI_OBJS += dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o
   endif 
   ifeq ($(CONFIG_DASD_MDSK),y)
-   D_OBJS += dasd_diag.o
+   MI_OBJS += dasd_diag.o
   endif 
-#  ifeq ($(CONFIG_DASD_CKD),y)
-#   O_OBJS += dasd_ckd.o
-#  endif 
 endif
 
 ifeq ($(CONFIG_MDISK),y)
@@ -51,7 +46,7 @@
  endif
 endif
 
-dasd_mod.o: $(D_OBJS)
-	$(LD) $(LD_RFLAG) -r -o $@ $(D_OBJS)
+dasd_mod.o: $(MI_OBJS) $(MIX_OBJS)
+	$(LD) $(LD_RFLAG) -r -o $@ $(MI_OBJS) $(MIX_OBJS)
 
 include $(TOPDIR)/Rules.make
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/block/dasd.c linux.19p18/drivers/s390/block/dasd.c
--- linux.vanilla/drivers/s390/block/dasd.c	Mon Dec 11 22:12:51 2000
+++ linux.19p18/drivers/s390/block/dasd.c	Sun Feb 25 23:10:56 2001
@@ -1,9 +1,10 @@
 /* 
  * File...........: linux/drivers/s390/block/dasd.c
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ *                  Horst Hummel <Horst.Hummel@de.ibm.com>  
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
-
+ *
  * History of changes (starts July 2000)
  * 07/03/00 Adapted code to compile with 2.2 and 2.4 kernels
  * 07/05/00 Added some missing cases when shutting down a device
@@ -36,8 +37,14 @@
  * 10/26/00 fixed ITPM PL010261EPA race condition when formatting  
             are the fixes in dasd_do_chanq
  * 11/21/00 fixed BLKFLSBUF ioctl and dasd_release to flush the buffers
+ * 01/17/01 fixed PL020234MVE problem accessing DASD 68-127, 133-191,...
+ * 01/23/01 fixed sleep_on_request to terminate when signal_pending
+ * 01/25/01 added code for error recovery with PAC'0x1D' = long busy
+ * 02/08/01 fixed PL020237RMI
+ * 02/08/01 fixed PL020265TDI
  */
 
+#include <linux/module.h>
 #include <linux/config.h>
 #include <linux/version.h>
 #include <linux/init.h>
@@ -96,12 +103,7 @@
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
 static struct block_device_operations dasd_device_operations;
 #endif /* VERSION_CODE */
-  
-#ifdef MODULE
-#define EXPORT_SYMTAB
-#include <linux/module.h>
 
-EXPORT_NO_SYMBOLS;
 MODULE_AUTHOR ("Holger Smolinski <Holger.Smolinski@de.ibm.com>");
 MODULE_DESCRIPTION ("Linux on S/390 DASD device driver, Copyright 2000 IBM Corporation");
 MODULE_SUPPORTED_DEVICE("dasd");
@@ -113,13 +115,8 @@
 EXPORT_SYMBOL (dasd_alloc_request);
 EXPORT_SYMBOL (dasd_free_request);
 
-#else
-#endif				/* MODULE */
-
 /* SECTION: Constant definitions to be used within this file */
-#ifdef PRINTK_HEADER
 #undef PRINTK_HEADER
-#endif
 #define PRINTK_HEADER DASD_NAME":"
 
 #define DASD_QUEUE_LIMIT 10
@@ -252,7 +249,7 @@
 
 static char dasd_parm_string[1024] = {0,};
 
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,2,17))
 static int
 dasd_setup (char *str) 
 {
@@ -280,7 +277,7 @@
 #endif /* LINUX_IS_24 */
 
 
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,2,17))
 __setup("dasd=", dasd_setup);
 #endif /* LINUX_IS_24 */
 
@@ -476,7 +473,7 @@
  * void dasd_chanq_enq (dasd_chanq_t * q, ccw_req_t * cqr)
  */
 
-static void
+void
 dasd_chanq_enq (dasd_chanq_t * q, ccw_req_t * cqr)
 {
 	if (q->head != NULL) {
@@ -493,7 +490,7 @@
  * void dasd_chanq_enq_head (dasd_chanq_t * q, ccw_req_t * cqr)
  */
 
-static void
+void
 dasd_chanq_enq_head (dasd_chanq_t * q, ccw_req_t * cqr)
 {
 	cqr->next = q->head;
@@ -501,14 +498,17 @@
 	if (q->tail == NULL)
 		q->tail = cqr;
 	q->queued_requests++;
-	atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_FILLED, CQR_STATUS_QUEUED);
+
+        atomic_compare_and_swap_debug (&cqr->status, 
+                                       CQR_STATUS_FILLED, 
+                                       CQR_STATUS_QUEUED);
 }
 
 /* 
  * int dasd_chanq_deq (dasd_chanq_t * q, ccw_req_t * cqr)
  */
 
-static int
+int
 dasd_chanq_deq (dasd_chanq_t * q, ccw_req_t * cqr)
 {
 	ccw_req_t *prev;
@@ -776,9 +776,8 @@
 	int retries = DASD_SSCH_RETRIES;
 	dasd_device_t *device = cqr->device;
 	int irq, devno;
-	int devindex, partn;
+	int devindex;
 	major_info_t *major_info;
-	struct request *req;
 
 	if (!cqr) {
 		printk (KERN_WARNING PRINTK_HEADER "No request passed to start_io function");
@@ -786,10 +785,9 @@
 	}
 	irq = device->devinfo.irq;
 	devno = device->devinfo.devno;
-	req = (struct request *) cqr->req;
-	devindex = devindex_from_kdev_t (req->rq_dev);
+	devindex = devindex_from_devno (devno);
 	major_info = major_info_from_devindex (devindex);
-	partn = MINOR (req->rq_dev) & ((1 << major_info->gendisk.minor_shift) - 1);
+
 	if (strncmp ((char *) &cqr->magic, device->discipline->ebcname, 4)) {
 		printk (KERN_WARNING PRINTK_HEADER
 			"0x%04X on sch %d = /dev/%s (%d:%d)"
@@ -801,10 +799,12 @@
 			cqr->magic, *(long *) device->discipline->name);
 		return -EINVAL;
 	}
-	atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_QUEUED, CQR_STATUS_IN_IO);
+	atomic_compare_and_swap_debug (&cqr->status, 
+                                       CQR_STATUS_QUEUED, 
+                                       CQR_STATUS_IN_IO);
 	do {
 		asm volatile ("STCK %0":"=m" (cqr->startclk));
-		rc = do_IO (irq, cqr->cpaddr, (long) cqr, 0x00, cqr->options);
+		rc = do_IO (irq, cqr->cpaddr, (long) cqr, cqr->lpm, cqr->options);
 		switch (rc) {
 		case 0:
                         if (!(cqr->options & DOIO_WAIT_FOR_INTERRUPT)) {
@@ -848,7 +848,7 @@
 	if (rc) {
                 atomic_compare_and_swap_debug (&cqr->status, 
                                                CQR_STATUS_IN_IO, 
-                                               CQR_STATUS_ERROR);
+                                               CQR_STATUS_FAILED);
 	}
 	return rc;
 }
@@ -879,6 +879,10 @@
                 schedule ();
                 s390irq_spin_lock_irqsave (device->devinfo.irq, flags);
                 cs = atomic_read (&req->status);
+		if ( signal_pending(current) ) {
+			rc = -ERESTARTSYS;
+			break;
+		}
         } while ( ! (cs & CQR_STATUS_FINISHED) );
         /* was originally: while ((cs != CQR_STATUS_DONE) && (cs != CQR_STATUS_FAILED)); */ 
         remove_wait_queue (&device->wait_q, &wait);
@@ -1178,189 +1182,216 @@
 					printk (KERN_WARNING PRINTK_HEADER
 						" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
 						" Failing to start I/O operation with rc %d\n",
-						devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, rc);
+						devno, irq, device->name, major_from_devindex (devindex), 
+                                                devindex << DASD_PARTN_BITS, rc);
 					switch (rc) {
 					case EBUSY:
 						if (cqr->retries--) {
 							printk (KERN_WARNING PRINTK_HEADER
 								" devno 0x%04X on subchannel %d = /dev/%s (%d:%d) busy:"
 								" retrying ... %d retries left\n",
-								devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, cqr->retries);
+								devno, irq, device->name, major_from_devindex (devindex), 
+                                                                devindex << DASD_PARTN_BITS, cqr->retries);
 							break;
 						}
 					default:{	/* Fallthrough ?? */
 							printk (KERN_WARNING PRINTK_HEADER
 								" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
 								" Giving up this request!\n",
-								devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
-
-							atomic_compare_and_swap_debug (&cqr->status,
-                                                                                       CQR_STATUS_QUEUED,
-                                                                                       CQR_STATUS_FAILED | CQR_STATUS_FINISHED);
+								devno, irq, device->name, major_from_devindex (devindex),
+                                                                devindex << DASD_PARTN_BITS);
 							break;
 						}
 					}
 				}
 				break;
 			case CQR_STATUS_IN_IO:{
-                                        unsigned long long now;
-                                        unsigned long long delta;
-                                        
-					asm volatile ("STCK %0":"=m" (now));
-					if (cqr->expires && cqr->startclk &&
-					    cqr->expires < now) {
-                                                delta = cqr->expires - cqr->startclk;
-						printk (KERN_ERR PRINTK_HEADER
-							" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
-							" I/O operation outstanding longer than 0x%08x%08x usecs on req %p\n",
-							devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, (long)(delta >> 44), (long)(delta >> 12), cqr);
-							cqr->expires += delta;
+                                unsigned long long now;
+                                unsigned long long delta;
+                                
+                                asm volatile ("STCK %0":"=m" (now));
+                                if (cqr->expires && cqr->startclk &&
+                                    cqr->expires < now) {
+                                        delta = cqr->expires - cqr->startclk;
+                                        printk (KERN_ERR PRINTK_HEADER
+                                                " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                " I/O operation outstanding longer than 0x%08lx%08lx usecs on req %p\n",
+                                                devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, (long)(delta >> 44), (long)(delta >> 12), cqr);
+                                        cqr->expires += delta;
 #if 0
-						if ( cqr->retries-- ) {
-							printk (KERN_WARNING PRINTK_HEADER
-								" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
-								" waiting %d more times\n",
-								devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, cqr->retries);
-							cqr->expires += delta;
-							break;
-						} else {
-							printk (KERN_WARNING PRINTK_HEADER
-								" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
-								" You should disable that device by issueing '@#?!'\n",		/* FIXME */
-								devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
-							atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_FAILED);
-							halt_IO(irq,(unsigned long)cqr, DOIO_WAIT_FOR_INTERRUPT);
-							break;
-						}
+                                        if ( cqr->retries-- ) {
+                                                printk (KERN_WARNING PRINTK_HEADER
+                                                        " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                        " waiting %d more times\n",
+                                                        devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, cqr->retries);
+                                                cqr->expires += delta;
+                                                break;
+                                        } else {
+                                                printk (KERN_WARNING PRINTK_HEADER
+                                                        " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                        " You should disable that device by issueing '@#?!'\n",		/* FIXME */
+                                                        devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
+                                                atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_FAILED);
+                                                halt_IO(irq,(unsigned long)cqr, DOIO_WAIT_FOR_INTERRUPT);
+                                                break;
+                                        }
 #endif
-					}
-					break;
+                                }
+                                break;
                         }
 			case CQR_STATUS_ERROR:{
-                                        dasd_erp_action_fn_t erp_action;
-                                        ccw_req_t *erp_cqr = NULL;
-                                        
- 					if (cqr->dstat->flag & DEVSTAT_HALT_FUNCTION) {
- 						atomic_compare_and_swap_debug(&cqr->status,CQR_STATUS_ERROR,CQR_STATUS_FAILED);
-                                                next = cqr;
-                                        } else if ( cqr -> retries--  &&
-                                             cqr -> refers == NULL &&
-                                             discipline -> erp_action != NULL &&
-                                             (erp_action = discipline->erp_action (cqr)) != NULL &&
-                                             (erp_cqr = erp_action (cqr)) != NULL ) {
+                                dasd_erp_action_fn_t erp_action;
+                                ccw_req_t *erp_cqr = NULL;
+                                
+                                if (cqr->dstat->flag & DEVSTAT_HALT_FUNCTION) {
+                                        atomic_compare_and_swap_debug(&cqr->status,
+                                                                      CQR_STATUS_ERROR,
+                                                                      CQR_STATUS_FAILED);
+                                        next = cqr;
+                                } else if (discipline -> erp_action != NULL                    &&
+                                           (erp_action = discipline->erp_action (cqr)) != NULL &&
+                                           (erp_cqr = erp_action (cqr)) != NULL                  ) {
+
+                                        if (erp_cqr != cqr){
+                                                
                                                 dasd_chanq_enq_head (qp, erp_cqr);
-                                                next = erp_cqr;		/* prefer execution of erp ccw */
-                                        } else {
-                                                atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED);
-                                                next = cqr;
                                         }
-					break;
-				}
+                                        cqr->retries--;
+                                        next = erp_cqr;	/* prefer execution of erp ccw */
+
+                                } else {
+                                        atomic_compare_and_swap_debug (&cqr->status, 
+                                                                       CQR_STATUS_ERROR, 
+                                                                       CQR_STATUS_FAILED);
+                                        next = cqr;
+                                }
+                                break;
+                        }
 			case CQR_STATUS_DONE:{
-                                        dasd_erp_postaction_fn_t erp_postaction;
-                                        next = cqr->next;
-                                        asm volatile ("STCK %0":"=m" (cqr->endclk));
-					if (cqr->refers && cqr->function) {	/* we deal with an ERP */
-						if ( discipline->erp_postaction &&
-						     ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) {
-							printk (KERN_WARNING PRINTK_HEADER
-								" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
-								" postprocessing successful error recovery action using %p\n",
-								devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, erp_postaction);
-							erp_postaction (cqr, 1);
-						} else {
-							printk (KERN_WARNING PRINTK_HEADER
-								" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
-								" No procedure to postprocess error recovery action"
-                                                                " giving up request",
-								devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
-							atomic_compare_and_swap_debug (&cqr->refers->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED);
-						}
+                                dasd_erp_postaction_fn_t erp_postaction;
+                                next = cqr->next;
+                                asm volatile ("STCK %0":"=m" (cqr->endclk));
+                                if (cqr->refers && cqr->function) {	/* we deal with an ERP */
+                                        if ( discipline->erp_postaction &&
+                                             ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) {
+                                                printk (KERN_WARNING PRINTK_HEADER
+                                                        " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                        " postprocessing successful ERA using %p\n",
+                                                        devno, irq, device->name, major_from_devindex (devindex), 
+                                                        devindex << DASD_PARTN_BITS, erp_postaction);
+                                                cqr = erp_postaction (cqr);  
+                                                next = cqr; 
+                                        } else {
+                                                printk (KERN_WARNING PRINTK_HEADER
+                                                        " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                        " No procedure to postprocess ERA - "
+                                                        " giving up request",
+                                                        devno, irq, device->name, major_from_devindex (devindex), 
+                                                        devindex << DASD_PARTN_BITS);
+                                                atomic_compare_and_swap_debug (&cqr->refers->status,
+                                                                               CQR_STATUS_ERROR, 
+                                                                               CQR_STATUS_FAILED);
+
                                                 atomic_dec (&device->queue.dirty_requests);
                                                 dasd_chanq_deq (&device->queue, cqr);
                                                 dasd_free_request(cqr); /* Only free request if nobody is waiting on it */
-					} else if ( cqr->req ) {
-						dasd_end_request (cqr->req, 1);
+                                        }
+                                } else if ( cqr->req ) {
+                                        dasd_end_request (cqr->req, 1);
 #ifdef DASD_PROFILE
-						dasd_profile_add (cqr);
+                                        dasd_profile_add (cqr);
 #endif				/* DASD_PROFILE */
-                                                dasd_chanq_deq (&device->queue, cqr);
-                                                dasd_free_request(cqr); /* Only free request if nobody is waiting on it */
-					} else {
-                                                /* during format we don't have the request structure */
-                                                /* notify sleeping task about finished postprocessing */
-                                                atomic_compare_and_swap_debug (&cqr->status, 
-                                                                               CQR_STATUS_DONE, 
-                                                                               CQR_STATUS_DONE | CQR_STATUS_FINISHED); 
-                                                dasd_chanq_deq (&device->queue, cqr);
+                                        dasd_chanq_deq (&device->queue, cqr);
+                                        dasd_free_request(cqr); /* Only free request if nobody is waiting on it */
+                                } else {
+                                        /* during format we don't have the request structure */
+                                        /* notify sleeping task about finished postprocessing */
+                                        atomic_compare_and_swap_debug (&cqr->status, 
+                                                                       CQR_STATUS_DONE, 
+                                                                       CQR_STATUS_DONE | CQR_STATUS_FINISHED); 
+                                        dasd_chanq_deq (&device->queue, cqr);
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-                                                wake_up (&device->wait_q);
+                                        wake_up (&device->wait_q);
 #else
-                                                if (device->wait_q) {
-                                                  wake_up (&device->wait_q);
-                                                }
-#endif /* LINUX_IS_24 */
+                                        if (device->wait_q) {
+                                                wake_up (&device->wait_q);
                                         }
-					break;
-				}
+#endif /* LINUX_IS_24 */
+                                }
+                                break;
+                        }
 			case CQR_STATUS_FAILED:{
-					dasd_erp_postaction_fn_t erp_postaction;
-					next = cqr->next;
-                                        asm volatile ("STCK %0":"=m" (cqr->endclk));
-					if (cqr->refers && cqr->function) {	/* we deal with an ERP */
-						if ( discipline->erp_postaction &&
-                                                     ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) {
-							printk (KERN_WARNING PRINTK_HEADER
-								" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
-								" postprocessing unsuccessful error recovery action using %p\n",
-								devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, erp_postaction);
-							erp_postaction (cqr, 0);
-						} else {
-							printk (KERN_WARNING PRINTK_HEADER
-								" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
-								" No procedure to postprocess unsuccessful error recovery action"
-                                                                " giving up request",
-								devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
-							atomic_compare_and_swap_debug (&cqr->refers->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED);
-						}
+                                dasd_erp_postaction_fn_t erp_postaction;
+                                next = cqr->next;
+                                asm volatile ("STCK %0":"=m" (cqr->endclk));
+                                if (cqr->refers && cqr->function) {	/* we deal with an ERP */
+                                        if ( discipline->erp_postaction &&
+                                             ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) {
+                                                printk (KERN_WARNING PRINTK_HEADER
+                                                        " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                        " postprocessing unsuccessful ERA using %p\n",
+                                                        devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, erp_postaction);
+                                                cqr = erp_postaction (cqr); 
+                                                next = cqr; 
+                                        } else {
+                                                printk (KERN_WARNING PRINTK_HEADER
+                                                        " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                        " No procedure to postprocess unsuccessful ERA - "
+                                                        " giving up request",
+                                                        devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
+                                                atomic_compare_and_swap_debug (&cqr->refers->status, 
+                                                                               CQR_STATUS_ERROR, 
+                                                                               CQR_STATUS_FAILED);
+                                                
                                                 atomic_dec (&device->queue.dirty_requests);
                                                 dasd_chanq_deq (&device->queue, cqr);
                                                 dasd_free_request(cqr); /* Only free request if nobody is waiting on it */
-					} else if (cqr->req) {
-						dasd_end_request (cqr->req, 0);
+                                        }
+                                } else if (cqr->req) {
+                                        dasd_end_request (cqr->req, 0);
 #ifdef DASD_PROFILE
-						dasd_profile_add (cqr);
+                                        dasd_profile_add (cqr);
 #endif				/* DASD_PROFILE */
-                                                dasd_chanq_deq (&device->queue, cqr);
-                                                dasd_free_request(cqr); /* Only free request if nobody is waiting on it */
-					} else {
-                                                /* during format we don't have the request structure */
-                                                /* notify sleeping task about finished postprocessing */
-                                                atomic_compare_and_swap_debug (&cqr->status, 
-                                                                               CQR_STATUS_FAILED, 
-                                                                               CQR_STATUS_FAILED | CQR_STATUS_FINISHED); 
-
-                                                dasd_chanq_deq (&device->queue, cqr);
+                                        dasd_chanq_deq (&device->queue, cqr);
+                                        dasd_free_request(cqr); /* Only free request if nobody is waiting on it */
+                                } else {
+                                        /* during format we don't have the request structure */
+                                        /* notify sleeping task about finished postprocessing */
+                                        atomic_compare_and_swap_debug (&cqr->status, 
+                                                                       CQR_STATUS_FAILED, 
+                                                                       CQR_STATUS_FAILED | CQR_STATUS_FINISHED); 
+                                        
+                                        dasd_chanq_deq (&device->queue, cqr);
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-                                                wake_up (&device->wait_q);
+                                        wake_up (&device->wait_q);
 #else
-                                                if (device->wait_q) {
-                                                  wake_up (&device->wait_q);
-                                                }
+                                        if (device->wait_q) {
+                                                wake_up (&device->wait_q);
+                                        }
 #endif /* LINUX_IS_24 */
-                                        } 
-					break;
-				}
+                                } 
+                                break;
+                        }
 
-			default:{
-					printk (KERN_WARNING PRINTK_HEADER
-						"Internal error in " __FILE__ " on line %d."
-                                                " inconsistent content of ccw_req_t"
-						" cqrstatus = %d"
-						" Pls send this message and your System.map to"
-						" linux390@de.ibm.com\n",
-						__LINE__, cqrstatus);
-				}
+			case CQR_STATUS_PENDING:
+                                /* just wait */
+                                printk (KERN_WARNING PRINTK_HEADER
+                                        " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                        " CQR_STATUS_PENDING - just wait...\n",
+                                        devno, irq, device->name, 
+                                        major_from_devindex (devindex), 
+                                        devindex << DASD_PARTN_BITS);
+                                break;
+                        
+			default:
+                                printk (KERN_WARNING PRINTK_HEADER
+                                        "Internal error in " __FILE__ " on line %d."
+                                        " inconsistent content of ccw_req_t"
+                                        " cqrstatus = %d"
+                                        " Pls send this message and your System.map to"
+                                        " linux390@de.ibm.com\n",
+                                        __LINE__, cqrstatus);
+                                
 			}
 			s390irq_spin_unlock_irqrestore (irq, flags);
 		} while ((cqr = next) != NULL);
@@ -1369,6 +1400,56 @@
         return;
 }
 
+/*
+ * DASD_HANDLE_STATE_CHANGE_PENDING 
+ *
+ * DESCRIPTION
+ *   Handles the state change pending interrupt.
+ *   Search for the device related request queue and check if the first 
+ *   cqr in queue in in status 'CQR_STATUE_PENDING'.
+ *   If so the status is set to 'CQR_STATUS_QUEUED' and the bh is
+ *   scheduled.
+ *
+ *  PARAMETER
+ *   stat               device status of state change pending interrupt.
+ */
+void 
+dasd_handle_state_change_pending (devstat_t *stat)
+{
+        dasd_device_t *device;
+        ccw_req_t     *cqr;
+        int           devindex;
+
+	devindex = devindex_from_devno (stat->devno);
+	if (devindex < 0) {
+                return;
+	}
+
+	device = find_dasd_device (devindex);
+	if (device == NULL) {
+                return; 
+        }
+
+        /* re-activate first request in queue */
+        cqr = device->queue.head;    
+        
+        if (cqr != NULL                                     &&
+            atomic_read(&cqr->status) == CQR_STATUS_PENDING   ) {
+                dasd_device_t *device = cqr->device;
+
+                DASD_MESSAGE (KERN_INFO, device,
+                              "%s",
+                              "device request queue restarted by "
+                              "SCP interrupt\n");
+                
+                del_timer(&device->timer);
+                atomic_compare_and_swap_debug (&cqr->status, 
+                                               CQR_STATUS_PENDING, 
+                                               CQR_STATUS_QUEUED);
+                dasd_schedule_bh();
+        }
+} /* end dasd_handle_state_change_pending */
+
 void
 dasd_int_handler (int irq, void *ds, struct pt_regs *regs)
 {
@@ -1380,8 +1461,7 @@
 	dasd_device_t *device;
 	int devno = -1, devindex = -1;
         
-#undef  ERP_DEBUG
-#ifdef ERP_DEBUG 
+#ifdef ERP_DEBUG                /* #define ERP_DEBUG is done in dasd.h */
         static int counter = 0;
 #endif
 
@@ -1389,12 +1469,23 @@
 		PRINT_ERR ("handler called without devstat");
 		return;
 	}
+
 	ip = stat->intparm;
 	if (!ip) {		/* no intparm: unsolicited interrupt */
 		PRINT_INFO ("%04X caught unsolicited interrupt\n",
 			    stat->devno);
+
+                /* check for state change pending interrupt */
+                if (stat->dstat & (DEV_STAT_ATTENTION | 
+                                   DEV_STAT_DEV_END   |
+                                   DEV_STAT_UNIT_EXCEP )) {
+                        
+                        dasd_handle_state_change_pending (stat);
+                }
+
 		return;
 	}
+
 	if (ip & 0x80000001) {
 		PRINT_INFO ("%04X  caught spurious interrupt with parm %08x\n",
 			    stat->devno, ip);
@@ -1436,20 +1527,63 @@
 		return;
 	}
 	asm volatile ("STCK %0":"=m" (cqr->stopclk));
-	if ((!(stat->flag & DEVSTAT_HALT_FUNCTION) &&
-	     stat->cstat == 0x00 &&
-	     stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) ||
- 	    (device->discipline->examine_error &&
-	     (era = device->discipline->examine_error (cqr, stat)) == dasd_era_none)) {
 #ifdef ERP_DEBUG
-                if ( ++counter % 137 == 0 ) {
-                        printk ( KERN_INFO PRINTK_HEADER "Faking I/O error to recover from\n");
+                if ((++counter % 937 >= 100) &&
+                    (  counter % 937 <= 110) &&
+                    (  counter < 5000    ) &&
+                    (  counter > 2000    )   ){
+                        static int fake_count = 0;
+                        printk ( KERN_INFO PRINTK_HEADER "***********************************************\n");
+                        printk ( KERN_INFO PRINTK_HEADER "Faking I/O error to recover from; cntr=%i / %02X\n",counter,++fake_count);
+                        printk ( KERN_INFO PRINTK_HEADER "***********************************************\n");
                         era = dasd_era_recover;
                         stat->flag |= DEVSTAT_FLAG_SENSE_AVAIL;
                         stat->dstat |= 0x02;
-                        goto error_fake_done;
+// reset notification
+                        {
+                                char *sense = stat->ii.sense.data;
+                                char buffer[100];
+				memset(sense,0,32);
+                                sprintf(buffer,"CPU ALL TR IO %X INST INT CCW", devno);
+                                cpcmd(buffer,NULL,NULL);
+                                sense[0]=0x10;
+                                sense[4]=0x21;
+                                sense[7]=0x9;
+                                sense[15]=0x4;
+                                sense[16]=0xe5;
+                                sense[18]=0x43;
+                                sense[19]=0xfb;
+                                sense[20]=0x54;
+                                sense[22]=0x0f;
+                                sense[23]=0x09;
+                                sense[26]=0x40;
+                                sense[27]=0xe0;
+                        }
+// sense 32
+//                        {
+//                                char *sense = stat->ii.sense.data;
+//                                sense [25] = 0x1D;
+//                                sense [27] = 0x00;
+//                                //sense [25] = (fake_count % 256); //0x1B;
+//                               //sense [27] = 0x00;
+//                        }
+// sense 24
+//                        {
+//                                char *sense = stat->ii.sense.data;
+//                                sense [0] = (counter % 0xFF); //0x1B;
+//                                sense [1] = ((counter * 7) % 0xFF); //0x1B;
+//                                sense [2] = (fake_count % 0xFF); //0x1B;
+//                                sense [27] = 0x80;
+//                        }
                 }
 #endif
+
+	if ((!(stat->flag & DEVSTAT_HALT_FUNCTION) &&
+	     stat->cstat == 0x00 &&
+	     stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) ||
+ 	    (device->discipline->examine_error &&
+	     (era = device->discipline->examine_error (cqr, stat)) == dasd_era_none)) {
+
 		atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_DONE);
                 atomic_compare_and_swap (DASD_DEVICE_LEVEL_ANALYSIS_PENDING,
 					 DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
@@ -1462,9 +1596,6 @@
 			}
 		}
 	} else {		/* only visited in case of error ! */
-#ifdef ERP_DEBUG
-        error_fake_done:
-#endif
 		if (cqr->dstat == NULL)
 			cqr->dstat = kmalloc (sizeof (devstat_t), GFP_ATOMIC);
 		if (cqr->dstat) {
@@ -1512,7 +1643,12 @@
 ccw_req_t *
 default_erp_action (ccw_req_t * cqr)
 {
-	ccw_req_t *erp = ccw_alloc_request ((char *) &cqr->magic, 1, 0);
+	ccw_req_t *erp = dasd_alloc_request ((char *) &cqr->magic, 1, 0);
+	if ( !erp ) {
+		printk(KERN_WARNING PRINTK_HEADER 
+                       "unable to allocate ERP request\n");
+		return NULL;
+	}
         
 	erp->cpaddr->cmd_code = CCW_CMD_TIC;
         erp->cpaddr->cda = (__u32)cqr -> cpaddr;
@@ -1528,30 +1664,97 @@
         return erp;
 }
 
-int
-default_erp_postaction (ccw_req_t * cqr, int success)
+/*
+ * DEFAULT_ERP_POSTACTION
+ *
+ * DESCRIPTION
+ *   Frees all ERPs of the current ERP Chain and set the status
+ *   of the original CQR either to CQR_STATUS_DONE if ERP was successful
+ *   or to CQR_STATUS_FAILED if ERP was NOT successful.
+ *
+ * PARAMETER
+ *   erp                current erp_head
+ *
+ * RETURN VALUES
+ *   cqr                pointer to the original CQR
+ */
+ccw_req_t *
+default_erp_postaction (ccw_req_t * erp)
 {
-	if (cqr->refers == NULL || cqr->function == NULL) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"ERP postaction called for non ERP cqr\n");
-		return -EINVAL;
+	ccw_req_t *cqr = NULL, *free_erp = NULL;
+	dasd_device_t *device = NULL;
+	int success;
+
+	device = (dasd_device_t *) (erp->device);
+
+	if (atomic_read(&erp->status) == CQR_STATUS_DONE)
+		success = 1;
+	else
+		success = 0;
+
+#ifdef ERP_DEBUG
+
+	/* print current erp_chain */
+        printk (KERN_WARNING PRINTK_HEADER
+                "default ERP postaction called for erp chain:\n");
+        {
+                ccw_req_t *temp_erp = NULL;
+                for (temp_erp = erp; temp_erp != NULL; temp_erp = temp_erp->refers){
+                        printk(KERN_WARNING PRINTK_HEADER 
+                               "       erp %p refers to %p with erp function %p\n",
+                               temp_erp,
+                               temp_erp->refers,
+                               temp_erp->function );
+                }
+        }
+
+#endif /* ERP_DEBUG*/
+
+	if (erp->refers == NULL || erp->function == NULL) {
+		panic (PRINTK_HEADER "Programming error in ERP! Postaction called "
+                       "for invalid ERPt\n");
+	}
+
+	/* free all ERPs - but NOT the original cqr */
+	while (erp->refers != NULL) {
+		free_erp = erp;
+		erp = erp->refers;
+		/* remove the request from the device queue */
+		dasd_chanq_deq (&device->queue,	free_erp);
+		/* free the finished erp request */
+		dasd_free_request (free_erp);
+	}
+
+	/* save ptr to original cqr */
+	cqr = erp;
+
+	/* set corresponding status to original cqr */
+	if (success) {
+		atomic_compare_and_swap_debug (&cqr->status, 
+                                               CQR_STATUS_ERROR, 
+                                               CQR_STATUS_DONE);
+	} else {
+		atomic_compare_and_swap_debug (&cqr->status,
+                                               CQR_STATUS_ERROR,
+                                               CQR_STATUS_FAILED);
 	}
-	if (cqr->function != default_erp_action) {
-		printk (KERN_WARNING PRINTK_HEADER
-                        "default ERP postaction called for non default ERP cqr\n");
-		return -EINVAL;
+
+#ifdef ERP_DEBUG
+	/* print current erp_chain */
+	printk (KERN_WARNING PRINTK_HEADER
+		"default ERP postaction finished with remaining chain:\n");
+	{
+		ccw_req_t *temp_erp = NULL;
+		for (temp_erp = cqr; temp_erp != NULL; temp_erp = temp_erp->refers) {
+			printk (KERN_WARNING PRINTK_HEADER
+				" erp %p refers to %p \n",
+				temp_erp, temp_erp->refers);
+		}
 	}
-        if ( success ) {
-		atomic_compare_and_swap_debug (&cqr->refers->status,
-					       CQR_STATUS_ERROR,
-					       CQR_STATUS_DONE);
-        } else {
-		atomic_compare_and_swap_debug (&cqr->refers->status,
-					       CQR_STATUS_ERROR,
-					       CQR_STATUS_FAILED);
-        } 
-	return 0;
-}
+#endif /* ERP_DEBUG */
+
+	return cqr;
+} /* end default_erp_postaction */
 
 /* SECTION: The helpers of the struct file_operations */
 
@@ -1641,7 +1844,7 @@
                 while ((!rc                                                               ) &&
                        ((req = device->discipline->format_device (device, &temp)) != NULL )   ) {
 
-                        if ( rc=sleep_on_req(req) ) {
+                        if ( (rc=sleep_on_req(req)) != 0 ) {
                                 printk (KERN_WARNING PRINTK_HEADER
                                         " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
                                         " Formatting failed with rc = %d\n",
@@ -1985,10 +2188,6 @@
 	major_info_t *major_info = NULL;
 	major_info = kmalloc (sizeof (major_info_t), GFP_KERNEL);
 	if (major_info) {
-                major_info_t *temp = dasd_major_info;
-                while (temp->next)
-                        temp = temp->next;
-		temp->next = major_info;
                 
 		memset (major_info, 0, sizeof (major_info_t));
 		major_info->read_ahead = 8;
@@ -1998,7 +2197,8 @@
 		major_info->gendisk.minor_shift = DASD_PARTN_BITS;
 		major_info->gendisk.max_p = 1 << DASD_PARTN_BITS;
 #if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-		major_info->gendisk.max_nr= 1 << DASD_PARTN_BITS;
+		/* HSM changed for PL020234MVE */
+		major_info->gendisk.max_nr= DASD_PER_MAJOR;
 #endif /* LINUX_IS_24 */
 		major_info->gendisk.nr_real=DASD_PER_MAJOR;
 	}
@@ -2013,6 +2213,7 @@
 #endif /* LINUX_IS_24 */
 	int rc = 0;
 	int major;
+        int need_insert=0;
 
 	if (major_info == NULL) {
 		major_info = get_new_major_info ();
@@ -2024,6 +2225,7 @@
 			printk (KERN_INFO PRINTK_HEADER
 				"Created another major number\n");
 		}
+                need_insert=1; //insert new major info into dasd_major_info later
 	}
 	major = major_info->gendisk.major;
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
@@ -2052,6 +2254,13 @@
 
 		}
 	}
+        /* Insert the new major info into dasd_major_info if needed */
+        if (need_insert) {
+            major_info_t *temp = dasd_major_info;
+            while (temp->next)
+                temp = temp->next;
+            temp->next = major_info;
+        }
         major_info->dasd_device = (dasd_device_t **) kmalloc( DASD_PER_MAJOR * sizeof(dasd_device_t*), 
                                                               GFP_ATOMIC);
         memset ( major_info->dasd_device ,0,DASD_PER_MAJOR * sizeof(dasd_device_t*));
@@ -2153,15 +2362,15 @@
                 index = devindex_from_kdev_t (MKDEV(hd->major,index<<hd->minor_shift));
         }
         third = index % 26;
-        second = (index / 26) % 27;
-	first = ((index / 26) / 27) % 27;
+        second = ((index-26) / 26) % 26;
+	first = (((index-702) / 26) / 26) % 26;
         
 	len = sprintf (str, "dasd");
-	if (first) {
-                len += sprintf (str + len, "%c", first + 'a' - 1 );
+	if (index>701) {
+                len += sprintf (str + len, "%c", first + 'a' );
 	}
-	if (second) {
-                len += sprintf (str + len, "%c", second + 'a' - 1 );
+	if (index>25) {
+                len += sprintf (str + len, "%c", second + 'a' );
 	}
         len += sprintf (str + len, "%c", third + 'a' );
 	if (partition) {
@@ -2307,6 +2516,7 @@
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
         init_waitqueue_head(&device->wait_q);
 #endif /* KERNEL_VERSION */
+        init_timer(&device->timer);
         minor = MINOR(device->kdev);
 	current_level = atomic_read (&device->level);
 	if (desired_level > current_level) {
@@ -2412,7 +2622,7 @@
                                 if (major_info->blksize_size[minor + i] < 1024 )
                                         major_info->blksize_size[minor + i] = 1024;
                                 
-				major_info->max_sectors[minor + i] = 200 << device->sizes.s2b_shift;	/* FIXME !!! */
+				major_info->max_sectors[minor + i] = device->discipline->max_blocks << device->sizes.s2b_shift;	
 			}
 			atomic_compare_and_swap_debug (&device->level,
                                                        DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
@@ -2509,6 +2719,14 @@
         int len;
 } tempinfo_t;
 
+void dasd_fill_inode (struct inode* inode, int fill) {
+    if (fill)
+        MOD_INC_USE_COUNT;
+    else
+        MOD_DEC_USE_COUNT;
+}
+
+
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
 static struct proc_dir_entry *dasd_proc_root_entry = NULL;
 #else
@@ -2521,7 +2739,8 @@
 	nlink:1,
 	uid:0,
 	gid:0,
-	size:0
+	size:0,
+        fill_inode:dasd_fill_inode
 };
 #endif /* KERNEL_VERSION */
 static struct proc_dir_entry* dasd_devices_entry;
@@ -2604,6 +2823,9 @@
 		temp = temp->next;
 	}
         info->len=len;
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif
         return rc;
 }
 
@@ -2661,6 +2883,9 @@
                 if ( p_info->data ) vfree(p_info->data);
                 vfree(p_info);
         }
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif
         return rc;
 }
 
@@ -2858,9 +3083,7 @@
                         dasd_unregister_major(major_info);
                 }
         }
- emergency_failed:
         dasd_cleanup_emergency_req();
- failed:
         printk (KERN_INFO PRINTK_HEADER "initialization not performed due to errors\n");
  out:
         printk (KERN_INFO PRINTK_HEADER "initialization finished\n");
@@ -2924,9 +3147,7 @@
 int
 init_module ( void )
 {
-        int rc=0;
         return dasd_init(); 
-        return rc;
 }
 
 void 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/block/dasd.h linux.19p18/drivers/s390/block/dasd.h
--- linux.vanilla/drivers/s390/block/dasd.h	Mon Dec 11 22:12:51 2000
+++ linux.19p18/drivers/s390/block/dasd.h	Tue Feb 20 13:26:26 2001
@@ -1,9 +1,13 @@
 ccw_req_t *default_erp_action (ccw_req_t *);
-int default_erp_postaction ( ccw_req_t *, int);
 int dasd_start_IO (ccw_req_t * cqr);
 void dasd_int_handler (int , void *, struct pt_regs *);
 ccw_req_t * dasd_alloc_request (char *, int , int ) ;
 void dasd_free_request(ccw_req_t *);
 int (*genhd_dasd_name)(char*,int,int,struct gendisk*);
 int dasd_oper_handler ( int irq, devreg_t *devreg );
+
+dasd_era_t dasd_3370_erp_examine (ccw_req_t * cqr, devstat_t * stat);
+dasd_era_t dasd_3990_erp_examine (ccw_req_t * cqr, devstat_t * stat);
+dasd_era_t dasd_9336_erp_examine (ccw_req_t * cqr, devstat_t * stat);
+dasd_era_t dasd_9343_erp_examine (ccw_req_t * cqr, devstat_t * stat);
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/block/dasd_3370_erp.c linux.19p18/drivers/s390/block/dasd_3370_erp.c
--- linux.vanilla/drivers/s390/block/dasd_3370_erp.c	Sat Sep  9 18:42:40 2000
+++ linux.19p18/drivers/s390/block/dasd_3370_erp.c	Thu Dec 21 22:50:30 2000
@@ -5,6 +5,7 @@
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
  */
 
+#include <linux/blkdev.h>
 #include <asm/ccwcache.h>
 #include <asm/dasd.h>
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/block/dasd_3990_erp.c linux.19p18/drivers/s390/block/dasd_3990_erp.c
--- linux.vanilla/drivers/s390/block/dasd_3990_erp.c	Mon Dec 11 22:12:51 2000
+++ linux.19p18/drivers/s390/block/dasd_3990_erp.c	Tue Feb 20 13:26:26 2001
@@ -1,46 +1,31 @@
 /* 
  * File...........: linux/drivers/s390/block/dasd_3990_erp.c
- * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- *                  Horst  Hummel    <Horst.Hummel@de.ibm.com> 
+ * Author(s)......: Horst  Hummel    <Horst.Hummel@de.ibm.com> 
+ *                  Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
  */
 
+#include <linux/blkdev.h>
 #include <asm/ccwcache.h>
+#include <asm/idals.h>
 #include <asm/dasd.h>
+#include <asm/s390io.h>
+#include <linux/timer.h>
+#include "dasd_eckd.h"
+#include "dasd_3990_erp.h"
 
 #ifdef PRINTK_HEADER
 #undef PRINTK_HEADER
-#define PRINTK_HEADER "dasd_erp(3990)"
-#endif /* PRINTK_HEADER */
+#endif				/* PRINTK_HEADER */
+#define PRINTK_HEADER "dasd_erp(3990): "
+
 
 /*
- * DASD_3990_ERP_EXAMINE_32 
- *
- * DESCRIPTION
- *   Checks only for fatal/no/recoverable error. 
- *   A detailed examination of the sense data is done later outside
- *   the interrupt handler.
- *
- * RETURN VALUES
- *   dasd_era_none      no error 
- *   dasd_era_fatal     for all fatal (unrecoverable errors)
- *   dasd_era_recover   for recoverable others.
+ ***************************************************************************** 
+ * SECTION ERP EXAMINATION
+ ***************************************************************************** 
  */
-dasd_era_t
-dasd_3990_erp_examine_32 (char *sense)
-{
-
-	switch (sense[25]) {
-	case 0x00:
-		return dasd_era_none;
-	case 0x01:
-		return dasd_era_fatal;
-	default:
-		return dasd_era_recover;
-	}
-
-}				/* end dasd_3990_erp_examine_32 */
 
 /*
  * DASD_3990_ERP_EXAMINE_24 
@@ -52,7 +37,7 @@
  *
  *   Each bit configuration leading to an action code 2 (Exit with
  *   programming error or unusual condition indication)
- *   and 10 (disabled interface) are handled as fatal error´s.
+ *   are handled as fatal error´s.
  * 
  *   All other configurations are handled as recoverable errors.
  *
@@ -64,31 +49,58 @@
 dasd_3990_erp_examine_24 (char *sense)
 {
 
-	/* check for 'Command Recejct' whithout environmental data present  */
-	if (sense[0] & 0x80) {
-                if (sense[2] &0x10){
-                        return dasd_era_recover;
-                } else {
-                        return dasd_era_fatal;
-                }
-        }
-	
-        /* check for 'Invalid Track Format' whithout environmental data present  */
-	if (sense[1] & 0x40) {
-                if (sense[2] &0x10){
-                        return dasd_era_recover;
-                } else {
-                        return dasd_era_fatal;
-                }
+	/* check for 'Command Recejct' which is always a fatal error  */
+	if (sense[0] & SNS0_CMD_REJECT) {
+		if (sense[2] & SNS2_ENV_DATA_PRESENT) {
+			return dasd_era_recover;
+		} else {
+			return dasd_era_fatal;
+		}
+	}
+	/* check for 'Invalid Track Format'                           */
+	if (sense[1] & SNS1_INV_TRACK_FORMAT) {
+		if (sense[2] & SNS2_ENV_DATA_PRESENT) {
+			return dasd_era_recover;
+		} else {
+			return dasd_era_fatal;
+		}
 	}
 	/* check for 'No Record Found'                                */
-	if (sense[1] & 0x08) {
+	if (sense[1] & SNS1_NO_REC_FOUND) {
 		return dasd_era_fatal;
 	}
 	/* return recoverable for all others                          */
 	return dasd_era_recover;
 
-}				/* END dasd_3990_erp_examine_24 */
+} /* END dasd_3990_erp_examine_24 */
+
+/*
+ * DASD_3990_ERP_EXAMINE_32 
+ *
+ * DESCRIPTION
+ *   Checks only for fatal/no/recoverable error. 
+ *   A detailed examination of the sense data is done later outside
+ *   the interrupt handler.
+ *
+ * RETURN VALUES
+ *   dasd_era_none      no error 
+ *   dasd_era_fatal     for all fatal (unrecoverable errors)
+ *   dasd_era_recover   for recoverable others.
+ */
+dasd_era_t
+dasd_3990_erp_examine_32 (char *sense)
+{
+
+	switch (sense[25]) {
+	case 0x00:
+		return dasd_era_none;
+	case 0x01:
+		return dasd_era_fatal;
+	default:
+		return dasd_era_recover;
+	}
+
+}				/* end dasd_3990_erp_examine_32 */
 
 /*
  * DASD_3990_ERP_EXAMINE 
@@ -118,19 +130,1134 @@
 		return dasd_era_none;
 
 	/* distinguish between 24 and 32 byte sense data */
-	if (sense[27] & 0x80) {
+	if (sense[27] & DASD_SENSE_BIT_0) {
+
+		/* examine the 24 byte sense data */
+		return dasd_3990_erp_examine_24 (sense);
+
+	} else {
 
 		/* examine the 32 byte sense data */
 		return dasd_3990_erp_examine_32 (sense);
 
+	} /* end distinguish between 24 and 32 byte sense data */
+
+} /* END dasd_3990_erp_examine */
+
+/*
+ ***************************************************************************** 
+ * SECTION ERP HANDLING
+ ***************************************************************************** 
+ */
+/*
+ ***************************************************************************** 
+ * 24 and 32 byte sense ERP functions
+ ***************************************************************************** 
+ */
+
+/*
+ * DASD_3990_ERP_BLOCK_QUEUE 
+ *
+ * DESCRIPTION
+ *   Block the given device request queue to prevent from further
+ *   processing until the started timer has expired or an related
+ *   interrupt was received.
+ *
+ *  PARAMETER
+ *   erp                request to be blocked
+ *   expires            time to wait until restart (in seconds) 
+ *
+ * RETURN VALUES
+ *   void               
+ */
+void
+dasd_3990_erp_block_queue (ccw_req_t     *erp,
+                           unsigned long expires)
+{
+
+	dasd_device_t *device = erp->device;
+
+        DASD_MESSAGE (KERN_INFO, device,
+                      "blocking request queue for %is",
+                      (int) expires);
+
+        atomic_compare_and_swap_debug (&erp->status,
+                                       CQR_STATUS_ERROR,
+                                       CQR_STATUS_PENDING);
+
+        /* restart queue after some time */
+        device->timer.function = dasd_3990_erp_restart_queue; 
+        device->timer.data = (unsigned long) erp;
+        device->timer.expires = jiffies + (expires * HZ);
+        add_timer(&device->timer); 
+
+        /* restart queue using int handler routing - just for testing - TDB */
+        /* insert "void dasd_handle_state_change_pending (devstat_t *stat);" to dasd.h */
+//        device->timer.function = dasd_handle_state_change_pending;
+//        device->timer.data = (unsigned long) &device->dev_status;
+//        device->timer.expires = jiffies + (expires * HZ);
+//        add_timer(&device->timer); 
+
+} /* end dasd_3990_erp_block_queue */ 
+
+/*
+ * DASD_3990_ERP_RESTART_QUEUE 
+ *
+ * DESCRIPTION
+ *   Restarts request currently in status PENDING.
+ *   This has to be done if either an related interrupt has received, or 
+ *   a timer has expired.
+ *   
+ *
+ *  PARAMETER
+ *   erp                pointer to the PENDING ERP
+ *
+ * RETURN VALUES
+ *   void               
+ *
+ */
+void
+dasd_3990_erp_restart_queue (unsigned long erp)
+{
+        ccw_req_t     *cqr    = (void *) erp;
+	dasd_device_t *device = cqr->device;
+	unsigned long flags;
+        
+        /* TBD delete */
+        DASD_MESSAGE (KERN_INFO, device,
+                      "%s irq %d erp %p",
+                      "dasd_3990_erp_restart_queue entered",device->devinfo.irq, erp);
+        /* get the needed locks to modify the request queue */
+	s390irq_spin_lock_irqsave (device->devinfo.irq, 
+                                   flags);
+
+        /* 'restart' the device queue */
+        if (atomic_read(&cqr->status) == CQR_STATUS_PENDING){
+                
+                DASD_MESSAGE (KERN_INFO, device,
+                              "%s",
+                              "request queue restarted by MIH");
+
+                atomic_compare_and_swap_debug (&cqr->status,
+                                               CQR_STATUS_PENDING,
+                                               CQR_STATUS_QUEUED);
+}
+
+        /* release the lock */
+        s390irq_spin_unlock_irqrestore (device->devinfo.irq, 
+                                        flags);
+        dasd_schedule_bh();
+
+} /* end dasd_3990_erp_restart_queue */
+
+/*
+ * DASD_3990_ERP_ALTERNATE_PATH 
+ *
+ * DESCRIPTION
+ *   Repeat the operation on a different channel path.
+ *   If all alternate paths have been tried, the request is posted with a
+ *   permanent error.
+ *
+ *  PARAMETER
+ *   erp                pointer to the current ERP
+ *
+ * RETURN VALUES
+ *   erp                modified pointer to the ERP
+ *
+ */
+void
+dasd_3990_erp_alternate_path (ccw_req_t *erp)
+{
+
+	dasd_device_t *device = erp->device;
+        int irq = device->devinfo.irq;
+
+	/* dissable current channel path - this causes the use of an other 
+	   channel path if there is one.. */
+
+	DASD_MESSAGE (KERN_WARNING, device,
+                      "disable lpu %x",
+                      erp->dstat->lpum);
+
+        /* try alternate valid path */
+        erp->lpm     &= ~(erp->dstat->lpum);
+        erp->options |= DOIO_VALID_LPM;		/* use LPM for DO_IO */
+
+	if ((erp->lpm & ioinfo[irq]->opm) != 0x00) {
+
+		DASD_MESSAGE (KERN_WARNING, device,
+			"try alternate lpm %x",
+			erp->lpm);
+
+		/* reset status to queued to handle the request again... */
+		atomic_compare_and_swap_debug (&erp->status,
+                                               CQR_STATUS_ERROR,
+                                               CQR_STATUS_QUEUED);
+
+                erp->retries = 1;
+                
 	} else {
+         
+                DASD_MESSAGE (KERN_WARNING, device,
+                              "%s",      
+                              "No alternate channel path left -> "
+                              "permanent error");
+                
+                /* post request with permanent error */
+                atomic_compare_and_swap_debug (&erp->status,
+                                               CQR_STATUS_ERROR,
+                                               CQR_STATUS_FAILED);
 
-		/* examine the 24 byte sense data */
-		return dasd_3990_erp_examine_24 (sense);
+        }
+        
+} /* end dasd_3990_erp_alternate_path */
+
+/*
+ * DASD_3990_ERP_ACTION_1 
+ *
+ * DESCRIPTION
+ *   Setup ERP to do the ERP action 1 (see Reference manual).
+ *   Repeat the operation on a different channel path.
+ *   If all alternate paths have been tried, the request is posted with a
+ *   permanent error.
+ *   Note: duplex handling is not implemented (yet).
+ *
+ *  PARAMETER
+ *   erp                pointer to the current ERP
+ *
+ * RETURN VALUES
+ *   erp                pointer to the ERP
+ *
+ */
+ccw_req_t *
+dasd_3990_erp_action_1 (ccw_req_t * erp)
+{
+        
+        erp->function = dasd_3990_erp_action_1;
+        
+ //       cpcmd ("TRACE IO 153 INST INT CCW", NULL, 0);  
+
+        dasd_3990_erp_alternate_path (erp);
+
+	return erp;
+
+} /* end dasd_3990_erp_action_1 */
+
+/*
+ * DASD_3990_ERP_ACTION_4 
+ *
+ * DESCRIPTION
+ *   Setup ERP to do the ERP action 4 (see Reference manual).
+ *   Set the current request to PENDING to block the CQR queue for that device
+ *   until the state change interrupt appears.
+ *   Use a timer (20 seconds) to retry the cqr if the interrupt is still missing.
+ *
+ *  PARAMETER
+ *   sense              sense data of the actual error
+ *   erp                pointer to the current ERP
+ *
+ * RETURN VALUES
+ *   erp                pointer to the ERP
+ *
+ */
+ccw_req_t *
+dasd_3990_erp_action_4 (ccw_req_t *erp,
+			char      *sense)
+{
+	dasd_device_t *device = erp->device;
+
+        /* first time set initial retry counter and erp_function    */
+        /* and retry once without waiting for state change pending  */
+        /* interrupt (this enables easier enqueing of the cqr)      */
+        if (erp->function != dasd_3990_erp_action_4) {
+                erp->retries  = 255; /* TBD 255 */
+                erp->function = dasd_3990_erp_action_4;
+
+        } else {
+
+                if (sense[25] & 0x1D) {	/* state change pending */
+                        
+                        DASD_MESSAGE (KERN_WARNING, device,
+                                      "%s",
+                                      "waiting for state change pending "
+                                      "int");
+                        
+                        dasd_3990_erp_block_queue (erp,
+                                                   60);    /* TBD change to 30 */
+                        
+                } else {
+                        /* no state change pending - retry */
+                        printk (KERN_WARNING PRINTK_HEADER
+                                "no state change pending - retry\n");
+                        
+                        atomic_compare_and_swap_debug (&erp->status,
+                                                       CQR_STATUS_ERROR,
+                                                       CQR_STATUS_QUEUED);
+                }
+        }
+
+	return erp;
+
+} /* end dasd_3990_erp_action_4 */
+
+/*
+ ***************************************************************************** 
+ * 24 byte sense ERP functions (only)
+ ***************************************************************************** 
+ */
+
+/*
+ * DASD_3990_ERP_EQUIP_CHECK
+ *
+ * DESCRIPTION
+ *   Handles 24 byte 'Equipment Check' error.
+ *
+ * PARAMETER
+ *   erp                current erp_head
+ * RETURN VALUES
+ *   erp                new erp_head - pointer to new ERP
+ */
+ccw_req_t *
+dasd_3990_erp_equip_check (ccw_req_t * erp,
+			   char *sense)
+{
+	dasd_device_t *device = erp->device;
+
+	erp->function = dasd_3990_erp_equip_check;
+
+	if (sense[2] & SNS2_ENV_DATA_PRESENT) {
+
+		DASD_MESSAGE (KERN_WARNING, device,
+                              "%s",
+                              "Equipment Check - environmental data present");
+
+		erp = dasd_3990_erp_action_4 (erp,
+					      sense);
+	}
+
+	return erp;
+
+} /* end dasd_3990_erp_equip_check */
+
+/*
+ * DASD_3990_ERP_DATA_CHECK
+ *
+ * DESCRIPTION
+ *   Handles 24 byte 'Data Check' error.
+ *
+ * PARAMETER
+ *   erp                current erp_head
+ * RETURN VALUES
+ *   erp                new erp_head - pointer to new ERP
+ */
+ccw_req_t *
+dasd_3990_erp_data_check (ccw_req_t * erp,
+			  char *sense)
+{
+	dasd_device_t *device = erp->device;
+
+	erp->function = dasd_3990_erp_data_check;
+
+	if (sense[2] & SNS2_ENV_DATA_PRESENT) {
+                
+		DASD_MESSAGE (KERN_WARNING, device,
+                              "%s",
+                              "Uncorrectable data check recovered secondary "
+                              "addr of duplex pair");
+
+		erp = dasd_3990_erp_action_4 (erp,
+					      sense);
+	}
+
+	return erp;
+
+} /* end dasd_3990_erp_data_check */
+
+
+/*
+ * DASD_3990_ERP_INV_FORMAT
+ *
+ * DESCRIPTION
+ *   Handles 24 byte 'Invalid Track Format' error.
+ *
+ * PARAMETER
+ *   erp                current erp_head
+ * RETURN VALUES
+ *   erp                new erp_head - pointer to new ERP
+ */
+ccw_req_t *
+dasd_3990_erp_inv_format (ccw_req_t * erp,
+			  char *sense)
+{
+	dasd_device_t *device = erp->device;
+
+	erp->function = dasd_3990_erp_inv_format;
+
+	if (sense[2] & SNS2_ENV_DATA_PRESENT) {
+
+		DASD_MESSAGE (KERN_WARNING, device,
+                              "%s",
+                              "Track format error when destaging or "
+                              "staging data");
+
+		erp = dasd_3990_erp_action_4 (erp,
+					      sense);
+	}
+
+	return erp;
+
+} /* end dasd_3990_erp_inv_format */
+
+/*
+ * DASD_3990_ERP_ENV_DATA
+ *
+ * DESCRIPTION
+ *   Handles 24 byte 'Environmental-Data Present' error.
+ *
+ * PARAMETER
+ *   erp                current erp_head
+ * RETURN VALUES
+ *   erp                new erp_head - pointer to new ERP
+ */
+ccw_req_t *
+dasd_3990_erp_env_data (ccw_req_t * erp,
+			char *sense)
+{
+	dasd_device_t *device = erp->device;
+
+	erp->function = dasd_3990_erp_env_data;
+
+        DASD_MESSAGE (KERN_WARNING, device,
+                      "%s",
+                      "Environmental data present");
+
+	erp = dasd_3990_erp_action_4 (erp,
+				      sense);
+
+	return erp;
+
+}				/* end dasd_3990_erp_env_data */
+
+/*
+ * DASD_3990_ERP_INSPECT_24 
+ *
+ * DESCRIPTION
+ *   Does a detailed inspection of the 24 byte sense data
+ *   and sets up a related error recovery action.  
+ *
+ * PARAMETER
+ *   sense              sense data of the actual error
+ *   erp                pointer to the currently created default ERP
+ *
+ * RETURN VALUES
+ *   erp                pointer to the (addtitional) ERP
+ */
+ccw_req_t *
+dasd_3990_erp_inspect_24 ( ccw_req_t * erp,
+                           char *sense)
+{
+	ccw_req_t *erp_filled = NULL;
+
+	/* Check sense for ....    */
+	/* 'Equipment Check'       */
+	if ((erp_filled == NULL) &&
+	    (sense[0] & SNS0_EQUIPMENT_CHECK)) {
+		erp_filled = dasd_3990_erp_equip_check (erp,
+							sense);
+	}
+	/* 'Data Check'            */
+	if ((erp_filled == NULL) &&
+	    (sense[0] & SNS0_DATA_CHECK)) {
+		erp_filled = dasd_3990_erp_data_check (erp,
+						       sense);
+	}
+	/* 'Invalid Track Format'  */
+	if ((erp_filled == NULL) &&
+	    (sense[1] & SNS1_INV_TRACK_FORMAT)) {
+		erp_filled = dasd_3990_erp_inv_format (erp,
+						       sense);
+	}
+	/* 'Environmental Data'    */
+	if ((erp_filled == NULL) &&
+	    (sense[2] & SNS2_ENV_DATA_PRESENT)) {
+		erp_filled = dasd_3990_erp_env_data (erp,
+						     sense);
+	}
+
+	/* other (unknown/not jet implemented) error - do default ERP */
+	if (erp_filled == NULL) {
+
+                printk (KERN_WARNING PRINTK_HEADER
+                        "default ERP taken\n");
+
+		erp_filled = erp;	
+	}
+
+	return erp_filled;
+
+} /* END dasd_3990_erp_inspect_24 */
+
+/*
+ ***************************************************************************** 
+ * 32 byte sense ERP functions (only)
+ ***************************************************************************** 
+ */
+
+/*
+ * DASD_3990_ERP_ACTION_1B_32
+ *
+ * DESCRIPTION
+ *   Handles 32 byte 'Action 1B' of Single Program Action Codes.
+ *   A write operation could not be finished because of an unexpected 
+ *   condition.
+ *   The already created 'default erp' is used to get the link to 
+ *   the erp chain, but it can not be used for this recovery 
+ *   action because it contains no DE/LO data space.
+ *
+ * PARAMETER
+ *   default_erp        already created default erp.
+ *   sense              current sense data 
+ * RETURN VALUES
+ *   erp                new erp or default_erp in case of error
+ */
+ccw_req_t *
+dasd_3990_erp_action_1B_32 (ccw_req_t *default_erp,
+                            char      *sense)
+{
+	dasd_device_t  *device     = default_erp->device;
+        ccw_req_t      *cqr;
+	ccw_req_t      *erp;
+        __u32          cpa;
+	DE_eckd_data_t *DE_data;
+	char           *LO_data;   /* LO_eckd_data_t */
+        ccw1_t         *ccw;
+
+	DASD_MESSAGE (KERN_WARNING, device,
+                      "%s",
+                      "Write not finsihed because of unexpected condition");
+        
+        /* determine the original cqr */
+        cqr = default_erp; 
+        while (cqr->refers != NULL){
+                cqr = cqr->refers;
+        }
+         
+        /* determine the address of the CCW to be restarted */
+        cpa = default_erp->refers->dstat->cpa;
+                
+        if (cpa == 0) {
+                cpa = (__u32) cqr->cpaddr;
+        }
+        
+        if (cpa == 0) {
+                
+                DASD_MESSAGE (KERN_WARNING, device,
+                              "%s",
+                              "Unable to determine address of the CCW "
+                              "to be restarted");
+                
+                atomic_compare_and_swap_debug (&default_erp->status,
+                                               CQR_STATUS_FILLED,
+                                               CQR_STATUS_FAILED);
+                
+                return default_erp;
+        }
+        
+	/* Build new ERP request including DE/LO */
+	erp = dasd_alloc_request ((char *) &cqr->magic,
+                                  2 + 1,                    /* DE/LO + TIC */
+                                  sizeof (DE_eckd_data_t) +
+                                  sizeof (LO_eckd_data_t));
+	if ( !erp ) {
+                DASD_MESSAGE (KERN_WARNING, device,
+                              "%s",
+                              "Unable to allocate ERP");
+                
+                atomic_compare_and_swap_debug (&default_erp->status,
+                                               CQR_STATUS_FILLED,
+                                               CQR_STATUS_FAILED);
+                
+                return default_erp;
+	}
+        
+        /* use original DE */
+	DE_data = erp->data;
+        memcpy (DE_data, 
+                cqr->data, 
+                sizeof (DE_eckd_data_t));
+        
+        /* create LO */
+	LO_data = erp->data + sizeof (DE_eckd_data_t);
+        
+        if ((sense[3]  == 0x01) &&
+            (LO_data[1] & 0x01)   ){
+                DASD_MESSAGE (KERN_WARNING, device,
+                              "%s",
+                              "BUG - this should not happen");
+                //BUG();    /* check for read count suffixing n.a. */
+        }
+
+        LO_data[0] = sense[7];  /* operation */
+        LO_data[1] = sense[8];  /* auxiliary */
+        LO_data[2] = sense[9];  
+        LO_data[3] = sense[3];  /* count */ 
+        LO_data[4] = sense[29]; /* seek_addr.cyl */
+        LO_data[5] = sense[30]; /* seek_addr.cyl 2nd byte */
+        LO_data[7] = sense[31]; /* seek_addr.head 2nd byte */  
+
+        memcpy (&(LO_data[8]), &(sense[11]), 8);   
+
+        /* create DE ccw */    
+        ccw = erp->cpaddr;
+	memset (ccw, 0, sizeof (ccw1_t));
+	ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;
+	ccw->flags = CCW_FLAG_CC;
+	ccw->count = 16;
+	ccw->cda = (__u32) __pa (DE_data);
+
+        /* create LO ccw */    
+        ccw++;
+	memset (ccw, 0, sizeof (ccw1_t));
+	ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD;
+	ccw->flags = CCW_FLAG_CC;
+	ccw->count = 16;
+	ccw->cda = (__u32) __pa (LO_data);
+        
+        /* TIC to the failed ccw */
+        ccw++;
+	ccw->cmd_code = CCW_CMD_TIC;
+	ccw->cda = cpa;
+
+        /* fill erp related fields */
+        erp->function = dasd_3990_erp_action_1B_32;
+	erp->refers   = default_erp->refers;
+	erp->device   = device;
+	erp->magic    = default_erp->magic;
+	erp->lpm      = 0xFF;
+	erp->expires  = 0;
+	erp->retries  = 2;
+
+	atomic_set(&erp->status, 
+                   CQR_STATUS_FILLED);
+        
+        /* remove the default erp */
+        dasd_free_request (default_erp);
+        
+	return erp;
+        
+} /* end dasd_3990_erp_action_1B_32 */
+
+
+/*
+ * DASD_3990_ERP_INSPECT_32 
+ *
+ * DESCRIPTION
+ *   Does a detailed inspection of the 32 byte sense data
+ *   and sets up a related error recovery action.  
+ *
+ * PARAMETER
+ *   sense              sense data of the actual error
+ *   erp                pointer to the currently created default ERP
+ *
+ * RETURN VALUES
+ *   erp_filled         pointer to the ERP
+ *
+ */
+ccw_req_t *
+dasd_3990_erp_inspect_32 ( ccw_req_t *erp,
+                           char      *sense )
+{
+	dasd_device_t *device = erp->device;
+
+	erp->function = dasd_3990_erp_inspect_32;
+
+	if (sense[25] & DASD_SENSE_BIT_0) {
+
+		/* compound program action codes (byte25 bit 0 == '1') */
+                printk (KERN_WARNING PRINTK_HEADER
+                        "default ERP taken\n");
+
+	} else {
+
+		/* single program action codes (byte25 bit 0 == '0') */
+		switch (sense[25]) {
+
+		case 0x1B:	/* unexpected condition during write */
+
+                        erp = dasd_3990_erp_action_1B_32 (erp,
+                                                          sense);
+#ifdef ERP_DEBUG
+                        /* TBD */
+//                        cpcmd ("STOP", NULL, 0);
+#endif
+                        break;
+
+		case 0x1D:	/* state-change pending */
+                        DASD_MESSAGE (KERN_WARNING, device, 
+                                      "%s",
+                                      "A State change pending condition exists "
+                                      "for the subsystem or device");
+
+                        erp = dasd_3990_erp_action_4 (erp,
+                                                      sense);
+//                        cpcmd ("STOP", NULL, 0);
+			break;
+
+		default:	/* all others errors */
+			printk (KERN_WARNING PRINTK_HEADER
+			 "default ERP taken\n");
+		}
+	}
+
+	return erp;
+
+} /* end dasd_3990_erp_inspect_32 */
+
+/*
+ ***************************************************************************** 
+ * main ERP control fuctions (24 and 32 byte sense)
+ ***************************************************************************** 
+ */
+
+/*
+ * DASD_3990_ERP_INSPECT
+ *
+ * DESCRIPTION
+ *   Does a detailed inspection for sense data by calling either
+ *   the 24-byte or the 32-byte inspection routine.
+ *
+ * PARAMETER
+ *   erp                pointer to the currently created default ERP
+ * RETURN VALUES
+ *   erp_new            contens was possibly modified 
+ */
+ccw_req_t *
+dasd_3990_erp_inspect (ccw_req_t * erp)
+{
+	ccw_req_t *erp_new = NULL;
+	/* sense data are located in the refers record of the */
+	/* already set up new ERP !                           */
+	char *sense = erp->refers->dstat->ii.sense.data;
+
+	/* distinguish between 24 and 32 byte sense data */
+	if (sense[27] & DASD_SENSE_BIT_0) {
+
+		/* inspect the 24 byte sense data */
+		erp_new = dasd_3990_erp_inspect_24 (erp,
+                                                    sense);
+
+	} else {
+
+		/* inspect the 32 byte sense data */
+		erp_new = dasd_3990_erp_inspect_32 (erp,
+                                                    sense);
+
+	} /* end distinguish between 24 and 32 byte sense data */
+
+	return erp_new;
+
+} /* END dasd_3990_erp_inspect */
+
+/*
+ * DASD_3990_ERP_ADD_ERP
+ * 
+ * DESCRIPTION
+ *   This funtion adds an additional request block (ERP) to the head of
+ *   the given cqr (or erp).
+ *   This erp is initialized as an default erp (retry TIC)
+ *
+ * PARAMETER
+ *   cqr                head of the current ERP-chain (or single cqr if 
+ *                      first error)
+ * RETURN VALUES
+ *   erp                pointer to new ERP-chain head
+ */
+ccw_req_t *
+dasd_3990_erp_add_erp (ccw_req_t * cqr)
+{
+	/* allocate additional request block */
+	ccw_req_t *erp = dasd_alloc_request ((char *) &cqr->magic, 1, 0);
+	if ( !erp ) {
+		printk( KERN_WARNING PRINTK_HEADER
+			"unable to allocate ERP request\n" );
+                return NULL;
+	}
+
+	/* initialize request with default TIC to current ERP/CQR */
+	erp->cpaddr->cmd_code = CCW_CMD_TIC;
+	erp->cpaddr->cda      = ((__u32) cqr->cpaddr);
+	erp->function = dasd_3990_erp_add_erp;
+	erp->refers   = cqr;
+	erp->device   = cqr->device;
+	erp->magic    = cqr->magic;
+	erp->lpm      = 0xFF;
+	erp->expires  = 0;
+	erp->retries  = 255;
+
+	atomic_set(&erp->status, 
+                   CQR_STATUS_FILLED);
+
+	return erp;
+}
+
+/*
+ * DASD_3990_ERP_ADDITIONAL_ERP 
+ * 
+ * DESCRIPTION
+ *   An additional ERP is needed to handle the current error.
+ *   Add ERP to the head of the ERP-chain containing the ERP processing
+ *   determined based on the sense data.
+ *
+ * PARAMETER
+ *   cqr                head of the current ERP-chain (or single cqr if 
+ *                      first error)
+ *
+ * RETURN VALUES
+ *   erp                pointer to new ERP-chain head
+ */
+ccw_req_t *
+dasd_3990_erp_additional_erp (ccw_req_t * cqr)
+{
+
+	ccw_req_t *erp = NULL;
+
+	/* add erp and initialize with default TIC */
+	erp = dasd_3990_erp_add_erp (cqr);
+
+	/* inspect sense, determine specific ERP if possible */
+	erp = dasd_3990_erp_inspect (erp);
+
+	return erp;
+
+}				/* end dasd_3990_erp_additional_erp */
+
+/*
+ * DASD_3990_ERP_ERROR_MATCH
+ *
+ * DESCRIPTION
+ *   check if the the device status of the given cqr is the same.
+ *   This means that the failed CCW and the relevant sense data
+ *   must match.
+ *   I don't distinguish between 24 and 32 byte sense becaus in case of
+ *   24 byte sense byte 25 and 27 is set as well.
+ *
+ * PARAMETER
+ *   cqr1               first cqr, which will be compared with the 
+ *   cqr2               second cqr.
+ *
+ * RETURN VALUES
+ *   match              'boolean' for match found
+ *                      returns 1 if match found, otherwise 0.
+ */
+int
+dasd_3990_erp_error_match (ccw_req_t * cqr1,
+			   ccw_req_t * cqr2)
+{
+	/* check failed CCW */
+	if (cqr1->dstat->cpa !=
+	    cqr2->dstat->cpa) {
+		return 0;	/* CCW doesn't match */
+
+	}
+	/* check sense data; byte 0-2,25,27 */
+	if (!((strncmp (cqr1->dstat->ii.sense.data,
+			cqr2->dstat->ii.sense.data,
+			3) == 0) &&
+	      (cqr1->dstat->ii.sense.data[27] ==
+	       cqr2->dstat->ii.sense.data[27]   ) &&
+	      (cqr1->dstat->ii.sense.data[25] ==
+	       cqr2->dstat->ii.sense.data[25]   )   )) {
+
+		return 0;	/* sense doesn't match */
+	}
+	return 1;		/* match */
+
+}				/* end dasd_3990_erp_error_match */
+
+/*
+ * DASD_3990_ERP_IN_ERP
+ *
+ * DESCRIPTION
+ *   check if the current error already happened before.
+ *   quick exit if current cqr is not an ERP (cqr->refers=NULL)
+ *
+ * PARAMETER
+ *   cqr                failed cqr (either original cqr or already an erp)
+ *
+ * RETURN VALUES
+ *   erp                erp-pointer to the already defined error recovery procedure OR
+ *                      NULL if a 'new' error occured.
+ */
+ccw_req_t *
+dasd_3990_erp_in_erp (ccw_req_t * cqr)
+{
+	ccw_req_t *erp_head = cqr,	/* save erp chain head */
+	         *erp_match = NULL;	/* save erp chain head */
+	int match = 0;		/* 'boolean' for matching error found */
+
+	if (cqr->refers == NULL) {	/* return if not in erp */
+		return NULL;
+	}
+	/* check the erp/cqr chain for current error */
+	do {
+		match = dasd_3990_erp_error_match (erp_head,
+						   cqr->refers);
+		erp_match = cqr;	/* save possible matching erp  */
+		cqr = cqr->refers;	/* check next erp/cqr in queue */
+	} while ((cqr->refers != NULL) &&
+		 (match == 0));
+
+	if (match) {
+                /* TBD */
+                printk(KERN_WARNING PRINTK_HEADER 
+                       "dasd_3990_erp_in_erp: return matching erp\n");
+		return erp_match;	/* retrun address of matching erp */
+	} else {
+                printk(KERN_WARNING PRINTK_HEADER 
+                       "dasd_3990_erp_in_erp: return no match\n");
+		return NULL;	/* return NULL to indicate that no match
+				   was found */
+	}
+
+}				/* END dasd_3990_erp_in_erp */
+
+/*
+ * DASD_3990_ERP_FURTHER_ERP (24 & 32 byte sense)
+ *
+ * DESCRIPTION
+ *   No retry is left for the current ERP. Check what has to be done 
+ *   with the ERP.
+ *     - do further defined ERP action or
+ *     - wait for interrupt or  
+ *     - exit with permanent error
+ *
+ * PARAMETER
+ *   erp                ERP which is in progress wiht no retry left
+ *
+ * RETURN VALUES
+ *   erp                modified/additional ERP
+ */
+ccw_req_t *
+dasd_3990_erp_further_erp (ccw_req_t * erp)
+{
+        dasd_device_t     *device = erp->device;
+        
+        /* check for 24 byte sense ERP */
+	if ((erp->function == dasd_3990_erp_action_1) ||
+            (erp->function == dasd_3990_erp_action_4)   ){
+                
+                erp = dasd_3990_erp_action_1 (erp);
+                
+	} else {
+                /* no retry left and no additional special handling necessary */
+                DASD_MESSAGE (KERN_WARNING, device,
+                              "no retries left for erp %p - "
+                              "set status to FAILED",
+                              erp);
+
+		atomic_compare_and_swap_debug (&erp->status,
+                                               CQR_STATUS_ERROR,
+                                               CQR_STATUS_FAILED);
+	}
+
+	return erp; 
+
+} /* end dasd_3990_erp_further_erp */
+
+/*
+ * DASD_3990_ERP_HANDLE_MATCH_ERP 
+ *
+ * DESCRIPTION
+ *   An error occured again and an ERP has been detected which is already
+ *   used to handle this error (e.g. retries). 
+ *   All prior ERP's are set to status DONE and the retry counter is
+ *   decremented.
+ *   If retry counter is already 0, it has to checked if further action
+ *   is needed (besides retry) or if the ERP has failed.
+ *
+ * PARAMETER
+ *   erp_head           first ERP in ERP-chain
+ *   erp_match          ERP that handles the actual error.
+ *
+ * RETURN VALUES
+ *   none                
+ */
+void
+dasd_3990_erp_handle_match_erp (ccw_req_t * erp_head,
+				ccw_req_t * erp_match)
+{
+
+	dasd_device_t *device   = erp_head->device;
+	ccw_req_t     *erp_done = erp_head;
+
+	/* loop over successful ERPs and remove them from chanq */
+	while ((erp_done != erp_match) &&
+	       (erp_done != NULL)) {
+
+#ifdef ERP_DEBUG
+		printk (KERN_WARNING PRINTK_HEADER
+			"successful ERP - dequeue and free request %p\n",
+			(void *) erp_done);
+#endif
+		atomic_compare_and_swap_debug (&erp_done->status,
+                                               CQR_STATUS_ERROR,
+                                               CQR_STATUS_DONE);
+
+		/* remove the request from the device queue */
+		dasd_chanq_deq (&device->queue,
+				erp_done);
+
+		/* free the finished erp request */
+		dasd_free_request (erp_done);
+
+		erp_done = erp_done->refers;
+	}
+
+	if (erp_done == NULL) 	/* erp_done should never be NULL! */
+		panic (PRINTK_HEADER "Programming error in ERP! The original "
+                       "request was lost\n");
+
+#ifdef ERP_DEBUG
+	/* handle matching ERP */
+        printk (KERN_WARNING PRINTK_HEADER
+                "handle matching erp %p\n",
+                (void *) erp_done);
+#endif
+        
+        if (erp_done->retries > 0) {
+                
+                /* check for special retries */
+                if (erp_done->function == dasd_3990_erp_action_4) {
+                        char *sense = erp_done->dstat->ii.sense.data;
+                        erp_done = dasd_3990_erp_action_4 (erp_done,
+                                                           sense);
+                        
+                } else {
+                        /* simple retry   */
+                        printk (KERN_WARNING PRINTK_HEADER
+                                "%i retries left for erp %p\n",
+                                erp_done->retries,
+                                (void *) erp_done);
+                        
+                        /* handle the request again... */
+                        atomic_compare_and_swap_debug (&erp_done->status,
+                                                       CQR_STATUS_ERROR,
+                                                       CQR_STATUS_QUEUED);
+                }
+        } else {
+                /* no retry left - check for further necessary action    */
+                /* if no further actions, handle rest as permanent error */
+                erp_done = dasd_3990_erp_further_erp (erp_done);
+	}
+
+        erp_head = erp_done;
+
+} /* end dasd_3990_erp_handle_match_erp */
+
+/*
+ * DASD_3990_ERP_ACTION
+ *
+ * DESCRIPTION
+ *   controll routine for 3990 erp actions.
+ *   Has to be called with the queue lock (namely the s390_irq_lock) acquired.
+ *
+ * PARAMETER
+ *   cqr                failed cqr (either original cqr or already an erp)
+ *
+ * RETURN VALUES
+ *   erp                erp-pointer to the head of the ERP action chain.
+ *                      This means:
+ *                       - either a ptr to an additional ERP cqr or
+ *                       - the original given cqr (which's status might be modified)
+ */
+ccw_req_t *
+dasd_3990_erp_action (ccw_req_t *cqr)
+{
+	ccw_req_t *erp = NULL;
+	dasd_device_t *device = cqr->device;
+
+#ifdef ERP_DEBUG 
+
+	printk (KERN_WARNING PRINTK_HEADER
+		"entering 3990 ERP for "
+		"0x%04X on sch %d = /dev/%s \n",
+		device->devinfo.devno,
+		device->devinfo.irq,
+		device->name);
+
+	/* print current erp_chain */
+        printk(KERN_WARNING PRINTK_HEADER 
+               "ERP chain at BEGINNING of ERP-ACTION\n");
+        {
+                ccw_req_t *temp_erp = NULL;
+                for (temp_erp = cqr; temp_erp != NULL; temp_erp = temp_erp->refers){
+                        printk(KERN_WARNING PRINTK_HEADER 
+                               "      erp %p refers to %p \n",
+                               temp_erp,
+                               temp_erp->refers);
+                }
+        } 
+#endif
+
+	/* double-check if current erp/cqr was successfull */
+	if ((cqr->dstat->cstat == 0x00) &&
+	    (cqr->dstat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))) {
+                DASD_MESSAGE (KERN_WARNING, device,
+                              "ERP called for successful request %p"
+                              " - NO ERP necessary",
+                              cqr);
+                
+                atomic_compare_and_swap_debug (&erp->status,
+                                               CQR_STATUS_ERROR,
+                                               CQR_STATUS_DONE);
+
+		return cqr;
+	}
+	/* check if sense data are available */
+	if (!cqr->dstat->ii.sense.data) {
+		DASD_MESSAGE (KERN_WARNING, device,
+			"ERP called witout sense data avail ..."
+			"request %p - NO ERP possible",
+			cqr);
+
+                atomic_compare_and_swap_debug (&erp->status,
+                                               CQR_STATUS_ERROR,
+                                               CQR_STATUS_FAILED);
+
+		return cqr; 
+
+	}
+
+	/* check if error happened before */
+	erp = dasd_3990_erp_in_erp (cqr);
+
+	if (erp == NULL) {
+		/* no matching erp found - set up erp */
+		erp = dasd_3990_erp_additional_erp (cqr);
+	} else {
+		/* matching erp found - set all leading erp's to DONE */
+		dasd_3990_erp_handle_match_erp (cqr, erp);
+		erp = cqr;
+	}
+
+#ifdef ERP_DEBUG
+	/* print current erp_chain */
+        printk(KERN_WARNING PRINTK_HEADER 
+               "ERP chain at END of ERP-ACTION\n");
+        {
+                ccw_req_t *temp_erp = NULL;
+                for (temp_erp = erp; temp_erp != NULL; temp_erp = temp_erp->refers){
+                        printk(KERN_WARNING PRINTK_HEADER 
+                               "      erp %p refers to %p \n",
+                               temp_erp,
+                               temp_erp->refers);
+                }
+        }
+#endif
 
-	}			/* end distinguish between 24 and 32 byte sense data */
+	return erp;
 
-}				/* END dasd_3990_erp_examine */
+} /* end dasd_3990_erp_action */
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/block/dasd_3990_erp.h linux.19p18/drivers/s390/block/dasd_3990_erp.h
--- linux.vanilla/drivers/s390/block/dasd_3990_erp.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/s390/block/dasd_3990_erp.h	Tue Feb 20 13:26:26 2001
@@ -0,0 +1,21 @@
+/* 
+ * File...........: linux/drivers/s390/block/dasd_3990_erp.h
+ * Author(s)......: Horst Hummel <Horst Hummel@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
+ *
+ * History of changes (starts Jul 2000)
+ */
+
+#ifndef DASD_3990_ERP_H
+#define DASD_3990_ERP_H
+
+
+dasd_era_t dasd_3990_erp_examine (ccw_req_t *, devstat_t *);
+
+ccw_req_t *dasd_3990_erp_action (ccw_req_t *);
+ccw_req_t *dasd_2105_erp_action (ccw_req_t *);
+
+void dasd_3990_erp_restart_queue (unsigned long);
+
+#endif /* DASD_3990_ERP_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/block/dasd_9336_erp.c linux.19p18/drivers/s390/block/dasd_9336_erp.c
--- linux.vanilla/drivers/s390/block/dasd_9336_erp.c	Sat Sep  9 18:42:40 2000
+++ linux.19p18/drivers/s390/block/dasd_9336_erp.c	Thu Dec 21 22:50:30 2000
@@ -5,6 +5,7 @@
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
  */
 
+#include <linux/blkdev.h>
 #include <asm/ccwcache.h>
 #include <asm/dasd.h>
 
@@ -32,8 +33,6 @@
 dasd_era_t
 dasd_9336_erp_examine (ccw_req_t * cqr, devstat_t * stat)
 {
-	char *sense = stat->ii.sense.data;
-
 	/* check for successful execution first */
 	if (stat->cstat == 0x00 &&
 	    stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/block/dasd_9343_erp.c linux.19p18/drivers/s390/block/dasd_9343_erp.c
--- linux.vanilla/drivers/s390/block/dasd_9343_erp.c	Sat Sep  9 18:42:40 2000
+++ linux.19p18/drivers/s390/block/dasd_9343_erp.c	Thu Dec 21 22:50:30 2000
@@ -5,6 +5,7 @@
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
  */
 
+#include <linux/blkdev.h>
 #include <asm/ccwcache.h>
 #include <asm/dasd.h>
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/block/dasd_9343_erp.h linux.19p18/drivers/s390/block/dasd_9343_erp.h
--- linux.vanilla/drivers/s390/block/dasd_9343_erp.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/s390/block/dasd_9343_erp.h	Tue Feb 20 13:26:26 2001
@@ -0,0 +1,18 @@
+/* 
+ * File...........: linux/drivers/s390/block/dasd_9343_erp.h
+ * Author(s)......: Horst Hummel <Horst Hummel@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
+ *
+ * History of changes (starts July 2000)
+ */
+
+#ifndef DASD_9343_ERP_H
+#define DASD_9343_ERP_H
+
+
+dasd_era_t dasd_9343_erp_examine (ccw_req_t *, devstat_t *);
+
+ccw_req_t *dasd_9343_erp_action (ccw_req_t *);
+
+#endif /* DASD_9343_ERP_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/block/dasd_diag.c linux.19p18/drivers/s390/block/dasd_diag.c
--- linux.vanilla/drivers/s390/block/dasd_diag.c	Mon Dec 11 22:12:51 2000
+++ linux.19p18/drivers/s390/block/dasd_diag.c	Sun Feb 25 23:10:56 2001
@@ -268,13 +268,14 @@
                          "Null device pointer passed to characteristics checker\n");
                 return -ENODEV;
         }
+        if ( device->private != NULL ) {
+                kfree(device->private);
+        }
+        device->private = kmalloc(sizeof(dasd_diag_private_t),GFP_KERNEL);
         if ( device->private == NULL ) {
-		device->private = kmalloc(sizeof(dasd_diag_private_t),GFP_KERNEL);
-		if ( device->private == NULL ) {
-			printk ( KERN_WARNING PRINTK_HEADER
-				 "memory allocation failed for private data\n");
-			return -ENOMEM;
-		}
+                printk ( KERN_WARNING PRINTK_HEADER
+                         "memory allocation failed for private data\n");
+                return -ENOMEM;
         }
         private = (dasd_diag_private_t *)device->private;
         rdc_data = (void *)&(private->rdc_data);
@@ -318,7 +319,7 @@
                 if (rc > 4) {
                         continue;
 		}
-                cqr = ccw_alloc_request (dasd_diag_discipline.name, 2,0);
+                cqr = dasd_alloc_request (dasd_diag_discipline.name, 2,0);
                 if ( cqr == NULL ) {
                         printk ( KERN_WARNING PRINTK_HEADER
                                  "No memory to allocate initialization request\n");
@@ -501,7 +502,7 @@
 			}
 		} else {
 			PRINT_WARN ("Cannot fulfill request smaller than block\n");
-			ccw_free_request (rw_cp);
+			dasd_free_request (rw_cp);
 			return NULL;
 		}
 	}
@@ -532,6 +533,7 @@
 dasd_discipline_t dasd_diag_discipline = {
 	name :                          "DIAG",
 	ebcname :                       "DIAG",
+	max_blocks:			PAGE_SIZE/sizeof(diag_bio_t),
         check_characteristics:          dasd_diag_check_characteristics,
         do_analysis:                    dasd_diag_do_analysis,          
         fill_geometry:                  dasd_diag_fill_geometry,
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/block/dasd_eckd.c linux.19p18/drivers/s390/block/dasd_eckd.c
--- linux.vanilla/drivers/s390/block/dasd_eckd.c	Mon Dec 11 22:12:51 2000
+++ linux.19p18/drivers/s390/block/dasd_eckd.c	Sun Feb 25 23:10:56 2001
@@ -12,6 +12,7 @@
  * 08/07/00 added some bits to define_extent for ESS support
  * 10/26/00 fixed ITPMPL020144ASC (problems when accesing a device formatted by VIF)
  * 10/30/00 fixed ITPMPL010263EPA (erronoeous timeout messages)
+ * 01/23/00 fixed kmalloc in dump_sense to be GFP_ATOMIC
  */
 
 #include <linux/stddef.h>
@@ -49,22 +50,6 @@
 #define ECKD_F7(i) (i->factor7)
 #define ECKD_F8(i) (i->factor8)
 
-#define DASD_ECKD_CCW_WRITE 0x05
-#define DASD_ECKD_CCW_READ 0x06
-#define DASD_ECKD_CCW_WRITE_HOME_ADDRESS 0x09
-#define DASD_ECKD_CCW_READ_HOME_ADDRESS 0x0a
-#define DASD_ECKD_CCW_READ_COUNT 0x12
-#define DASD_ECKD_CCW_WRITE_RECORD_ZERO 0x15
-#define DASD_ECKD_CCW_READ_RECORD_ZERO 0x16
-#define DASD_ECKD_CCW_WRITE_CKD 0x1d
-#define DASD_ECKD_CCW_READ_CKD 0x1e
-#define DASD_ECKD_CCW_LOCATE_RECORD 0x47
-#define DASD_ECKD_CCW_DEFINE_EXTENT 0x63
-#define DASD_ECKD_CCW_WRITE_MT 0x85
-#define DASD_ECKD_CCW_READ_MT 0x86
-#define DASD_ECKD_CCW_READ_CKD_MT 0x9e
-#define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d
-
 dasd_discipline_t dasd_eckd_discipline;
 
 typedef struct
@@ -74,6 +59,7 @@
         eckd_count_t count_area;
 } dasd_eckd_private_t;
 
+#ifdef CONFIG_DASD_DYNAMIC
 static
 devreg_t dasd_eckd_known_devices[] = {
 	{
@@ -92,6 +78,7 @@
                 oper_func: dasd_oper_handler
         }
 };
+#endif
 
 static inline unsigned int
 round_up_multiple (unsigned int no, unsigned int mult)
@@ -372,9 +359,9 @@
 dasd_eckd_check_characteristics (struct dasd_device_t *device)
 {
         int rc = -ENODEV;
-        void *conf_data;
+        void *conf_data=NULL;
         void *rdc_data;
-        int conf_len;
+        int conf_len=0;
         dasd_eckd_private_t *private;
 
         if ( device == NULL ) {
@@ -382,13 +369,14 @@
                          "Null device pointer passed to characteristics checker\n");
                 return -ENODEV;
         }
+        if ( device->private != NULL ) {
+                kfree(device->private);
+        }
+        device->private = kmalloc(sizeof(dasd_eckd_private_t),GFP_KERNEL);
         if ( device->private == NULL ) {
-          device->private = kmalloc(sizeof(dasd_eckd_private_t),GFP_KERNEL);
-          if ( device->private == NULL ) {
-            printk ( KERN_WARNING PRINTK_HEADER
-                     "memory allocation failed for private data\n");
-            return -ENOMEM;
-          }
+                printk ( KERN_WARNING PRINTK_HEADER
+                         "memory allocation failed for private data\n");
+                return -ENOMEM;
         }
         private = (dasd_eckd_private_t *)device->private;
         rdc_data = (void *)&(private->rdc_data);
@@ -448,7 +436,7 @@
 	LO_eckd_data_t *LO_data;
 	eckd_count_t *count_data = &(((dasd_eckd_private_t *)(device->private))->count_area);
 
-        cqr = ccw_alloc_request (dasd_eckd_discipline.name, 3, sizeof (DE_eckd_data_t) + sizeof (LO_eckd_data_t));
+        cqr = dasd_alloc_request (dasd_eckd_discipline.name, 3, sizeof (DE_eckd_data_t) + sizeof (LO_eckd_data_t));
         if ( cqr == NULL ) {
                 printk ( KERN_WARNING PRINTK_HEADER
                          "No memory to allocate initialization request\n");
@@ -622,9 +610,9 @@
                         datasize += sizeof(eckd_home_t);
                 }
         }
-	fcp = ccw_alloc_request (dasd_eckd_discipline.name, 
-                                 wrccws + 2,
-                                 datasize+rpt*sizeof(eckd_count_t));
+	fcp = dasd_alloc_request (dasd_eckd_discipline.name, 
+                                  wrccws + 2,
+                                  datasize+rpt*sizeof(eckd_count_t));
         if ( fcp != NULL ) {
                 fcp->device = device;
                 fcp->retries = 2;       /* set retry counter to enable ERP */
@@ -749,21 +737,26 @@
 	}
 }
 
-static dasd_erp_action_fn_t 
-dasd_eckd_erp_action ( ccw_req_t * cqr ) 
+static dasd_erp_action_fn_t
+dasd_eckd_erp_action (ccw_req_t * cqr)
 {
-        return default_erp_action;
+	dasd_device_t *device = (dasd_device_t *) cqr->device;
+
+	switch (device->devinfo.sid_data.cu_type) {
+	case 0x3990:
+	case 0x2105:
+		return dasd_3990_erp_action;
+	case 0x9343:
+		/* return dasd_9343_erp_action; */
+	default:
+		return default_erp_action;
+	}
 }
 
 static dasd_erp_postaction_fn_t
 dasd_eckd_erp_postaction (ccw_req_t * cqr)
 {
-        if ( cqr -> function == default_erp_action)
-                return default_erp_postaction;
-        printk ( KERN_WARNING PRINTK_HEADER
-                 "unknown ERP action %p\n",
-                 cqr -> function);
-	return NULL;
+	return default_erp_postaction;
 }
 
 static ccw_req_t *
@@ -842,7 +835,7 @@
 			}
 			if (size != byt_per_blk) {
 				PRINT_WARN ("Cannot fulfill small request %ld vs. %d (%ld sects)\n", size, byt_per_blk, req->nr_sectors);
-				ccw_free_request (rw_cp);
+				dasd_free_request (rw_cp);
 				return NULL;
 			}
 			ccw->flags = CCW_FLAG_CC;
@@ -860,7 +853,7 @@
 static char *
 dasd_eckd_dump_sense(struct dasd_device_t *device, ccw_req_t *req)
 {
-        char *page = (char *)get_free_page(GFP_KERNEL);
+        char *page = (char *)get_free_page(GFP_ATOMIC);
         devstat_t *stat = &device->dev_status;
 	char *sense = stat->ii.sense.data;
         int len,sl,sct;
@@ -905,6 +898,7 @@
 dasd_discipline_t dasd_eckd_discipline = {
 	name :                          "ECKD",
 	ebcname :                       "ECKD",
+	max_blocks:			255,
         id_check:                       dasd_eckd_id_check,          
         check_characteristics:          dasd_eckd_check_characteristics,
         init_analysis:                  dasd_eckd_init_analysis,
@@ -923,7 +917,9 @@
 int
 dasd_eckd_init( void ) {
         int rc = 0;
+#ifdef CONFIG_DASD_DYNAMIC
 	int i;
+#endif
         printk ( KERN_INFO PRINTK_HEADER
                  "%s discipline initializing\n", dasd_eckd_discipline.name);
         ASCEBC(dasd_eckd_discipline.ebcname,4);
@@ -944,8 +940,9 @@
 
 void
 dasd_eckd_cleanup( void ) {
-        int rc = 0;
+#ifdef CONFIG_DASD_DYNAMIC
 	int i;
+#endif
         printk ( KERN_INFO PRINTK_HEADER
                  "%s discipline cleaning up\n", dasd_eckd_discipline.name);
 #ifdef CONFIG_DASD_DYNAMIC
@@ -960,7 +957,7 @@
 	} 
 #endif /* CONFIG_DASD_DYNAMIC */
         dasd_discipline_deq(&dasd_eckd_discipline);
-        return rc;
+        return;
 }
 
 /*
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/block/dasd_eckd.h linux.19p18/drivers/s390/block/dasd_eckd.h
--- linux.vanilla/drivers/s390/block/dasd_eckd.h	Sat Sep  9 18:42:40 2000
+++ linux.19p18/drivers/s390/block/dasd_eckd.h	Tue Feb 20 13:26:26 2001
@@ -1,6 +1,25 @@
 #ifndef DASD_ECKD_H
 #define DASD_ECKD_H
 
+#include "dasd_3990_erp.h"
+#include "dasd_9343_erp.h"
+
+#define DASD_ECKD_CCW_WRITE 0x05
+#define DASD_ECKD_CCW_READ 0x06
+#define DASD_ECKD_CCW_WRITE_HOME_ADDRESS 0x09
+#define DASD_ECKD_CCW_READ_HOME_ADDRESS 0x0a
+#define DASD_ECKD_CCW_READ_COUNT 0x12
+#define DASD_ECKD_CCW_WRITE_RECORD_ZERO 0x15
+#define DASD_ECKD_CCW_READ_RECORD_ZERO 0x16
+#define DASD_ECKD_CCW_WRITE_CKD 0x1d
+#define DASD_ECKD_CCW_READ_CKD 0x1e
+#define DASD_ECKD_CCW_LOCATE_RECORD 0x47
+#define DASD_ECKD_CCW_DEFINE_EXTENT 0x63
+#define DASD_ECKD_CCW_WRITE_MT 0x85
+#define DASD_ECKD_CCW_READ_MT 0x86
+#define DASD_ECKD_CCW_READ_CKD_MT 0x9e
+#define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d
+
 typedef 
 struct eckd_count_t {
 	__u16 cyl;
@@ -282,5 +301,6 @@
 } __attribute__ ((packed)) dasd_eckd_confdata_t;
 
 int dasd_eckd_init( void );
+void dasd_eckd_cleanup( void );
 
 #endif /* DASD_ECKD_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/block/dasd_fba.c linux.19p18/drivers/s390/block/dasd_fba.c
--- linux.vanilla/drivers/s390/block/dasd_fba.c	Mon Dec 11 22:12:51 2000
+++ linux.19p18/drivers/s390/block/dasd_fba.c	Sun Feb 25 23:10:56 2001
@@ -117,13 +117,14 @@
                          "Null device pointer passed to characteristics checker\n");
                 return -ENODEV;
         }
+        if ( device->private != NULL ) {
+                kfree(device->private);
+        }
+        device->private = kmalloc(sizeof(dasd_fba_private_t),GFP_KERNEL);
         if ( device->private == NULL ) {
-		device->private = kmalloc(sizeof(dasd_fba_private_t),GFP_KERNEL);
-		if ( device->private == NULL ) {
-			printk ( KERN_WARNING PRINTK_HEADER
-				 "memory allocation failed for private data\n");
-			return -ENOMEM;
-		}
+                printk ( KERN_WARNING PRINTK_HEADER
+                         "memory allocation failed for private data\n");
+                return -ENOMEM;
         }
         private = (dasd_fba_private_t *)device->private;
         rdc_data = (void *)&(private->rdc_data);
@@ -181,9 +182,7 @@
         int rc = 0;
 	unsigned long sectors = device->sizes.blocks << device->sizes.s2b_shift;
 	unsigned long tracks = sectors >> 6;
-	unsigned long trk_rem = sectors & ((1<<6)-1);
 	unsigned long cyls = tracks >> 4;
-	unsigned long cyls_rem = tracks & ((1<<4)-1);
 
         switch(device->sizes.bp_block) {
         case 512:
@@ -308,7 +307,7 @@
 					ccw->flags = CCW_FLAG_DC;
 				} else {
 					PRINT_WARN ("Cannot chain chunks smaller than one block\n");
-					ccw_free_request (rw_cp);
+					dasd_free_request (rw_cp);
 					return NULL;
 				}
 				ccw->cmd_code = rw_cmd;
@@ -320,7 +319,7 @@
 			ccw->flags = CCW_FLAG_CC;
 			if (size != byt_per_blk) {
 				PRINT_WARN ("Cannot fulfill request smaller than block\n");
-				ccw_free_request (rw_cp);
+				dasd_free_request (rw_cp);
 				return NULL;
 			}
 		}
@@ -354,6 +353,7 @@
 dasd_discipline_t dasd_fba_discipline = {
 	name :                          "FBA ",
 	ebcname :                       "FBA ",
+	max_blocks:			PAGE_SIZE/sizeof(ccw1_t),
         id_check:                       dasd_fba_id_check,          
         check_characteristics:          dasd_fba_check_characteristics,
         do_analysis:                    dasd_fba_do_analysis,          
@@ -371,7 +371,9 @@
 int
 dasd_fba_init( void ) {
         int rc = 0;
+#ifdef	CONFIG_DASD_DYNAMIC
 	int i;
+#endif
         printk ( KERN_INFO PRINTK_HEADER
                  "%s discipline initializing\n", dasd_fba_discipline.name);
         ASCEBC(dasd_fba_discipline.ebcname,4);
@@ -392,8 +394,9 @@
 
 void
 dasd_fba_cleanup( void ) {
-        int rc = 0;
+#ifdef	CONFIG_DASD_DYNAMIC
 	int i;
+#endif
         printk ( KERN_INFO PRINTK_HEADER
                  "%s discipline cleaning up\n", dasd_fba_discipline.name);
 #ifdef CONFIG_DASD_DYNAMIC
@@ -408,7 +411,7 @@
         }
 #endif /* CONFIG_DASD_DYNAMIC */
         dasd_discipline_deq(&dasd_fba_discipline);
-        return rc;
+        return;
 }
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/block/dasd_fba.h linux.19p18/drivers/s390/block/dasd_fba.h
--- linux.vanilla/drivers/s390/block/dasd_fba.h	Sat Sep  9 18:42:40 2000
+++ linux.19p18/drivers/s390/block/dasd_fba.h	Thu Dec 21 22:50:30 2000
@@ -66,5 +66,6 @@
 } __attribute__ ((packed)) dasd_fba_characteristics_t;
 
 int dasd_fba_init( void );
+void dasd_fba_cleanup( void );
 
 #endif /* DASD_FBA_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/block/mdisk.c linux.19p18/drivers/s390/block/mdisk.c
--- linux.vanilla/drivers/s390/block/mdisk.c	Sun Jun 11 21:44:15 2000
+++ linux.19p18/drivers/s390/block/mdisk.c	Thu Dec 21 22:50:30 2000
@@ -105,6 +105,122 @@
 } mdisk_setup_data;
 
 /*
+ * The 'low level' IO function
+ */
+
+static __inline__ int
+dia250(void* iob,int cmd)
+{
+	int rc;
+	
+	iob = (void*) virt_to_phys(iob);
+
+	asm volatile ("    lr    2,%1\n"
+		      "    lr    3,%2\n"
+		      "    .long 0x83230250\n"
+		      "    lr    %0,3"
+		      : "=d" (rc)
+		      : "d" (iob) , "d" (cmd)
+		      : "2", "3" );
+	return rc;
+}
+
+/*
+ * The device characteristics function
+ */
+
+static __inline__ int
+dia210(void* devchar)
+{
+	int rc;
+
+	devchar = (void*) virt_to_phys(devchar);
+
+	asm volatile ("    lr    2,%1\n"
+		      "    .long 0x83200210\n"
+		      "    ipm   %0\n"
+		      "    srl   %0,28"
+		      : "=d" (rc)
+		      : "d" (devchar)
+		      : "2" );
+	return rc;
+}
+
+
+/*
+ * release of minidisk device
+ */
+
+static __inline__ int
+mdisk_term_io(mdisk_Dev *dev)
+{
+	mdisk_init_io_t *iob = (mdisk_init_io_t*) dev->iob;
+	
+	memset(iob,0,sizeof(mdisk_init_io_t));
+	
+	iob->dev_nr = dev->vdev;
+	
+	return dia250(iob,TERM_BIO);
+}
+
+
+/*
+ * Init of minidisk device
+ */
+
+static __inline__ int
+mdisk_init_io(mdisk_Dev *dev,int blocksize,int offset,int size)
+{
+	mdisk_init_io_t *iob = (mdisk_init_io_t*) dev->iob;
+	int rc;
+
+	memset(iob,0,sizeof(mdisk_init_io_t));
+	
+	iob->dev_nr = dev->vdev;
+	iob->block_size = blocksize;
+	iob->offset     = offset;
+	iob->start_block= 0;
+	iob->end_block  = size;
+	
+	rc = dia250(iob,INIT_BIO);
+	
+	/*
+	 * clear for following io once
+	 */
+	
+	memset(iob,0,sizeof(mdisk_rw_io_t));
+	
+	return rc;
+}
+
+
+/*
+ * setup and start of minidisk io request
+ */
+
+static __inline__ int
+mdisk_rw_io_clustered (mdisk_Dev *dev,
+                       mdisk_bio_t* bio_array,
+                       int length,
+                       int req,
+                       int sync)
+{
+	int rc;
+	mdisk_rw_io_t *iob = dev->iob;
+	
+	iob->dev_nr      = dev->vdev;
+	iob->key         = 0;
+	iob->flags       = sync;
+	
+	iob->block_count = length;
+	iob->interrupt_params = req;
+	iob->bio_list     = virt_to_phys(bio_array);
+	
+	rc = dia250(iob,RW_BIO);
+	return rc;
+}
+
+/*
  * Parameter parsing function, called from init/main.c
  * vdev    : virtual device number
  * size    : size in kbyte
@@ -117,7 +233,7 @@
 {
 	char *cur = str;
 	int vdev, size, offset=0,blksize;
-	static i = 0;
+static	int i = 0;
 	if (!i)
 	  memset(&mdisk_setup_data,0,sizeof(mdisk_setup_data));
 
@@ -280,48 +396,7 @@
 	NULL,          /* mdisk_lock */
 };
 
-/*
- * The 'low level' IO function
- */
-
-
-static __inline__ int
-dia250(void* iob,int cmd)
-{
-	int rc;
-	
-	iob = (void*) virt_to_phys(iob);
-
-	asm volatile ("    lr    2,%1\n"
-		      "    lr    3,%2\n"
-		      "    .long 0x83230250\n"
-		      "    lr    %0,3"
-		      : "=d" (rc)
-		      : "d" (iob) , "d" (cmd)
-		      : "2", "3" );
-	return rc;
-}
-
-/*
- * The device characteristics function
- */
-
-static __inline__ int
-dia210(void* devchar)
-{
-	int rc;
-
-	devchar = (void*) virt_to_phys(devchar);
 
-	asm volatile ("    lr    2,%1\n"
-		      "    .long 0x83200210\n"
-		      "    ipm   %0\n"
-		      "    srl   %0,28"
-		      : "=d" (rc)
-		      : "d" (devchar)
-		      : "2" );
-	return rc;
-}
 /*
  * read the label of a minidisk and extract its characteristics
  */
@@ -396,80 +471,6 @@
 }
 
 
-
-/*
- * Init of minidisk device
- */
-
-static __inline__ int
-mdisk_init_io(mdisk_Dev *dev,int blocksize,int offset,int size)
-{
-	mdisk_init_io_t *iob = (mdisk_init_io_t*) dev->iob;
-	int rc;
-
-	memset(iob,0,sizeof(mdisk_init_io_t));
-	
-	iob->dev_nr = dev->vdev;
-	iob->block_size = blocksize;
-	iob->offset     = offset;
-	iob->start_block= 0;
-	iob->end_block  = size;
-	
-	rc = dia250(iob,INIT_BIO);
-	
-	/*
-	 * clear for following io once
-	 */
-	
-	memset(iob,0,sizeof(mdisk_rw_io_t));
-	
-	return rc;
-}
-
-/*
- * release of minidisk device
- */
-
-static __inline__ int
-mdisk_term_io(mdisk_Dev *dev)
-{
-	mdisk_init_io_t *iob = (mdisk_init_io_t*) dev->iob;
-	
-	memset(iob,0,sizeof(mdisk_init_io_t));
-	
-	iob->dev_nr = dev->vdev;
-	
-	return dia250(iob,TERM_BIO);
-}
-
-/*
- * setup and start of minidisk io request
- */
-
-static __inline__ int
-mdisk_rw_io_clustered (mdisk_Dev *dev,
-                       mdisk_bio_t* bio_array,
-                       int length,
-                       int req,
-                       int sync)
-{
-	int rc;
-	mdisk_rw_io_t *iob = dev->iob;
-	
-	iob->dev_nr      = dev->vdev;
-	iob->key         = 0;
-	iob->flags       = sync;
-	
-	iob->block_count = length;
-	iob->interrupt_params = req;
-	iob->bio_list     = virt_to_phys(bio_array);
-	
-	rc = dia250(iob,RW_BIO);
-	return rc;
-}
-
-
-
 /*
  * this handles a clustered request in success case
  * all buffers are detach and marked uptodate to the kernel
@@ -640,11 +641,8 @@
  */
 void do_mdisk_interrupt(struct pt_regs *regs, __u16 code)
 {
-        u16 code;
 	mdisk_Dev *dev;
 	
-	code = S390_lowcore.cpu_addr;
-
 	if ((code >> 8) != 0x03) {
 	  printk("mnd: wrong sub-interruption code %d",code>>8);
 	  return;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/block/xpram.c linux.19p18/drivers/s390/block/xpram.c
--- linux.vanilla/drivers/s390/block/xpram.c	Mon Dec 11 22:12:51 2000
+++ linux.19p18/drivers/s390/block/xpram.c	Mon Feb 19 18:37:49 2001
@@ -413,7 +413,7 @@
 		"   .long 0xb22e0012 \n"   /* pgin r1,r2                     */
 		/* copy page from expanded memory */
 		"0: ipm  %0          \n"   /* save status (cc & program mask */
-		"   srl  %0,28(0)    \n"   /* cc into least significant bits */
+		"   srl  %0,28       \n"   /* cc into least significant bits */
                 "1:                  \n"   /* we are done                    */
                 ".section .fixup,\"ax\"\n" /* start of fix up section        */
                 "2: lhi    %0,2      \n"   /* return unused condition code 2 */
@@ -456,7 +456,7 @@
 		" .long 0xb22f0012 \n"   /* pgout r1,r2                    */
                                 /* copy page from expanded memory */
 		"0: ipm  %0        \n"   /* save status (cc & program mask */
-                " srl  %0,28(0)    \n"   /* cc into least significant bits */
+                " srl  %0,28       \n"   /* cc into least significant bits */
                 "1:                  \n"   /* we are done                    */
                 ".section .fixup,\"ax\"\n" /* start of fix up section        */
                 "2: lhi   %0,2       \n"   /* return unused condition code 2 */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/ccwcache.c linux.19p18/drivers/s390/ccwcache.c
--- linux.vanilla/drivers/s390/ccwcache.c	Mon Dec 11 22:12:51 2000
+++ linux.19p18/drivers/s390/ccwcache.c	Mon Feb 19 18:33:37 2001
@@ -8,6 +8,7 @@
    * 07/10/00 moved ccwcache.h from linux/ to asm/
  */
 
+#include <linux/module.h>
 #include <linux/malloc.h>
 #include <asm/debug.h>
 #include <asm/ccwcache.h>
@@ -15,19 +16,14 @@
 #include <asm/ebcdic.h>
 #include <asm/spinlock.h>
 
-#ifdef PRINTK_HEADER
-#undef PRINTK_HEADER
-#endif
+#undef  PRINTK_HEADER
 #define PRINTK_HEADER "ccwcache"
 
-#ifdef MODULE
 MODULE_AUTHOR ("Holger Smolinski <Holger.Smolinski@de.ibm.com>");
 MODULE_DESCRIPTION ("Linux on S/390 CCW cache,"
 		    "Copyright 2000 IBM Corporation");
-EXPORT_NO_SYMBOLS; 
 EXPORT_SYMBOL(ccw_alloc_request);
 EXPORT_SYMBOL(ccw_free_request);
-#endif /* MODULE */
 
 
 /* pointer to list of allocated requests */
@@ -314,8 +310,7 @@
 	} else {
 		printk (KERN_DEBUG PRINTK_HEADER "debug area is 0x%8p\n", debug_area );
 	}
-        debug_register_view(debug_area,&debug_hex_view);
-        debug_register_view(debug_area,&debug_ebcdic_view);
+        debug_register_view(debug_area,&debug_hex_ascii_view);
 	debug_text_event ( debug_area, 0, "INIT");
 	
 	/* First allocate the kmem caches */
@@ -389,3 +384,4 @@
 	ccwcache_cleanup();
 }
 #endif /* MODULE */
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/char/hwc.h linux.19p18/drivers/s390/char/hwc.h
--- linux.vanilla/drivers/s390/char/hwc.h	Mon Dec 11 22:12:51 2000
+++ linux.19p18/drivers/s390/char/hwc.h	Mon Feb 19 18:36:14 2001
@@ -39,6 +39,8 @@
 #define HWC_BUSY		2
 #define HWC_NOT_OPERATIONAL	3
 
+#define hwc_cmdw_t u32;
+
 #define HWC_CMDW_READDATA 0x00770005
 
 #define HWC_CMDW_WRITEDATA 0x00760005
@@ -207,9 +209,25 @@
 	0x0000,
 	0x0000,
 	sizeof (_hwcb_mask_t),
-	ET_OpCmd_Mask | ET_PMsgCmd_Mask,
-	ET_Msg_Mask
+	ET_OpCmd_Mask | ET_PMsgCmd_Mask | ET_StateChange_Mask,
+	ET_Msg_Mask | ET_PMsgCmd_Mask
 };
+
+typedef struct {
+	_EBUF_HEADER
+	u8 validity_hwc_active_facility_mask:1;
+	u8 validity_hwc_receive_mask:1;
+	u8 validity_hwc_send_mask:1;
+	u8 validity_read_data_function_mask:1;
+	u16 _zeros:12;
+	u16 mask_length;
+	u64 hwc_active_facility_mask;
+	_hwcb_mask_t hwc_receive_mask;
+	_hwcb_mask_t hwc_send_mask;
+	u32 read_data_function_mask;
+} __attribute__ ((packed)) 
+
+statechangebuf_t;
 
 #define _GDS_VECTOR_HEADER	u16	length; \
 				u16	gds_id;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/char/hwc_rw.c linux.19p18/drivers/s390/char/hwc_rw.c
--- linux.vanilla/drivers/s390/char/hwc_rw.c	Mon Dec 11 22:12:51 2000
+++ linux.19p18/drivers/s390/char/hwc_rw.c	Mon Feb 19 18:36:14 2001
@@ -29,9 +29,13 @@
 #include <asm/s390_ext.h>
 
 #ifndef MIN
-#define MIN(a,b) ((a<b) ? a : b)
+#define MIN(a,b) (((a<b) ? a : b))
 #endif
 
+#define HWC_ASCEBC(x) ((MACHINE_IS_VM ? _ascebc[x] : _ascebc_500[x]))
+
+#define HWC_EBCASC_STR(s,c) ((MACHINE_IS_VM ? EBCASC(s,c) : EBCASC_500(s,c)))
+
 #define HWC_RW_PRINT_HEADER "hwc low level driver: "
 
 #define  USE_VM_DETECTION
@@ -50,7 +54,7 @@
 
 #undef BUFFER_STRESS_TEST
 
-#define MEASURE_HWC_OUTPUT
+#undef MEASURE_HWC_OUTPUT
 
 typedef struct {
 	unsigned char *next;
@@ -119,15 +123,16 @@
 static unsigned char
  _page[PAGE_SIZE] __attribute__ ((aligned (PAGE_SIZE)));
 
-typedef u32 kmem_pages_t;
+typedef unsigned long kmem_pages_t;
 
 #define MAX_KMEM_PAGES (sizeof(kmem_pages_t) << 3)
 
-#define HWC_TIMER_RUNS	1
-#define HWC_FLUSH	2
-#define HWC_INIT	4
-#define HWC_BROKEN	8
-#define HWC_INTERRUPT	16
+#define HWC_WTIMER_RUNS	1
+#define HWC_FLUSH		2
+#define HWC_INIT		4
+#define HWC_BROKEN		8
+#define HWC_INTERRUPT		16
+#define HWC_PTIMER_RUNS	32
 
 static struct {
 
@@ -169,6 +174,7 @@
 	unsigned char write_prio:1;
 	unsigned char read_nonprio:1;
 	unsigned char read_prio:1;
+	unsigned char read_statechange:1;
 
 	unsigned char flags;
 
@@ -177,6 +183,8 @@
 	spinlock_t lock;
 
 	struct timer_list write_timer;
+
+	struct timer_list poll_timer;
 } hwc_data =
 {
 	{
@@ -185,7 +193,6 @@
 		8,
 		    0,
 		    80,
-		    CODE_ASCII,
 		    1,
 		    50,
 		    MAX_KMEM_PAGES,
@@ -218,6 +225,7 @@
 	    0,
 	    0,
 	    0,
+	    0,
 	    NULL
 
 };
@@ -231,7 +239,6 @@
 
 static signed int do_hwc_write (int from_user, unsigned char *,
 				unsigned int,
-				unsigned char,
 				unsigned char);
 
 static asmlinkage int 
@@ -244,7 +251,7 @@
 	va_start (args, fmt);
 	i = vsprintf (buf, fmt, args);
 	va_end (args);
-	return do_hwc_write (0, buf, i, CODE_ASCII, write_time);
+	return do_hwc_write (0, buf, i, write_time);
 }
 
 int 
@@ -260,7 +267,7 @@
 
 	i = vsprintf (buf, fmt, args);
 	va_end (args);
-	retval = do_hwc_write (0, buf, i, CODE_ASCII, IMMEDIATE_WRITE);
+	retval = do_hwc_write (0, buf, i, IMMEDIATE_WRITE);
 
 	spin_unlock_irqrestore (&hwc_data.lock, flags);
 
@@ -310,8 +317,8 @@
 {
 	unsigned int condition_code = 1;
 
-	__asm__ __volatile__ ("L 1, 0(0,%0) \n\t"
-			      "LRA 2, 0(0,%1) \n\t"
+	__asm__ __volatile__ ("L 1, 0(%0) \n\t"
+			      "LRA 2, 0(%1) \n\t"
 			      ".long 0xB2200012 \n\t"
 			      :
 			      :"a" (&hwc_command_word), "a" (hwcb)
@@ -329,7 +336,7 @@
 {
 	u32 param;
 
-	__asm__ __volatile__ ("L %0,128(0,0)\n\t"
+	__asm__ __volatile__ ("L %0,128\n\t"
 			      :"=r" (param));
 
 	return ((unsigned char *) param);
@@ -350,9 +357,6 @@
 
 	memcpy (hwcb, &write_hwcb_template, sizeof (write_hwcb_t));
 
-	if (!hwc_data.write_nonprio && hwc_data.write_prio)
-		hwcb->msgbuf.type = ET_PMsgCmd;
-
 	return 0;
 }
 
@@ -375,7 +379,7 @@
 
 #ifdef DUMP_HWC_WRITE_LIST_ERROR
 		__asm__ ("LHI 1,0xe30\n\t"
-			 "LRA 2,0(0,%0) \n\t"
+			 "LRA 2,0(%0) \n\t"
 			 "J .+0 \n\t"
 	      :
 	      :	 "a" (bad_addr)
@@ -437,8 +441,8 @@
 	if (hwc_data.hwcb_count < 2)
 #ifdef DUMP_HWC_WRITE_LIST_ERROR
 		__asm__ ("LHI 1,0xe31\n\t"
-			 "LRA 2,0(0,%0)\n\t"
-			 "LRA 3,0(0,%1)\n\t"
+			 "LRA 2,0(%0)\n\t"
+			 "LRA 3,0(%1)\n\t"
 			 "J .+0 \n\t"
 	      :
 	      :	 "a" (BUF_HWCB), "a" (OUT_HWCB)
@@ -658,32 +662,65 @@
 	return count;
 }
 
+static int write_event_data_1 (void);
+
+static void 
+do_poll_hwc (unsigned long data)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave (&hwc_data.lock, flags);
+
+	write_event_data_1 ();
+
+	spin_unlock_irqrestore (&hwc_data.lock, flags);
+}
+
+void 
+start_poll_hwc (void)
+{
+	init_timer (&hwc_data.poll_timer);
+	hwc_data.poll_timer.function = do_poll_hwc;
+	hwc_data.poll_timer.data = (unsigned long) NULL;
+	hwc_data.poll_timer.expires = jiffies + 2 * HZ;
+	add_timer (&hwc_data.poll_timer);
+	hwc_data.flags |= HWC_PTIMER_RUNS;
+}
+
 static int 
 write_event_data_1 (void)
 {
 	unsigned short int condition_code;
 	int retval;
+	write_hwcb_t *hwcb = (write_hwcb_t *) OUT_HWCB;
 
-	if ((!hwc_data.write_prio) && (!hwc_data.write_nonprio))
-		return -EPERM;
+	if ((!hwc_data.write_prio) &&
+	    (!hwc_data.write_nonprio) &&
+	    hwc_data.read_statechange)
+		return -EOPNOTSUPP;
 
 	if (hwc_data.current_servc)
 		return -EBUSY;
 
 	retval = sane_write_hwcb ();
 	if (retval < 0)
-		return retval;
+		return -EIO;
 
 	if (!OUT_HWCB_MTO)
 		return -ENODATA;
 
+	if (!hwc_data.write_nonprio && hwc_data.write_prio)
+		hwcb->msgbuf.type = ET_PMsgCmd;
+	else
+		hwcb->msgbuf.type = ET_Msg;
+
 	condition_code = service_call (HWC_CMDW_WRITEDATA, OUT_HWCB);
 
 #ifdef DUMP_HWC_WRITE_ERROR
 	if (condition_code != HWC_COMMAND_INITIATED)
 		__asm__ ("LHI 1,0xe20\n\t"
-			 "L 2,0(0,%0)\n\t"
-			 "LRA 3,0(0,%1)\n\t"
+			 "L 2,0(%0)\n\t"
+			 "LRA 3,0(%1)\n\t"
 			 "J .+0 \n\t"
 	      :
 	      :	 "a" (&condition_code), "a" (OUT_HWCB)
@@ -702,6 +739,8 @@
 	case HWC_BUSY:
 		retval = -EBUSY;
 		break;
+	case HWC_NOT_OPERATIONAL:
+		start_poll_hwc ();
 	default:
 		retval = -EIO;
 	}
@@ -724,7 +763,7 @@
 write_event_data_2 (void)
 {
 	write_hwcb_t *hwcb;
-	int retval;
+	int retval = 0;
 
 #ifdef DUMP_HWC_WRITE_ERROR
 	unsigned char *param;
@@ -734,7 +773,7 @@
 		internal_print (
 				       DELAYED_WRITE,
 				       HWC_RW_PRINT_HEADER
-				       "write_event_mask_2 : "
+				       "write_event_data_2 : "
 				       "HWCB address does not fit "
 				       "(expected: 0x%x, got: 0x%x).\n",
 				       hwc_data.current_hwcb,
@@ -748,10 +787,10 @@
 #ifdef DUMP_HWC_WRITE_LIST_ERROR
 	if (((unsigned char *) hwcb) != hwc_data.current_hwcb) {
 		__asm__ ("LHI 1,0xe22\n\t"
-			 "LRA 2,0(0,%0)\n\t"
-			 "LRA 3,0(0,%1)\n\t"
-			 "LRA 4,0(0,%2)\n\t"
-			 "LRA 5,0(0,%3)\n\t"
+			 "LRA 2,0(%0)\n\t"
+			 "LRA 3,0(%1)\n\t"
+			 "LRA 4,0(%2)\n\t"
+			 "LRA 5,0(%3)\n\t"
 			 "J .+0 \n\t"
 	      :
 	      :	 "a" (OUT_HWCB),
@@ -765,11 +804,11 @@
 #ifdef DUMP_HWC_WRITE_ERROR
 	if (hwcb->response_code != 0x0020) {
 		__asm__ ("LHI 1,0xe21\n\t"
-			 "LRA 2,0(0,%0)\n\t"
-			 "LRA 3,0(0,%1)\n\t"
-			 "LRA 4,0(0,%2)\n\t"
-			 "LH 5,0(0,%3)\n\t"
-			 "SRL 5,8(0)\n\t"
+			 "LRA 2,0(%0)\n\t"
+			 "LRA 3,0(%1)\n\t"
+			 "LRA 4,0(%2)\n\t"
+			 "LH 5,0(%3)\n\t"
+			 "SRL 5,8\n\t"
 			 "J .+0 \n\t"
 	      :
 	      :	 "a" (OUT_HWCB), "a" (hwc_data.current_hwcb),
@@ -779,11 +818,22 @@
 	}
 #endif
 
-	if (hwcb->response_code == 0x0020) {
+	switch (hwcb->response_code) {
+	case 0x0020:
 
 		retval = OUT_HWCB_CHAR;
 		release_write_hwcb ();
-	} else {
+		break;
+	case 0x0040:
+	case 0x0340:
+	case 0x40F0:
+		if (!hwc_data.read_statechange) {
+			hwcb->response_code = 0;
+			start_poll_hwc ();
+		}
+		retval = -EIO;
+		break;
+	default:
 		internal_print (
 				       DELAYED_WRITE,
 				       HWC_RW_PRINT_HEADER
@@ -796,6 +846,13 @@
 		retval = -EIO;
 	}
 
+	if (retval == -EIO) {
+
+		hwcb->control_mask[0] = 0;
+		hwcb->control_mask[1] = 0;
+		hwcb->control_mask[2] = 0;
+		hwcb->response_code = 0;
+	}
 	hwc_data.current_servc = 0;
 	hwc_data.current_hwcb = NULL;
 
@@ -819,10 +876,10 @@
 #ifdef DUMP_HWC_WRITE_LIST_ERROR
 		if (add_mto (message, count) != count)
 			__asm__ ("LHI 1,0xe32\n\t"
-				 "LRA 2,0(0,%0)\n\t"
-				 "L 3,0(0,%1)\n\t"
-				 "LRA 4,0(0,%2)\n\t"
-				 "LRA 5,0(0,%3)\n\t"
+				 "LRA 2,0(%0)\n\t"
+				 "L 3,0(%1)\n\t"
+				 "LRA 4,0(%2)\n\t"
+				 "LRA 5,0(%3)\n\t"
 				 "J .+0 \n\t"
 		      :
 		      :	 "a" (message), "a" (&hwc_data.kmem_pages),
@@ -840,9 +897,9 @@
 		 unsigned short count)
 {
 
-	if ((!hwc_data.obuf_start) && (hwc_data.flags & HWC_TIMER_RUNS)) {
+	if ((!hwc_data.obuf_start) && (hwc_data.flags & HWC_WTIMER_RUNS)) {
 		del_timer (&hwc_data.write_timer);
-		hwc_data.flags &= ~HWC_TIMER_RUNS;
+		hwc_data.flags &= ~HWC_WTIMER_RUNS;
 	}
 	hwc_data.obuf_start += count;
 
@@ -888,13 +945,12 @@
 		     int from_user,
 		     unsigned char *msg,
 		     unsigned int count,
-		     unsigned char code,
 		     unsigned char write_time)
 {
 	unsigned int i_msg = 0;
 	unsigned short int spaces = 0;
 	unsigned int processed_characters = 0;
-	unsigned char ch, orig_ch;
+	unsigned char ch;
 	unsigned short int obuf_count;
 	unsigned short int obuf_cursor;
 	unsigned short int obuf_columns;
@@ -911,15 +967,10 @@
 	}
 
 	for (i_msg = 0; i_msg < count; i_msg++) {
-
 		if (from_user)
-			get_user (orig_ch, msg + i_msg);
+			get_user (ch, msg + i_msg);
 		else
-			orig_ch = msg[i_msg];
-		if (code == CODE_EBCDIC)
-			ch = (MACHINE_IS_VM ? _ebcasc[orig_ch] : _ebcasc_500[orig_ch]);
-		else
-			ch = orig_ch;
+			ch = msg[i_msg];
 
 		processed_characters++;
 
@@ -957,7 +1008,7 @@
 				if (obuf_cursor < obuf_columns) {
 					hwc_data.obuf[hwc_data.obuf_start +
 						      obuf_cursor]
-					    = 0x20;
+					    = HWC_ASCEBC (' ');
 					obuf_cursor++;
 				} else
 					break;
@@ -975,7 +1026,7 @@
 			while (spaces) {
 				hwc_data.obuf[hwc_data.obuf_start +
 					      obuf_cursor - spaces]
-				    = 0x20;
+				    = HWC_ASCEBC (' ');
 				spaces--;
 			}
 
@@ -1005,11 +1056,7 @@
 			if (isprint (ch))
 				hwc_data.obuf[hwc_data.obuf_start +
 					      obuf_cursor++]
-				    = (code == CODE_ASCII) ?
-				    (MACHINE_IS_VM ?
-				     _ascebc[orig_ch] :
-				     _ascebc_500[orig_ch]) :
-				    orig_ch;
+				    = HWC_ASCEBC (ch);
 		}
 		if (obuf_cursor > obuf_count)
 			obuf_count = obuf_cursor;
@@ -1028,11 +1075,10 @@
 
 			if (hwc_data.ioctls.final_nl > 0) {
 
-				if (hwc_data.flags & HWC_TIMER_RUNS) {
+				if (hwc_data.flags & HWC_WTIMER_RUNS) {
 
-					hwc_data.write_timer.expires =
-					    jiffies +
-					    hwc_data.ioctls.final_nl * HZ / 10;
+					mod_timer (&hwc_data.write_timer,
+						   jiffies + hwc_data.ioctls.final_nl * HZ / 10);
 				} else {
 
 					init_timer (&hwc_data.write_timer);
@@ -1044,7 +1090,7 @@
 					    jiffies +
 					    hwc_data.ioctls.final_nl * HZ / 10;
 					add_timer (&hwc_data.write_timer);
-					hwc_data.flags |= HWC_TIMER_RUNS;
+					hwc_data.flags |= HWC_WTIMER_RUNS;
 				}
 			} else;
 
@@ -1072,8 +1118,7 @@
 	spin_lock_irqsave (&hwc_data.lock, flags);
 
 	retval = do_hwc_write (from_user, (unsigned char *) msg,
-			       count, hwc_data.ioctls.code,
-			       IMMEDIATE_WRITE);
+			       count, IMMEDIATE_WRITE);
 
 	spin_unlock_irqrestore (&hwc_data.lock, flags);
 
@@ -1329,15 +1374,11 @@
 	if (hwc_data.ioctls.delim)
 		count = seperate_cases (start, count);
 
+	HWC_EBCASC_STR (start, count);
+
 	if (hwc_data.ioctls.echo)
-		do_hwc_write (0, start, count, CODE_EBCDIC, IMMEDIATE_WRITE);
+		do_hwc_write (0, start, count, IMMEDIATE_WRITE);
 
-	if (hwc_data.ioctls.code == CODE_ASCII) {
-		if (MACHINE_IS_VM)
-			EBCASC (start, count);
-		else
-			EBCASC_500 (start, count);
-	}
 	if (hwc_data.calls != NULL)
 		if (hwc_data.calls->move_input != NULL)
 			(hwc_data.calls->move_input) (start, count);
@@ -1440,7 +1481,7 @@
 	return retval;
 }
 
-inline static int 
+static int 
 eval_evbuf (gds_vector_t * start, void *end)
 {
 	gds_vector_t *vec;
@@ -1458,6 +1499,128 @@
 	return retval;
 }
 
+static inline int 
+eval_hwc_receive_mask (_hwcb_mask_t mask)
+{
+
+	hwc_data.write_nonprio
+	    = ((mask & ET_Msg_Mask) == ET_Msg_Mask);
+
+	hwc_data.write_prio
+	    = ((mask & ET_PMsgCmd_Mask) == ET_PMsgCmd_Mask);
+
+	if (hwc_data.write_prio || hwc_data.write_nonprio) {
+		internal_print (
+				       DELAYED_WRITE,
+				       HWC_RW_PRINT_HEADER
+				       "can write messages\n");
+		return 0;
+	} else {
+		internal_print (
+				       DELAYED_WRITE,
+				       HWC_RW_PRINT_HEADER
+				       "can not write messages\n");
+		return -1;
+	}
+}
+
+static inline int 
+eval_hwc_send_mask (_hwcb_mask_t mask)
+{
+
+	hwc_data.read_statechange
+	    = ((mask & ET_StateChange_Mask) == ET_StateChange_Mask);
+	if (hwc_data.read_statechange)
+		internal_print (
+				       DELAYED_WRITE,
+				       HWC_RW_PRINT_HEADER
+				     "can read state change notifications\n");
+	else
+		internal_print (
+				       DELAYED_WRITE,
+				       HWC_RW_PRINT_HEADER
+				 "can not read state change notifications\n");
+
+	hwc_data.read_nonprio
+	    = ((mask & ET_OpCmd_Mask) == ET_OpCmd_Mask);
+	if (hwc_data.read_nonprio)
+		internal_print (
+				       DELAYED_WRITE,
+				       HWC_RW_PRINT_HEADER
+				       "can read commands\n");
+
+	hwc_data.read_prio
+	    = ((mask & ET_PMsgCmd_Mask) == ET_PMsgCmd_Mask);
+	if (hwc_data.read_prio)
+		internal_print (
+				       DELAYED_WRITE,
+				       HWC_RW_PRINT_HEADER
+				       "can read priority commands\n");
+
+	if (hwc_data.read_prio || hwc_data.read_nonprio) {
+		return 0;
+	} else {
+		internal_print (
+				       DELAYED_WRITE,
+				       HWC_RW_PRINT_HEADER
+				     "can not read commands from operator\n");
+		return -1;
+	}
+}
+
+static int 
+eval_statechangebuf (statechangebuf_t * scbuf)
+{
+	int retval = 0;
+
+	internal_print (
+			       DELAYED_WRITE,
+			       HWC_RW_PRINT_HEADER
+			       "HWC state change detected\n");
+
+	if (scbuf->validity_hwc_active_facility_mask) {
+
+	}
+	if (scbuf->validity_hwc_receive_mask) {
+
+		if (scbuf->mask_length != 4) {
+#ifdef DUMP_HWC_INIT_ERROR
+			__asm__ ("LHI 1,0xe50\n\t"
+				 "LRA 2,0(%0)\n\t"
+				 "J .+0 \n\t"
+		      :
+		      :	 "a" (scbuf)
+		      :	 "1", "2");
+#endif
+		} else {
+
+			retval += eval_hwc_receive_mask
+			    (scbuf->hwc_receive_mask);
+		}
+	}
+	if (scbuf->validity_hwc_send_mask) {
+
+		if (scbuf->mask_length != 4) {
+#ifdef DUMP_HWC_INIT_ERROR
+			__asm__ ("LHI 1,0xe51\n\t"
+				 "LRA 2,0(%0)\n\t"
+				 "J .+0 \n\t"
+		      :
+		      :	 "a" (scbuf)
+		      :	 "1", "2");
+#endif
+		} else {
+
+			retval += eval_hwc_send_mask
+			    (scbuf->hwc_send_mask);
+		}
+	}
+	if (scbuf->validity_read_data_function_mask) {
+
+	}
+	return retval;
+}
+
 static int 
 process_evbufs (void *start, void *end)
 {
@@ -1490,17 +1653,17 @@
 			retval += eval_evbuf (evbuf_data, evbuf_end);
 			break;
 		case ET_StateChange:
-
-			retval = -ENOSYS;
+			retval += eval_statechangebuf
+			    ((statechangebuf_t *) evbuf);
 			break;
 		default:
-			printk (
-				       KERN_WARNING
-				       HWC_RW_PRINT_HEADER
-				       "unconditional read: "
-				       "unknown event buffer found, "
-				       "type 0x%x",
-				       evbuf->type);
+			internal_print (
+					       DELAYED_WRITE,
+					       HWC_RW_PRINT_HEADER
+					       "unconditional read: "
+					       "unknown event buffer found, "
+					       "type 0x%x",
+					       evbuf->type);
 			retval = -ENOSYS;
 		}
 		evbuf = (evbuf_t *) evbuf_end;
@@ -1515,11 +1678,14 @@
 	read_hwcb_t *hwcb = (read_hwcb_t *) hwc_data.page;
 	int retval;
 
+#if 0
+
 	if ((!hwc_data.read_prio) && (!hwc_data.read_nonprio))
 		return -EOPNOTSUPP;
 
 	if (hwc_data.current_servc)
 		return -EBUSY;
+#endif
 
 	memset (hwcb, 0x00, PAGE_SIZE);
 	memcpy (hwcb, &read_hwcb_template, sizeof (read_hwcb_t));
@@ -1529,8 +1695,8 @@
 #ifdef DUMP_HWC_READ_ERROR
 	if (condition_code == HWC_NOT_OPERATIONAL)
 		__asm__ ("LHI 1,0xe40\n\t"
-			 "L 2,0(0,%0)\n\t"
-			 "LRA 3,0(0,%1)\n\t"
+			 "L 2,0(%0)\n\t"
+			 "LRA 3,0(%1)\n\t"
 			 "J .+0 \n\t"
 	      :
 	      :	 "a" (&condition_code), "a" (hwc_data.page)
@@ -1564,8 +1730,8 @@
 	    (hwcb->response_code != 0x60F0) &&
 	    (hwcb->response_code != 0x62F0))
 		__asm__ ("LHI 1,0xe41\n\t"
-			 "LRA 2,0(0,%0)\n\t"
-			 "L 3,0(0,%1)\n\t"
+			 "LRA 2,0(%0)\n\t"
+			 "L 3,0(%1)\n\t"
 			 "J .+0\n\t"
 	      :
 	      :	 "a" (hwc_data.page), "a" (&(hwcb->response_code))
@@ -1625,26 +1791,21 @@
 		internal_print (
 				       IMMEDIATE_WRITE,
 				       HWC_RW_PRINT_HEADER
-			   "unconditional read: invalid function code - this "
-			 "must not occur in a correct driver, please contact "
-				       "author\n");
+			       "unconditional read: invalid function code\n");
 		return -EIO;
 
 	case 0x70F0:
 		internal_print (
 				       IMMEDIATE_WRITE,
 				       HWC_RW_PRINT_HEADER
-			  "unconditional read: invalid selection mask - this "
-			 "must not occur in a correct driver, please contact "
-				       "author\n");
+			      "unconditional read: invalid selection mask\n");
 		return -EIO;
 
 	case 0x0040:
 		internal_print (
 				       IMMEDIATE_WRITE,
 				       HWC_RW_PRINT_HEADER
-			    "unconditional read: HWC equipment check - don't "
-				       "know how to handle this case\n");
+				 "unconditional read: HWC equipment check\n");
 		return -EIO;
 
 	default:
@@ -1671,8 +1832,8 @@
 
 	if (condition_code == HWC_NOT_OPERATIONAL)
 		__asm__ ("LHI 1,0xe10\n\t"
-			 "L 2,0(0,%0)\n\t"
-			 "LRA 3,0(0,%1)\n\t"
+			 "L 2,0(%0)\n\t"
+			 "LRA 3,0(%1)\n\t"
 			 "J .+0\n\t"
 	      :
 	      :	 "a" (&condition_code), "a" (hwc_data.page)
@@ -1701,38 +1862,34 @@
 	init_hwcb_t *hwcb = (init_hwcb_t *) hwc_data.page;
 	int retval = 0;
 
-	if (hwcb->hwc_receive_mask & ET_Msg_Mask)
-		hwc_data.write_nonprio = 1;
-
-	if (hwcb->hwc_receive_mask & ET_PMsgCmd_Mask)
-		hwc_data.write_prio = 1;
-
-	if (hwcb->hwc_send_mask & ET_OpCmd_Mask) {
-		internal_print (DELAYED_WRITE,
-				HWC_RW_PRINT_HEADER
-				"capable of receipt of commands\n");
-		hwc_data.read_nonprio = 1;
-	}
-	if (hwcb->hwc_send_mask & ET_PMsgCmd_Mask) {
-		internal_print (DELAYED_WRITE,
-				HWC_RW_PRINT_HEADER
-				"capable of receipt of priority commands\n");
-		hwc_data.read_nonprio = 1;
-	}
-	if ((hwcb->response_code != 0x0020) ||
-	    (!hwc_data.write_nonprio) ||
-	    ((!hwc_data.read_nonprio) && (!hwc_data.read_prio)))
+	if (hwcb->response_code != 0x0020) {
 #ifdef DUMP_HWC_INIT_ERROR
 		__asm__ ("LHI 1,0xe11\n\t"
-			 "LRA 2,0(0,%0)\n\t"
-			 "L 3,0(0,%1)\n\t"
+			 "LRA 2,0(%0)\n\t"
+			 "L 3,0(%1)\n\t"
 			 "J .+0\n\t"
 	      :
 	      :	 "a" (hwcb), "a" (&(hwcb->response_code))
 	      :	 "1", "2", "3");
 #else
-		retval = -EIO;
+		retval = -1;
 #endif
+	} else {
+		if (hwcb->mask_length != 4) {
+#ifdef DUMP_HWC_INIT_ERROR
+			__asm__ ("LHI 1,0xe52\n\t"
+				 "LRA 2,0(%0)\n\t"
+				 "J .+0 \n\t"
+		      :
+		      :	 "a" (hwcb)
+		      :	 "1", "2");
+#endif
+		} else {
+			retval += eval_hwc_receive_mask
+			    (hwcb->hwc_receive_mask);
+			retval += eval_hwc_send_mask (hwcb->hwc_send_mask);
+		}
+	}
 
 	hwc_data.current_servc = 0;
 	hwc_data.current_hwcb = NULL;
@@ -1764,18 +1921,6 @@
 	} else
 		tmp.columns = ioctls->columns;
 
-	switch (ioctls->code) {
-	case CODE_EBCDIC:
-	case CODE_ASCII:
-		tmp.code = ioctls->code;
-		break;
-	default:
-		if (correct)
-			tmp.code = CODE_ASCII;
-		else
-			retval = -EINVAL;
-	}
-
 	tmp.final_nl = ioctls->final_nl;
 
 	if (ioctls->max_hwcb < 2) {
@@ -1915,7 +2060,7 @@
 			       HWC_RW_PRINT_HEADER
 			       "use %i bytes for buffering.\n",
 			       hwc_data.ioctls.kmem_hwcb * PAGE_SIZE);
-	for (i = 0; i < 500; i++) {
+	for (i = 0; i < 2000; i++) {
 		hwcb = (init_hwcb_t *) BUF_HWCB;
 		internal_print (
 				       DELAYED_WRITE,
@@ -1975,6 +2120,10 @@
 	} else {
 		spin_lock (&hwc_data.lock);
 
+		if (hwc_data.flags & HWC_PTIMER_RUNS) {
+			del_timer (&hwc_data.poll_timer);
+			hwc_data.flags &= ~HWC_PTIMER_RUNS;
+		}
 		if (!hwc_data.current_servc) {
 
 			unconditional_read_1 ();
@@ -2064,12 +2213,6 @@
 			goto fault;
 		break;
 
-	case TIOCHWCSCODE:
-		if (get_user (tmp.code, (ioctl_code_t *) arg))
-			goto fault;
-
-		break;
-
 	case TIOCHWCSNL:
 		if (get_user (tmp.final_nl, (ioctl_nl_t *) arg))
 			goto fault;
@@ -2126,12 +2269,6 @@
 	case TIOCHWCGCOLS:
 		if (put_user (tmp.columns, (ioctl_cols_t *) arg))
 			goto fault;
-		break;
-
-	case TIOCHWCGCODE:
-		if (put_user (tmp.code, (ioctl_code_t *) arg))
-			goto fault;
-
 		break;
 
 	case TIOCHWCGNL:
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/char/hwc_rw.h linux.19p18/drivers/s390/char/hwc_rw.h
--- linux.vanilla/drivers/s390/char/hwc_rw.h	Mon Dec 11 22:12:51 2000
+++ linux.19p18/drivers/s390/char/hwc_rw.h	Mon Feb 19 18:36:14 2001
@@ -26,7 +26,6 @@
 typedef unsigned short int ioctl_htab_t;
 typedef unsigned char ioctl_echo_t;
 typedef unsigned short int ioctl_cols_t;
-typedef unsigned char ioctl_code_t;
 typedef signed char ioctl_nl_t;
 typedef unsigned short int ioctl_obuf_t;
 typedef unsigned char ioctl_case_t;
@@ -37,7 +36,6 @@
 	ioctl_htab_t width_htab;
 	ioctl_echo_t echo;
 	ioctl_cols_t columns;
-	ioctl_code_t code;
 	ioctl_nl_t final_nl;
 	ioctl_obuf_t max_hwcb;
 	ioctl_obuf_t kmem_hwcb;
@@ -58,8 +56,6 @@
 
 #define TIOCHWCSCOLS	_IOW(HWC_IOCTL_LETTER, 2, _hwc_ioctls.columns)
 
-#define TIOCHWCSCODE	_IOW(HWC_IOCTL_LETTER, 3, _hwc_ioctls.code)
-
 #define TIOCHWCSNL	_IOW(HWC_IOCTL_LETTER, 4, _hwc_ioctls.final_nl)
 
 #define TIOCHWCSOBUF	_IOW(HWC_IOCTL_LETTER, 5, _hwc_ioctls.max_hwcb)
@@ -78,8 +74,6 @@
 
 #define TIOCHWCGCOLS	_IOR(HWC_IOCTL_LETTER, 12, _hwc_ioctls.columns)
 
-#define TIOCHWCGCODE	_IOR(HWC_IOCTL_LETTER, 13, _hwc_ioctls.code)
-
 #define TIOCHWCGNL	_IOR(HWC_IOCTL_LETTER, 14, _hwc_ioctls.final_nl)
 
 #define TIOCHWCGOBUF	_IOR(HWC_IOCTL_LETTER, 15, _hwc_ioctls.max_hwcb)
@@ -99,9 +93,6 @@
 #define TIOCHWCGMEASC  _IOR(HWC_IOCTL_LETTER, 22, _hwc_ioctls.measured_chars)
 
 #define TIOCHWCGMEASS	_IOR(HWC_IOCTL_LETTER, 23, _hwc_ioctls.measured_wcalls)
-
-#define CODE_ASCII              0x0
-#define CODE_EBCDIC             0x1
 
 #ifndef __HWC_RW_C__
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/char/hwc_tty.c linux.19p18/drivers/s390/char/hwc_tty.c
--- linux.vanilla/drivers/s390/char/hwc_tty.c	Mon Dec 11 22:12:51 2000
+++ linux.19p18/drivers/s390/char/hwc_tty.c	Tue Feb 27 16:30:13 2001
@@ -171,7 +171,9 @@
 
 	switch (cmd) {
 	case TIOCHWCTTYSINTRC:
-		count = strlen_user ((const char *) arg);
+		count = strnlen_user((const char *)arg, HWC_TTY_MAX_CNTL_SIZE);
+		if (!count)
+			return -EFAULT;
 		if (count > HWC_TTY_MAX_CNTL_SIZE)
 			return -EINVAL;
 		strncpy_from_user (hwc_tty_data.ioctl.intr_char,
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/idals.c linux.19p18/drivers/s390/idals.c
--- linux.vanilla/drivers/s390/idals.c	Mon Dec 11 22:12:51 2000
+++ linux.19p18/drivers/s390/idals.c	Mon Feb 19 18:33:37 2001
@@ -9,71 +9,36 @@
  */
 
 #include <linux/malloc.h>
+
 #include <asm/irq.h>
 #include <asm/idals.h>
-#include <asm/spinlock.h>
-
-#ifdef PRINTK_HEADER
-#undef PRINTK_HEADER
-#endif
-#define PRINTK_HEADER "idals:"
-
-/* a name template for the cache-names */
-static char idal_name_template[] = "idalcache-\0\0\0\0"; /* fill name with zeroes! */
-/* the cache's names */
-static char idal_cache_name[IDAL_NUMBER_CACHES][sizeof(idal_name_template)+1]; 
-/* the caches itself*/
-static kmem_cache_t *idal_cache[IDAL_NUMBER_CACHES]; 
 
-void
-free_idal ( ccw1_t *cp )
+#ifdef CONFIG_ARCH_S390X
+void 
+set_normalized_cda ( ccw1_t * cp, unsigned long address )
 {
+	int nridaws;
 	idaw_t *idal;
-	unsigned long upper2k,lower2k;
-	int nridaws,cacheind;
-	if ( cp -> flags & CCW_FLAG_IDA ) {
-		idal = cp -> cda;
-		lower2k = *idal & 0xfffffffffffff800;
-		upper2k = (*idal  + cp -> count - 1) & 0xfffffffffffff800;
-		nridaws = ((upper2k - lower2k) >> 11) + 1;
-		for ( cacheind = 0; (1 << cacheind) < nridaws ; cacheind ++ );
-		kmem_cache_free ( idal_cache[cacheind], idal );
-	}
-}
-
-int 
-idal_support_init ( void ) 
-{
-	int rc=0;
-	int cachind;
-	
-	for ( cachind = 0; cachind < IDAL_NUMBER_CACHES; cachind ++ ) {
-		int slabsize = 8 << cachind;
-		sprintf ( idal_cache_name[cachind], 
-			  "%s%d%c", idal_name_template, slabsize, 0);
-		idal_cache[cachind] = kmem_cache_create( idal_cache_name[cachind], 
-							 slabsize, 0,
-							 SLAB_HWCACHE_ALIGN | SLAB_DMA, 
-							 NULL, NULL );
-		if ( ! idal_cache [cachind] ) {
-			printk (KERN_WARNING PRINTK_HEADER "Allocation of IDAL cache failed\n");
-		}
-	}
-	
-	return rc;
-}
+        int count = cp->count;
 
-void idal_support_cleanup ( void )
-{
-	int cachind;
-
-	/* Shrink the caches, if available */
-	for ( cachind = 0; cachind < IDAL_NUMBER_CACHES; cachind ++ ) {
-		if ( idal_cache[cachind] ) {
-			if ( kmem_cache_shrink(idal_cache[cachind]) == 0 ) {
-				idal_cache[cachind] = NULL;
-			}
-		}
+	if (cp->flags & CCW_FLAG_IDA)
+		BUG();
+	if (((address + count) >> 31) == 0)
+		cp -> cda = address;
+		return;
+        nridaws = ((address & 2047L) + count + 2047L) >> 11;
+	idal = idal_alloc(nridaws);
+	if ( idal == NULL ) {
+		/* probably we should have a fallback here */
+		panic ("Cannot allocate memory for IDAL\n");
 	}
-
+	cp->flags |= CCW_FLAG_IDA;
+	cp->cda = (__u32)(unsigned long)(idaw_t *)idal;
+        do {
+		*idal++ = address;
+		address = (address & -2048L) + 2048;
+		nridaws --;
+        } while ( nridaws > 0 );
+	return;
 }
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/misc/Makefile linux.19p18/drivers/s390/misc/Makefile
--- linux.vanilla/drivers/s390/misc/Makefile	Sun Jun 11 21:44:15 2000
+++ linux.19p18/drivers/s390/misc/Makefile	Mon Feb 19 18:37:07 2001
@@ -2,7 +2,8 @@
 
 CFLAFS += 
 O_TARGET := s390-misc.o
-O_OBJS    :=         
+O_OBJS   :=         
+OX_OBJS  :=         
 M_OBJS   := 
 
 include $(TOPDIR)/Rules.make
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/net/Makefile linux.19p18/drivers/s390/net/Makefile
--- linux.vanilla/drivers/s390/net/Makefile	Mon Dec 11 22:12:51 2000
+++ linux.19p18/drivers/s390/net/Makefile	Mon Feb 19 18:37:07 2001
@@ -2,7 +2,8 @@
 
 CFLAFS += 
 O_TARGET := s390-net.o
-O_OBJS   := iucv.o
+O_OBJS   :=
+OX_OBJS  := iucv.o
 M_OBJS   :=
 
 ifeq ($(CONFIG_CTC),y)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/net/ctc.c linux.19p18/drivers/s390/net/ctc.c
--- linux.vanilla/drivers/s390/net/ctc.c	Mon Dec 11 22:12:51 2000
+++ linux.19p18/drivers/s390/net/ctc.c	Mon Feb 19 18:35:28 2001
@@ -1,5 +1,5 @@
 /*
- * $Id: ctc.c,v 1.25.2.5 2000/10/11 15:08:59 bird Exp $
+ * $Id: ctc.c,v 1.29 2001/01/25 22:28:21 uweigand Exp $
  *
  *  drivers/s390/net/ctc.c 
  *    CTC / ESCON network driver
@@ -22,12 +22,13 @@
  *    order or doesn't want to have automatic channel selection on, you can do 
  *    this with the "ctc= kernel keyword". 
  *
- *	 ctc=0,0xrrrr,0xwwww,ddddd
+ *	 ctc=prid,0xrrrr,0xwwww,ddddd
  *
  *     Where:
  *
- *	 "rrrr" is the read channel address
- *	 "wwww" is the write channel address
+ *       "prid" is the protocol id (must always be 0)
+ *	 "rrrr" is the read channel address (hexadecimal)
+ *	 "wwww" is the write channel address (hexadecimal)
  *	 "dddd" is the network device (ctc0 to ctc7 for a parallel channel, escon0
  *		to escon7 for ESCON channels).
  *
@@ -38,24 +39,39 @@
  *	 ctc=noauto
  * 
  * $Log: ctc.c,v $
- * Revision 1.25.2.5  2000/10/11 15:08:59  bird
- * ctc_tx(): Quick fix of possible underflow when calculating free block space
+ * Revision 1.29  2001/01/25 22:28:21  uweigand
+ * Minor 2.2.18 fix.
  *
- * Revision 1.25.2.4  2000/09/25 16:40:56  bird
- * Some more debug information
+ * Revision 1.28  2001/01/18 13:04:47  tonn
+ * upgrade to 2.2.18
  *
- * Revision 1.25.2.3  2000/09/20 13:28:19  bird
- * - ctc_open(): fixed bug
- * - ctc_release(): added timer for terminating in case of halt_io()-hang
- *
- * Revision 1.25.2.2  2000/09/20 09:48:27  bird
- * - ctc_open()/ctc_release(): use wait_event_interruptible()/wait_event() in
- *   instead of direct waiting on a wait queue
- * - ctc_buffer_swap(), ccw_check_return_code() and ccw_check_unit_check():
- *   print more debug information
+ * Revision 1.27  2000/10/26 16:16:07  bird
+ * Merged in changes from Revision 1.25.2.1 to Revision 1.25.2.6:
  *
- * Revision 1.25.2.1  2000/09/19 09:09:56  bird
- * Merged in changes from 1.25 to 1.26
+ *   Revision 1.25.2.6  2000/10/25 16:11:55  bird
+ *   Set size of empty block to BLOCK_HEADER_LENGTH (used to be 0)
+ *
+ *   Revision 1.25.2.5  2000/10/11 15:08:59  bird
+ *   ctc_tx(): Quick fix of possible underflow when calculating free block space
+ *
+ *   Revision 1.25.2.4  2000/09/25 16:40:56  bird
+ *   Some more debug information
+ *
+ *   Revision 1.25.2.3  2000/09/20 13:28:19  bird
+ *   - ctc_open(): fixed bug
+ *   - ctc_release(): added timer for terminating in case of halt_io()-hang
+ *
+ *   Revision 1.25.2.2  2000/09/20 09:48:27  bird
+ *   - ctc_open()/ctc_release(): use wait_event_interruptible()/wait_event() in
+ *     instead of direct waiting on a wait queue
+ *   - ctc_buffer_swap(), ccw_check_return_code() and ccw_check_unit_check():
+ *     print more debug information
+ *
+ *   Revision 1.25.2.1  2000/09/19 09:09:56  bird
+ *   Merged in changes from 1.25 to 1.26
+ *
+ * Revision 1.26  2000/09/15 12:29:32  weigand
+ * Some 2.3 diffs merged and other fixes.
  *
  * Revision 1.25  2000/09/08 09:22:11  bird
  * Proper cleanup and bugfixes in ctc_probe()
@@ -276,8 +292,6 @@
 typedef struct net_device  net_device;
 #else
 typedef struct device  net_device;
-typedef struct wait_queue* wait_queue_head_t;
-#define init_waitqueue_head(nothing)
 #endif
 
 struct adapterlist{ 
@@ -319,9 +333,9 @@
 #define CTC_BH_ACTIVE	    0	
 	__u8		    last_dstat;
 	__u8		    flag;
-#define CTC_WRITE      0x01      /* - Set if this is a write channel */
+#define CTC_WRITE	     0x01      /* - Set if this is a write channel */
 #define CTC_WAKEUP     0x02      /* - Set if this channel should wake up from waiting for an event */
-#define CTC_TIMER      0x80      /* - Set if timer made the wake_up  */ 
+#define CTC_TIMER	     0x80      /* - Set if timer made the wake_up  */ 
 };
 
 
@@ -352,6 +366,8 @@
 	__u16	      length;
 	struct packet data;
 };
+#define BLOCK_PAGES_POW 4    /* 2^4 = 16 pages per block (64k) */
+#define BLOCK_MAX_DATA 65535 /* maximal amount of data a block can hold */
 
 #if LINUX_VERSION_CODE>=0x02032D
 #define ctc_protect_busy(dev) \
@@ -485,7 +501,7 @@
  */
 static void print_banner(void) {
 	static int printed = 0;
-	char vbuf[] = "$Revision: 1.25.2.5 $";
+	char vbuf[] = "$Revision: 1.29 $";
 	char *version = vbuf;
 
 	if (printed)
@@ -763,12 +779,12 @@
 	else {	
 		p->next = NULL;	 
 		p->packets = 0;
-		p->block = (struct block *) __get_free_pages(GFP_KERNEL+GFP_DMA, 4);
+		p->block = (struct block *) __get_free_pages(GFP_KERNEL+GFP_DMA, BLOCK_PAGES_POW);
 		if (p->block == NULL) {
 			kfree(p);
 			return -ENOMEM;
 		}
-		p->block->length = 0; 
+		p->block->length = BLOCK_HEADER_LENGTH; /* empty block */
 	}
    
 	if (ctc->free_anchor == NULL) 
@@ -1109,7 +1125,7 @@
 
 } 
 
- 
+
 static void ctc_irq_handler (int irq, void *initparm, struct pt_regs *regs)
 {
 	int		  rc = 0;
@@ -1196,7 +1212,6 @@
 			wake_up(&ctc->wait);   /* wake up ctc_release */
 			return;
  
-
 		case CTC_START_HALT_IO:	 /* HALT_IO issued by ctc_open (start sequence) */
 #ifdef DEBUG
 		  printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__,  "CTC_START_HALT_IO");
@@ -1228,7 +1243,6 @@
 				return;
 			ctc->state =  CTC_START_SELECT;
  
-
 		case CTC_START_SELECT:
 #ifdef DEBUG
 		  printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__,  "CTC_START_SELECT");
@@ -1241,7 +1255,7 @@
 			}
 			if (!(ctc->flag & CTC_WRITE)) {
 				ctc->state = CTC_START_READ_TEST;
-				ctc->free_anchor->block->length = 0;	
+				ctc->free_anchor->block->length = BLOCK_HEADER_LENGTH; /* empty block */
 				ctc->ccw[1].cda	 = __pa(ctc->free_anchor->block);
 				parm = (__u32)(long) ctc;
 				rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
@@ -1253,7 +1267,7 @@
 			} else {
 				ctc->state = CTC_START_WRITE_TEST;
 				/* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 1 */
-				ctc->free_anchor->block->length = 0;	
+				ctc->free_anchor->block->length = BLOCK_HEADER_LENGTH; /* empty block */
 				ctc->ccw[1].count = BLOCK_HEADER_LENGTH; /* Transfer only length */
 				ctc->ccw[1].cda	 = __pa(ctc->free_anchor->block);
 				parm = (__u32)(long) ctc; 
@@ -1263,7 +1277,6 @@
 			}
 			return;
 
-
 		case CTC_START_READ_TEST:
 #ifdef DEBUG
 		  printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__,  "CTC_START_READ_TEST");
@@ -1300,8 +1313,7 @@
 			/* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 2 */
 			/* wake_up(&privptr->channel[WRITE].wait);*/  /* wake up ctc_open (WRITE) */
 
-
-		case CTC_START_READ:
+		case CTC_START_READ: 
 #ifdef DEBUG
 		  printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__,  "CTC_START_READ");
 #endif 
@@ -1333,7 +1345,7 @@
 			ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor, dev);
 
 			if (ctc->free_anchor != NULL) {
-				ctc->free_anchor->block->length = 0;
+				ctc->free_anchor->block->length = BLOCK_HEADER_LENGTH; /* empty block */
 				ctc->ccw[1].cda	 = __pa(ctc->free_anchor->block);
 				parm = (__u32)(long) ctc;
 				rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
@@ -1352,7 +1364,6 @@
 			}
 			return;
 
-
 		case CTC_START_WRITE_TEST:
 #ifdef DEBUG
 		  printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__,  "CTC_START_WRITE_TEST");
@@ -1378,7 +1389,6 @@
 			wake_up(&ctc->wait);  /* wake up ctc_open (WRITE) */
 			return;
  
-
 		case CTC_START_WRITE:
 #ifdef DEBUG
 		  printk(KERN_DEBUG "%s: %s(): entering state %s\n", dev->name, __FUNCTION__,  "CTC_START_WRITE");
@@ -1394,7 +1404,7 @@
 				privptr->stats.tx_packets += ctc->proc_anchor->packets;
 			} 
 
-			ctc->proc_anchor->block->length = 0;
+			ctc->proc_anchor->block->length = BLOCK_HEADER_LENGTH; /* empty block */
 			ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor, dev);
 			ctc_clearbit_busy(TB_NOBUFFER, dev);	 
 			if (ctc->proc_anchor != NULL) {	 
@@ -1416,7 +1426,7 @@
 							 "irq=%d, ctc=0x%p, dev=0x%p \n", irq, ctc, privptr);
 				return;
 			}
-			if (ctc->free_anchor->block->length != 0) {
+			if (ctc->free_anchor->block->length != BLOCK_HEADER_LENGTH) { /* non-empty block */
 				if (ctc_test_and_setbit_busy(TB_TX,dev) == 0) {	    
 				       /* set transmission to busy */
 					ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor, dev);
@@ -1470,15 +1480,17 @@
 
 	while (ctc->proc_anchor != NULL) {
 		block = ctc->proc_anchor->block;
-		if (block->length < BLOCK_HEADER_LENGTH) {
-			if(block->length == 0 && !ctc->initial_block_received)
-				ctc->initial_block_received = 1;
-			else
+
+		if ((block->length < BLOCK_HEADER_LENGTH)
+		    || (block->length == BLOCK_HEADER_LENGTH && ctc->initial_block_received)) {
 				printk(KERN_INFO "%s: %s(): discarding block at 0x%p: "
-				       "block length=%d<%d=block header length\n",
+					 "block length=%d<=%d=block header length\n",
 				       dev->name, __FUNCTION__, block, block->length, BLOCK_HEADER_LENGTH);
 		}
-		else {
+		else if(block->length == BLOCK_HEADER_LENGTH && !ctc->initial_block_received) {
+			ctc->initial_block_received = 1;
+		}
+		else { /* there is valid data in the buffer */
 			lp = &block->data;
 			while ((__u8 *) lp < (__u8 *) block + block->length) {
 				if(lp->length < PACKET_HEADER_LENGTH) {
@@ -1559,6 +1571,7 @@
 	       dev->name, ctc->state);
 #endif	
 	s390irq_spin_lock_irqsave(ctc->irq, saveflags);
+
 	if (ctc->state != CTC_STOP) {
 		if (!ctc->free_anchor) {
 			s390irq_spin_unlock_irqrestore(ctc->irq, saveflags);
@@ -1568,7 +1581,7 @@
 			return;
 		}
 
-		ctc->free_anchor->block->length = 0;
+		ctc->free_anchor->block->length = BLOCK_HEADER_LENGTH; /* empty block */
 		ctc->ccw[1].cda	 = __pa(ctc->free_anchor->block);
 		parm = (__u32)(long) ctc; 
 		rc = do_IO(ctc->irq, &ctc->ccw[0], parm, 0xff, flags);
@@ -1636,7 +1649,6 @@
 	struct ctc_priv	   *privptr;
 	struct timer_list  timer;
 
-
 	ctc_set_busy(dev);
 
 	privptr = (struct ctc_priv *) (dev->priv);
@@ -1698,13 +1710,13 @@
 		rc = halt_IO(privptr->channel[i].irq, parm, flags);
 		s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags);
 
-		wait_rc = wait_event_interruptible(privptr->channel[i].wait, privptr->channel[i].flag & CTC_WAKEUP);
-
-		del_timer(&timer);
-
 		if(rc != 0)
 			ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]");
 
+		wait_rc = wait_event_interruptible(privptr->channel[i].wait, privptr->channel[i].flag & CTC_WAKEUP);
+
+			del_timer(&timer);
+	
 		if (wait_rc == -ERESTARTSYS) { /* wait_event_interruptible() was terminated by a signal */
 			for (ii=0; ii<=i; ii++) {
 
@@ -1720,7 +1732,7 @@
 			return -ERESTARTSYS;
 		}
 	}
-	
+
 	if ((((privptr->channel[READ].last_dstat | privptr->channel[WRITE].last_dstat) & 
 	       ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) ||
 	    (((privptr->channel[READ].flag | privptr->channel[WRITE].flag) & CTC_TIMER) != 0x00)) {
@@ -1783,7 +1795,7 @@
 	ctc_setbit_busy(TB_STOP,dev);	 
 	ctc_unprotect_busy_irqrestore(dev, saveflags);
 
-	for (i = 0; i < 2;  i++) {
+	for (i = 0; i < 2;  i++) {		  
 		privptr->channel[i].flag &= ~(CTC_WAKEUP | CTC_TIMER);
 		init_timer(&timer);
 		timer.function = ctc_timer; 
@@ -1805,7 +1817,7 @@
 		if (rc != 0) {
 			ccw_check_return_code(dev, rc, __FUNCTION__ "()[1]");
 		}
-
+		 
 		if(privptr->channel[i].flag & CTC_TIMER)
 		{
 			printk(KERN_WARNING "%s: %s(): timeout during halt_io()\n",
@@ -1874,7 +1886,7 @@
 		goto Done;
 	} 
 
-	if (privptr->channel[WRITE].free_anchor->block->length + BLOCK_HEADER_LENGTH + PACKET_HEADER_LENGTH + skb->len > 65535) {
+	if (privptr->channel[WRITE].free_anchor->block->length + PACKET_HEADER_LENGTH + skb->len > BLOCK_MAX_DATA) {
 #ifdef DEBUG
 		printk(KERN_DEBUG "%s: early swap\n", dev->name);
 #endif
@@ -1887,15 +1899,14 @@
 		}
 	}
 	
-	if (privptr->channel[WRITE].free_anchor->block->length == 0) {
-		privptr->channel[WRITE].free_anchor->block->length = BLOCK_HEADER_LENGTH; 
+	if (privptr->channel[WRITE].free_anchor->block->length == BLOCK_HEADER_LENGTH) { /* empty block */
 		privptr->channel[WRITE].free_anchor->packets = 0;
 	} 
 
 
 	(__u8 *)lp = (__u8 *) (privptr->channel[WRITE].free_anchor->block) + privptr->channel[WRITE].free_anchor->block->length;
-	privptr->channel[WRITE].free_anchor->block->length += skb->len + PACKET_HEADER_LENGTH;
-	lp->length = skb->len + PACKET_HEADER_LENGTH; 
+	privptr->channel[WRITE].free_anchor->block->length += PACKET_HEADER_LENGTH + skb->len;
+	lp->length = PACKET_HEADER_LENGTH + skb->len; 
 	lp->type = 0x0800; 
 	lp->unused = 0;
 	memcpy(&lp->data, skb->data, skb->len); 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/net/iucv.c linux.19p18/drivers/s390/net/iucv.c
--- linux.vanilla/drivers/s390/net/iucv.c	Mon Dec 11 22:12:52 2000
+++ linux.19p18/drivers/s390/net/iucv.c	Mon Feb 19 18:37:07 2001
@@ -9,6 +9,8 @@
  *               Alan Altmark (Alan_Altmark@us.ibm.com)
  */
 
+#include <linux/module.h>
+#include <linux/config.h>
 #include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/malloc.h>
@@ -28,8 +30,6 @@
 //#define DEBUG         /* Turns Printk's on                         */
 //#define DEBUG2        /* This prints the parameter list before and */
 		      /* after the b2f0 call to cp                 */
-#define EXPORT_SYMTAB
-#include <linux/module.h>
 #undef NULL
 #define NULL 0
 #define ADDED_STOR 64		/* ADDITIONAL STORAGE FOR PATHID @'S */
@@ -1533,7 +1533,7 @@
 {
 	iucv_packet *pkt;
 	pkt = (iucv_packet *) kmalloc
-	    (sizeof (iucv_packet), GFP_KERNEL | GFP_ATOMIC);
+	    (sizeof (iucv_packet), GFP_ATOMIC);
 	if (pkt == NULL) {
 		printk (KERN_DEBUG "out of memory\n");
 		return;
@@ -1869,15 +1869,16 @@
 	new_handler->size = ADDED_STOR;
 	/* Allocate storage for pathid table */
 	new_handler->start = kmalloc (ADDED_STOR * sizeof (ulong), GFP_KERNEL);
-	memset (new_handler->start, 0, ADDED_STOR * sizeof (ulong));
 	if (new_handler->start == NULL) {
 #ifdef DEBUG
 		printk (KERN_DEBUG
 			"IUCV: returned NULL address for pathid table,"
 			" exiting\n");
 #endif
+		kfree(new_handler);
 		return NULL;
 	}
+	memset (new_handler->start, 0, ADDED_STOR * sizeof (ulong));
 	new_handler->end = (*new_handler).start + ADDED_STOR;
 	new_handler->next = 0;
 	new_handler->prev = 0;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/s390/net/netiucv.c linux.19p18/drivers/s390/net/netiucv.c
--- linux.vanilla/drivers/s390/net/netiucv.c	Mon Dec 11 22:12:52 2000
+++ linux.19p18/drivers/s390/net/netiucv.c	Mon Feb 19 18:37:07 2001
@@ -493,7 +493,7 @@
 	pr_debug ("message_pending: ID=%p Length=%u\n", (void *) mpi->ipmsgid,
 		  buffer_length);
 
-	buffer = kmalloc (buffer_length, GFP_KERNEL | GFP_DMA);
+	buffer = kmalloc (buffer_length, GFP_ATOMIC | GFP_DMA);
 	if (buffer == NULL) {
 		p->stats.rx_dropped++;
 		return;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sbus/audio/cs4215.h linux.19p18/drivers/sbus/audio/cs4215.h
--- linux.vanilla/drivers/sbus/audio/cs4215.h	Fri Apr 21 12:46:24 2000
+++ linux.19p18/drivers/sbus/audio/cs4215.h	Tue Jan  9 11:57:27 2001
@@ -105,7 +105,7 @@
 
 /* Time Slot 6, Output Setting  */
 #define CS4215_RO(v)	v	/* Right Output Attenuation 0x3f: -94.5 dB */
-#define CS4215_SE	(1<<6)	/* Line Out Enable */
+#define CS4215_SE	(1<<6)	/* Speaker Enable */
 #define CS4215_ADI	(1<<7)	/* A/D Data Invalid: Busy in calibration */
 
 /* Time Slot 7, Input Setting */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sbus/audio/dbri.c linux.19p18/drivers/sbus/audio/dbri.c
--- linux.vanilla/drivers/sbus/audio/dbri.c	Fri Apr 21 12:46:24 2000
+++ linux.19p18/drivers/sbus/audio/dbri.c	Tue Jan  9 11:57:27 2001
@@ -1382,8 +1382,13 @@
 
         dbri->perchip_info.play.channels = 1;
         dbri->perchip_info.play.precision = 8;
-        dbri->perchip_info.play.gain = 128;
+        dbri->perchip_info.play.gain = (AUDIO_MAX_GAIN * 7 / 10);  /* 70% */
         dbri->perchip_info.play.balance = AUDIO_MID_BALANCE;
+        dbri->perchip_info.play.port = dbri->perchip_info.play.avail_ports =
+                AUDIO_SPEAKER | AUDIO_HEADPHONE | AUDIO_LINE_OUT;
+        dbri->perchip_info.record.port = AUDIO_MICROPHONE;
+        dbri->perchip_info.record.avail_ports =
+                AUDIO_MICROPHONE | AUDIO_LINE_IN;
 }
 
 /* mmcodec_setgain(dbri, int muted)
@@ -1406,6 +1411,7 @@
         } else {
                 int left_gain = (dbri->perchip_info.play.gain / 4) % 64;
                 int right_gain = (dbri->perchip_info.play.gain / 4) % 64;
+		int outport = dbri->perchip_info.play.port;
 
                 if (dbri->perchip_info.play.balance < AUDIO_MID_BALANCE) {
                         right_gain *= dbri->perchip_info.play.balance;
@@ -1416,8 +1422,12 @@
                         left_gain /= AUDIO_MID_BALANCE;
                 }
 
-                dbri->mm.data[0] = CS4215_LE | CS4215_HE | (63 - left_gain);
-                dbri->mm.data[1] = CS4215_SE | (63 - right_gain);
+		dbri->mm.data[0] = (63 - left_gain);
+		if (outport & AUDIO_HEADPHONE) dbri->mm.data[0] |= CS4215_HE;
+		if (outport & AUDIO_LINE_OUT)  dbri->mm.data[0] |= CS4215_LE;
+		dbri->mm.data[1] = (63 - right_gain);
+		if (outport & AUDIO_SPEAKER)   dbri->mm.data[1] |= CS4215_SE;
+
         }
 
         xmit_fixed(dbri, 20, *(int *)dbri->mm.data);
@@ -1585,7 +1595,7 @@
                 dbri->mm.offset = chi_offsets[i];
                 if (mmcodec_setctrl(dbri) && dbri->mm.version != 0xff) {
                         dbri->perchip_info.play.balance = AUDIO_MID_BALANCE;
-                        dbri->perchip_info.play.gain = AUDIO_MAX_GAIN/2;
+                        dbri->perchip_info.play.gain = AUDIO_MAX_GAIN*7/10;
                         return 0;
                 }
         }
@@ -1936,32 +1946,52 @@
 
 static int dbri_set_output_port(struct sparcaudio_driver *drv, int port)
 {
-        return 0;
+	struct dbri *dbri = (struct dbri *) drv->private;
+
+	port &= dbri->perchip_info.play.avail_ports;
+	dbri->perchip_info.play.port = port;
+	mmcodec_setgain(dbri, 0);
+
+	return 0;
 }
 
 static int dbri_get_output_port(struct sparcaudio_driver *drv)
 {
-        return 0;
+	struct dbri *dbri = (struct dbri *) drv->private;
+
+	return dbri->perchip_info.play.port;
 }
 
 static int dbri_set_input_port(struct sparcaudio_driver *drv, int port)
 {
-        return 0;
+	struct dbri *dbri = (struct dbri *) drv->private;
+
+	port &= dbri->perchip_info.record.avail_ports;
+	dbri->perchip_info.record.port = port;
+	mmcodec_setgain(dbri, 0);
+
+	return 0;
 }
 
 static int dbri_get_input_port(struct sparcaudio_driver *drv)
 {
-        return 0;
+	struct dbri *dbri = (struct dbri *) drv->private;
+
+	return dbri->perchip_info.record.port;
 }
 
 static int dbri_get_output_ports(struct sparcaudio_driver *drv)
 {
-        return 0;
+	struct dbri *dbri = (struct dbri *) drv->private;
+
+	return dbri->perchip_info.play.avail_ports;
 }
 
 static int dbri_get_input_ports(struct sparcaudio_driver *drv)
 {
-        return 0;
+	struct dbri *dbri = (struct dbri *) drv->private;
+
+	return dbri->perchip_info.record.avail_ports;
 }
 
 /******************* sparcaudio midlevel - driver ID ********************/
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sbus/char/Makefile linux.19p18/drivers/sbus/char/Makefile
--- linux.vanilla/drivers/sbus/char/Makefile	Sat Sep  9 18:42:40 2000
+++ linux.19p18/drivers/sbus/char/Makefile	Wed Feb  7 09:45:38 2001
@@ -45,6 +45,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_WATCHDOG_CP1XXX),y)
+O_OBJS += cpwatchdog.o
+else
+  ifeq ($(CONFIG_WATCHDOG_CP1XXX),m)
+  M_OBJS += cpwatchdog.o
+  endif
+endif
+
 endif # eq($(CONFIG_PCI,y)
 
 ifeq ($(CONFIG_OBP_FLASH),y)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sbus/char/cpwatchdog.c linux.19p18/drivers/sbus/char/cpwatchdog.c
--- linux.vanilla/drivers/sbus/char/cpwatchdog.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/sbus/char/cpwatchdog.c	Wed Feb  7 09:45:38 2001
@@ -0,0 +1,846 @@
+/* cpwatchdog.c - driver implementation for hardware watchdog
+ * timers found on Sun Microsystems CP1400 and CP1500 boards.
+ *
+ * This device supports both the generic Linux watchdog 
+ * interface and Solaris-compatible ioctls as best it is
+ * able.
+ *
+ * NOTE: 	CP1400 systems appear to have a defective intr_mask
+ * 			register on the PLD, preventing the disabling of
+ * 			timer interrupts.  We use a timer to periodically 
+ * 			reset 'stopped' watchdogs on affected platforms.
+ *
+ * Copyright (c) 2000 Eric Brower (ebrower@usa.net)
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/major.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/timer.h>
+#include <asm/irq.h>
+#include <asm/ebus.h>
+#include <asm/oplib.h>
+#include <asm/uaccess.h>
+
+#include <asm/watchdog.h>
+
+#define WD_OBPNAME	"watchdog"
+#define WD_BADMODEL "SUNW,501-5336"
+#define WD_BTIMEOUT	(jiffies + (HZ * 1000))
+#define WD_BLIMIT	0xFFFF
+
+#define WD0_DEVNAME "watchdog0"
+#define WD1_DEVNAME "watchdog1"
+#define WD2_DEVNAME "watchdog2"
+
+#define WD0_MINOR	212
+#define WD1_MINOR	213	
+#define WD2_MINOR	214	
+
+#define WD_DEBUG
+
+/* Internal driver definitions
+ */
+#define WD0_ID			0		/* Watchdog0						*/
+#define WD1_ID			1		/* Watchdog1						*/
+#define WD2_ID			2		/* Watchdog2						*/
+#define WD_NUMDEVS		3		/* Device contains 3 timers			*/
+
+#define WD_INTR_OFF		0		/* Interrupt disable value			*/
+#define WD_INTR_ON		1		/* Interrupt enable value			*/
+
+#define WD_STAT_INIT	0x01	/* Watchdog timer is initialized	*/
+#define WD_STAT_BSTOP	0x02	/* Watchdog timer is brokenstopped	*/
+#define WD_STAT_SVCD	0x04	/* Watchdog interrupt occurred		*/
+
+/* Register value definitions
+ */
+#define WD0_INTR_MASK	0x01	/* Watchdog device interrupt masks	*/
+#define WD1_INTR_MASK	0x02
+#define WD2_INTR_MASK	0x04
+
+#define WD_S_RUNNING	0x01	/* Watchdog device status running	*/
+#define WD_S_EXPIRED	0x02	/* Watchdog device status expired	*/
+
+/* Sun uses Altera PLD EPF8820ATC144-4 
+ * providing three hardware watchdogs:
+ *
+ * 	1) RIC - sends an interrupt when triggered
+ * 	2) XIR - asserts XIR_B_RESET when triggered, resets CPU
+ * 	3) POR - asserts POR_B_RESET when triggered, resets CPU, backplane, board
+ *
+ *** Timer register block definition (struct wd_timer_regblk)
+ *
+ * dcntr and limit registers (halfword access):      
+ * -------------------
+ * | 15 | ...| 1 | 0 |
+ * -------------------
+ * |-  counter val  -|
+ * -------------------
+ * dcntr - 	Current 16-bit downcounter value.
+ * 			When downcounter reaches '0' watchdog expires.
+ * 			Reading this register resets downcounter with 'limit' value.
+ * limit - 	16-bit countdown value in 1/10th second increments.
+ * 			Writing this register begins countdown with input value.
+ * 			Reading from this register does not affect counter.
+ * NOTES:	After watchdog reset, dcntr and limit contain '1'
+ *
+ * status register (byte access):
+ * ---------------------------
+ * | 7 | ... | 2 |  1  |  0  |
+ * --------------+------------
+ * |-   UNUSED  -| EXP | RUN |
+ * ---------------------------
+ * status-	Bit 0 - Watchdog is running
+ * 			Bit 1 - Watchdog has expired
+ *
+ *** PLD register block definition (struct wd_pld_regblk)
+ *
+ * intr_mask register (byte access):
+ * ---------------------------------
+ * | 7 | ... | 3 |  2  |  1  |  0  |
+ * +-------------+------------------
+ * |-   UNUSED  -| WD3 | WD2 | WD1 |
+ * ---------------------------------
+ * WD3 -  1 == Interrupt disabled for watchdog 3
+ * WD2 -  1 == Interrupt disabled for watchdog 2
+ * WD1 -  1 == Interrupt disabled for watchdog 1
+ *
+ * pld_status register (byte access):
+ * UNKNOWN, MAGICAL MYSTERY REGISTER
+ *
+ */
+struct wd_timer_regblk {
+	volatile __u16	dcntr;		/* down counter		- hw	*/
+	volatile __u16	dcntr_pad;
+	volatile __u16	limit;		/* limit register	- hw	*/
+	volatile __u16	limit_pad;
+	volatile __u8	status;		/* status register	- b		*/
+	volatile __u8	status_pad;
+	volatile __u16	status_pad2;
+	volatile __u32	pad32;		/* yet more padding			*/
+};
+
+struct wd_pld_regblk {
+	volatile __u8	intr_mask;	/* interrupt mask	- b		*/
+	volatile __u8	intr_mask_pad;
+	volatile __u16	intr_mask_pad2;
+	volatile __u8	status;		/* device status	- b		*/
+	volatile __u8	status_pad;
+	volatile __u16	status_pad2;
+};
+
+struct wd_regblk {
+	volatile struct wd_timer_regblk		wd0_regs;
+	volatile struct wd_timer_regblk		wd1_regs;
+	volatile struct wd_timer_regblk		wd2_regs;
+	volatile struct wd_pld_regblk		pld_regs;
+};
+
+/* Individual timer structure 
+ */
+struct wd_timer {
+	__u16			timeout;
+	__u8			intr_mask;
+	unsigned char	runstatus;
+	volatile struct wd_timer_regblk* regs;
+};
+
+/* Device structure
+ */
+struct wd_device {
+	int				irq;
+	spinlock_t		lock;
+	unsigned char	isbaddoggie;	/* defective PLD */
+	unsigned char	opt_enable;
+	unsigned char	opt_reboot;
+	unsigned short	opt_timeout;
+	unsigned char	initialized;
+	struct wd_timer	watchdog[WD_NUMDEVS];
+	volatile struct	wd_regblk* regs;
+};
+
+static struct wd_device wd_dev = { 
+		0, SPIN_LOCK_UNLOCKED, 0, 0, 0, 0,
+};
+
+struct timer_list wd_timer;
+
+static int wd0_timeout = 0;
+static int wd1_timeout = 0;
+static int wd2_timeout = 0;
+
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+
+MODULE_PARM		(wd0_timeout, "i");
+MODULE_PARM_DESC(wd0_timeout, "Default watchdog0 timeout in 1/10secs");
+MODULE_PARM 	(wd1_timeout, "i");
+MODULE_PARM_DESC(wd1_timeout, "Default watchdog1 timeout in 1/10secs");
+MODULE_PARM 	(wd2_timeout, "i");
+MODULE_PARM_DESC(wd2_timeout, "Default watchdog2 timeout in 1/10secs");
+
+MODULE_AUTHOR
+	("Eric Brower <ebrower@usa.net>");
+MODULE_DESCRIPTION
+	("Hardware watchdog driver for Sun Microsystems CP1400/1500");
+MODULE_SUPPORTED_DEVICE
+	("watchdog");
+#endif /* ifdef MODULE */
+
+/* Forward declarations of internal methods
+ */
+void wd_dumpregs(void);
+void wd_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+void wd_toggleintr(struct wd_timer* pTimer, int enable);
+void wd_pingtimer(struct wd_timer* pTimer);
+void wd_starttimer(struct wd_timer* pTimer);
+void wd_resetbrokentimer(struct wd_timer* pTimer);
+void wd_stoptimer(struct wd_timer* pTimer);
+void wd_brokentimer(unsigned long data);
+int  wd_getstatus(struct wd_timer* pTimer);
+
+#define wd_writew(val, addr)	(addr = val)
+#define wd_writeb(val, addr)	(addr = val)
+#define wd_readw(addr)			(addr)
+#define wd_readb(addr)			(addr)
+
+/* CP1400s seem to have broken PLD implementations--
+ * the interrupt_mask register cannot be written, so
+ * no timer interrupts can be masked within the PLD.
+ */
+static inline int wd_isbroken(void)
+{
+	/* we could test this by read/write/read/restore
+	 * on the interrupt mask register only if OBP
+	 * 'watchdog-enable?' == FALSE, but it seems 
+	 * ubiquitous on CP1400s
+	 */
+	char val[32];
+	prom_getproperty(prom_root_node, "model", val, sizeof(val));
+	return((!strcmp(val, WD_BADMODEL)) ? 1 : 0);
+}
+		
+/* Retrieve watchdog-enable? option from OBP
+ * Returns 0 if false, 1 if true
+ */
+static inline int wd_opt_enable(void)
+{
+	int opt_node;
+
+	opt_node = prom_getchild(prom_root_node);
+	opt_node = prom_searchsiblings(opt_node, "options");
+	return((-1 == prom_getint(opt_node, "watchdog-enable?")) ? 0 : 1);
+}
+
+/* Retrieve watchdog-reboot? option from OBP
+ * Returns 0 if false, 1 if true
+ */
+static inline int wd_opt_reboot(void)
+{
+	int opt_node;
+
+	opt_node = prom_getchild(prom_root_node);
+	opt_node = prom_searchsiblings(opt_node, "options");
+	return((-1 == prom_getint(opt_node, "watchdog-reboot?")) ? 0 : 1);
+}
+
+/* Retrieve watchdog-timeout option from OBP
+ * Returns OBP value, or 0 if not located
+ */
+static inline int wd_opt_timeout(void)
+{
+	int opt_node;
+	char value[32];
+	char *p = value;
+
+	opt_node = prom_getchild(prom_root_node);
+	opt_node = prom_searchsiblings(opt_node, "options");
+	opt_node = prom_getproperty(opt_node, 
+								"watchdog-timeout", 
+								value, 
+								sizeof(value));
+	if(-1 != opt_node) {
+		/* atoi implementation */
+		for(opt_node = 0; /* nop */; p++) {
+			if(*p >= '0' && *p <= '9') {
+				opt_node = (10*opt_node)+(*p-'0');
+			}
+			else {
+				break;
+			}
+		}
+	}
+	return((-1 == opt_node) ? (0) : (opt_node)); 
+}
+
+static int wd_open(struct inode *inode, struct file *f)
+{
+	switch(MINOR(inode->i_rdev))
+	{
+		case WD0_MINOR:
+			f->private_data = &wd_dev.watchdog[WD0_ID];
+			break;
+		case WD1_MINOR:
+			f->private_data = &wd_dev.watchdog[WD1_ID];
+			break;
+		case WD2_MINOR:
+			f->private_data = &wd_dev.watchdog[WD2_ID];
+			break;
+		default:
+			return(-ENODEV);
+	}
+
+	/* Register IRQ on first open of device */
+	if(0 == wd_dev.initialized)
+	{	
+		if (request_irq(wd_dev.irq, 
+						&wd_interrupt, 
+						SA_SHIRQ,
+						WD_OBPNAME,
+						(void *)wd_dev.regs)) {
+			printk("%s: Cannot register IRQ %s\n", 
+				WD_OBPNAME, __irq_itoa(wd_dev.irq));
+			return(-EBUSY);
+		}
+		wd_dev.initialized = 1;
+	}
+
+	MOD_INC_USE_COUNT;
+	return(0);
+}
+
+static int wd_release(struct inode *inode, struct file *file)
+{
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static int wd_ioctl(struct inode *inode, struct file *file, 
+		     unsigned int cmd, unsigned long arg)
+{
+	int 	setopt 				= 0;
+	struct 	wd_timer* pTimer 	= (struct wd_timer*)file->private_data;
+	struct 	watchdog_info info 	= {
+		0,
+		0,
+		"Altera EPF8820ATC144-4"
+	};
+
+	if(NULL == pTimer) {
+		return(-EINVAL);
+	}
+
+	switch(cmd)
+	{
+		/* Generic Linux IOCTLs */
+		case WDIOC_GETSUPPORT:
+			if(copy_to_user((struct watchdog_info *)arg, 
+							(struct watchdog_info *)&info, 
+							sizeof(struct watchdog_info *))) {
+				return(-EFAULT);
+			}
+			break;
+		case WDIOC_KEEPALIVE:
+			wd_pingtimer(pTimer);
+			break;
+		case WDIOC_SETOPTIONS:
+			if(copy_from_user(&setopt, (void*) arg, sizeof(unsigned int))) {
+				return -EFAULT;
+			}
+			if(setopt & WDIOS_DISABLECARD) {
+				if(wd_dev.opt_enable) {
+					printk(
+						"%s: cannot disable watchdog in ENABLED mode\n",
+						WD_OBPNAME);
+					return(-EINVAL);
+				}
+				wd_stoptimer(pTimer);
+			}
+			else if(setopt & WDIOS_ENABLECARD) {
+				wd_starttimer(pTimer);
+			}
+			else {
+				return(-EINVAL);
+			}	
+			break;
+		/* Solaris-compatible IOCTLs */
+		case WIOCGSTAT:
+			setopt = wd_getstatus(pTimer);
+			if(copy_to_user((void*)arg, &setopt, sizeof(unsigned int))) {
+				return(-EFAULT);
+			}
+			break;
+		case WIOCSTART:
+			wd_starttimer(pTimer);
+			break;
+		case WIOCSTOP:
+			if(wd_dev.opt_enable) {
+				printk("%s: cannot disable watchdog in ENABLED mode\n",
+					WD_OBPNAME);
+				return(-EINVAL);
+			}
+			wd_stoptimer(pTimer);
+			break;
+		default:
+			return(-EINVAL);
+	}
+	return(0);
+}
+
+static ssize_t wd_write(	struct file 	*file, 
+							const char		*buf, 
+							size_t 			count, 
+							loff_t 			*ppos)
+{
+	struct wd_timer* pTimer = (struct wd_timer*)file->private_data;
+
+	if(NULL == pTimer) {
+		return(-EINVAL);
+	}
+
+	wd_pingtimer(pTimer);
+	return(count);
+}
+
+static ssize_t wd_read(struct file * file, char * buffer,
+		        size_t count, loff_t *ppos)
+{
+#ifdef WD_DEBUG
+	wd_dumpregs();
+	return(0);
+#else
+	return(-EINVAL);
+#endif /* ifdef WD_DEBUG */
+}
+
+void wd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	/* Only WD0 will interrupt-- others are NMI and we won't
+	 * see them here....
+	 */
+	spin_lock_irq(&wd_dev.lock);
+	if((unsigned long)wd_dev.regs == (unsigned long)dev_id)
+	{
+		wd_stoptimer(&wd_dev.watchdog[WD0_ID]);
+		wd_dev.watchdog[WD0_ID].runstatus |=  WD_STAT_SVCD;
+	}
+	spin_unlock_irq(&wd_dev.lock);
+	return;
+}
+
+static struct file_operations wd_fops = {
+	NULL,		/* lseek	*/
+	wd_read,
+	wd_write,
+	NULL,		/* readdir	*/
+	NULL,		/* select	*/
+	wd_ioctl,
+	NULL,		/* mmap		*/
+	wd_open,
+	NULL,		/* flush	*/
+	wd_release,
+	NULL,		/* fsync	*/
+	NULL,		/* fasync	*/
+	NULL,		/* chk media*/
+	NULL,		/* revalid	*/
+	NULL,		/* lock		*/
+};
+
+static struct miscdevice wd0_miscdev = { WD0_MINOR, WD0_DEVNAME, &wd_fops };
+static struct miscdevice wd1_miscdev = { WD1_MINOR, WD1_DEVNAME, &wd_fops };
+static struct miscdevice wd2_miscdev = { WD2_MINOR, WD2_DEVNAME, &wd_fops };
+
+void wd_dumpregs(void)
+{
+	/* Reading from downcounters initiates watchdog countdown--
+	 * Example is included below for illustration purposes.
+	 */
+	int i;
+	printk("%s: dumping register values\n", WD_OBPNAME);
+	for(i = WD0_ID; i < WD_NUMDEVS; ++i) {
+			/* printk("\t%s%i: dcntr  at 0x%lx: 0x%x\n", 
+			  	WD_OBPNAME,
+		 	 	i,
+			 	(unsigned long)(&wd_dev.watchdog[i].regs->dcntr), 
+				wd_readw(wd_dev.watchdog[i].regs->dcntr));
+			*/
+			printk("\t%s%i: limit  at 0x%lx: 0x%x\n", 
+				WD_OBPNAME,
+				i,
+				(unsigned long)(&wd_dev.watchdog[i].regs->limit), 
+				wd_readw(wd_dev.watchdog[i].regs->limit));
+			printk("\t%s%i: status at 0x%lx: 0x%x\n", 
+				WD_OBPNAME,
+				i,
+				(unsigned long)(&wd_dev.watchdog[i].regs->status), 
+				wd_readb(wd_dev.watchdog[i].regs->status));
+			printk("\t%s%i: driver status: 0x%x\n",
+				WD_OBPNAME,
+				i,
+				wd_getstatus(&wd_dev.watchdog[i]));
+	}
+	printk("\tintr_mask  at 0x%lx: 0x%x\n", 
+		(unsigned long)(&wd_dev.regs->pld_regs.intr_mask), 
+		wd_readb(wd_dev.regs->pld_regs.intr_mask));
+	printk("\tpld_status at 0x%lx: 0x%x\n", 
+		(unsigned long)(&wd_dev.regs->pld_regs.status), 
+		wd_readb(wd_dev.regs->pld_regs.status));
+}
+
+/* Enable or disable watchdog interrupts
+ * Because of the CP1400 defect this should only be
+ * called during initialzation or by wd_[start|stop]timer()
+ *
+ * pTimer 	- pointer to timer device, or NULL to indicate all timers 
+ * enable	- non-zero to enable interrupts, zero to disable
+ */
+void wd_toggleintr(struct wd_timer* pTimer, int enable)
+{
+	unsigned char curregs = wd_readb(wd_dev.regs->pld_regs.intr_mask);
+	unsigned char setregs = 
+		(NULL == pTimer) ? 
+			(WD0_INTR_MASK | WD1_INTR_MASK | WD2_INTR_MASK) : 
+			(pTimer->intr_mask);
+
+	(WD_INTR_ON == enable) ?
+		(curregs &= ~setregs):
+		(curregs |=  setregs);
+
+	wd_writeb(curregs, wd_dev.regs->pld_regs.intr_mask);
+	return;
+}
+
+/* Reset countdown timer with 'limit' value and continue countdown.
+ * This will not start a stopped timer.
+ *
+ * pTimer	- pointer to timer device
+ */
+void wd_pingtimer(struct wd_timer* pTimer)
+{
+	if(wd_readb(pTimer->regs->status) & WD_S_RUNNING) {
+		wd_readb(pTimer->regs->dcntr);
+	}
+}
+
+/* Stop a running watchdog timer-- the timer actually keeps
+ * running, but the interrupt is masked so that no action is
+ * taken upon expiration.
+ *
+ * pTimer	- pointer to timer device
+ */
+void wd_stoptimer(struct wd_timer* pTimer)
+{
+	if(wd_readb(pTimer->regs->status) & WD_S_RUNNING) {
+		wd_toggleintr(pTimer, WD_INTR_OFF);
+
+		if(wd_dev.isbaddoggie) {
+			pTimer->runstatus |= WD_STAT_BSTOP;
+			wd_brokentimer((unsigned long)&wd_dev);
+		}
+	}
+}
+
+/* Start a watchdog timer with the specified limit value
+ * If the watchdog is running, it will be restarted with
+ * the provided limit value.
+ *
+ * This function will enable interrupts on the specified
+ * watchdog.
+ *
+ * pTimer	- pointer to timer device
+ * limit	- limit (countdown) value in 1/10th seconds
+ */
+void wd_starttimer(struct wd_timer* pTimer)
+{
+	if(wd_dev.isbaddoggie) {
+		pTimer->runstatus &= ~WD_STAT_BSTOP;
+	}
+	pTimer->runstatus &= ~WD_STAT_SVCD;
+	wd_writew(pTimer->timeout, pTimer->regs->limit);
+	wd_toggleintr(pTimer, WD_INTR_ON);
+}
+
+/* Restarts timer with maximum limit value and
+ * does not unset 'brokenstop' value.
+ */
+void wd_resetbrokentimer(struct wd_timer* pTimer)
+{
+	wd_toggleintr(pTimer, WD_INTR_ON);
+	wd_writew(WD_BLIMIT, pTimer->regs->limit);
+}
+
+/* Timer device initialization helper.
+ * Returns 0 on success, other on failure
+ */
+int wd_inittimer(int whichdog)
+{
+	struct miscdevice 				*whichmisc;
+	volatile struct wd_timer_regblk	*whichregs;
+	char 							whichident[8];
+	int								whichmask;
+	__u16							whichlimit;
+
+	switch(whichdog)
+	{
+		case WD0_ID:
+			whichmisc = &wd0_miscdev;
+			strcpy(whichident, "RIC");
+			whichregs = &wd_dev.regs->wd0_regs;
+			whichmask = WD0_INTR_MASK;
+			whichlimit= (0 == wd0_timeout) 	? 
+						(wd_dev.opt_timeout): 
+						(wd0_timeout);
+			break;
+		case WD1_ID:
+			whichmisc = &wd1_miscdev;
+			strcpy(whichident, "XIR");
+			whichregs = &wd_dev.regs->wd1_regs;
+			whichmask = WD1_INTR_MASK;
+			whichlimit= (0 == wd1_timeout) 	? 
+						(wd_dev.opt_timeout): 
+						(wd1_timeout);
+			break;
+		case WD2_ID:
+			whichmisc = &wd2_miscdev;
+			strcpy(whichident, "POR");
+			whichregs = &wd_dev.regs->wd2_regs;
+			whichmask = WD2_INTR_MASK;
+			whichlimit= (0 == wd2_timeout) 	? 
+						(wd_dev.opt_timeout): 
+						(wd2_timeout);
+			break;
+		default:
+			printk("%s: %s: invalid watchdog id: %i\n",
+				WD_OBPNAME, __FUNCTION__, whichdog);
+			return(1);
+	}
+	if(0 != misc_register(whichmisc))
+	{
+		return(1);
+	}
+	wd_dev.watchdog[whichdog].regs			= whichregs;
+	wd_dev.watchdog[whichdog].timeout 		= whichlimit;
+	wd_dev.watchdog[whichdog].intr_mask		= whichmask;
+	wd_dev.watchdog[whichdog].runstatus 	&= ~WD_STAT_BSTOP;
+	wd_dev.watchdog[whichdog].runstatus 	|= WD_STAT_INIT;
+
+	printk("%s%i: %s hardware watchdog [%01i.%i sec] %s\n", 
+		WD_OBPNAME, 
+		whichdog, 
+		whichident, 
+		wd_dev.watchdog[whichdog].timeout / 10,
+		wd_dev.watchdog[whichdog].timeout % 10,
+		(0 != wd_dev.opt_enable) ? "in ENABLED mode" : "");
+	return(0);
+}
+
+/* Timer method called to reset stopped watchdogs--
+ * because of the PLD bug on CP1400, we cannot mask
+ * interrupts within the PLD so me must continually
+ * reset the timers ad infinitum.
+ */
+void wd_brokentimer(unsigned long data)
+{
+	struct wd_device* pDev = (struct wd_device*)data;
+	int id, tripped = 0;
+
+	/* kill a running timer instance, in case we
+	 * were called directly instead of by kernel timer
+	 */
+	if(timer_pending(&wd_timer)) {
+		del_timer(&wd_timer);
+	}
+
+	for(id = WD0_ID; id < WD_NUMDEVS; ++id) {
+		if(pDev->watchdog[id].runstatus & WD_STAT_BSTOP) {
+			++tripped;
+			wd_resetbrokentimer(&pDev->watchdog[id]);
+		}
+	}
+
+	if(tripped) {
+		/* there is at least one timer brokenstopped-- reschedule */
+		wd_timer.expires = WD_BTIMEOUT;
+		add_timer(&wd_timer);
+	}
+}
+
+int wd_getstatus(struct wd_timer* pTimer)
+{
+	unsigned char stat = wd_readb(pTimer->regs->status);
+	unsigned char intr = wd_readb(wd_dev.regs->pld_regs.intr_mask);
+	unsigned char ret  = WD_STOPPED;
+
+	/* determine STOPPED */
+	if(0 == stat ) { 
+		return(ret);
+	}
+	/* determine EXPIRED vs FREERUN vs RUNNING */
+	else if(WD_S_EXPIRED & stat) {
+		ret = WD_EXPIRED;
+	}
+	else if(WD_S_RUNNING & stat) {
+		if(intr & pTimer->intr_mask) {
+			ret = WD_FREERUN;
+		}
+		else {
+			/* Fudge WD_EXPIRED status for defective CP1400--
+			 * IF timer is running 
+			 * 	AND brokenstop is set 
+			 * 	AND an interrupt has been serviced
+			 * we are WD_EXPIRED.
+			 *
+			 * IF timer is running 
+			 * 	AND brokenstop is set 
+			 * 	AND no interrupt has been serviced
+			 * we are WD_FREERUN.
+			 */
+			if(wd_dev.isbaddoggie && (pTimer->runstatus & WD_STAT_BSTOP)) {
+				if(pTimer->runstatus & WD_STAT_SVCD) {
+					ret = WD_EXPIRED;
+				}
+				else {
+					/* we could as well pretend we are expired */
+					ret = WD_FREERUN;
+				}
+			}
+			else {
+				ret = WD_RUNNING;
+			}
+		}
+	}
+
+	/* determine SERVICED */
+	if(pTimer->runstatus & WD_STAT_SVCD) {
+		ret |= WD_SERVICED;
+	}
+
+	return(ret);
+}
+
+#ifdef MODULE
+int init_module(void)
+#else
+__initfunc(int wd_init(void))
+#endif
+{
+	int 	id;
+	struct 	linux_ebus *ebus = NULL;
+	struct 	linux_ebus_device *edev = NULL;
+
+	for_each_ebus(ebus) {
+		for_each_ebusdev(edev, ebus) {
+			if (!strcmp(edev->prom_name, WD_OBPNAME))
+				goto ebus_done;
+		}
+	}
+
+ebus_done:
+	if(!edev) {
+		printk("%s: unable to locate device\n", WD_OBPNAME);
+		return -ENODEV;
+	}
+
+	if(check_region(edev->base_address[0], sizeof(*wd_dev.regs)))
+	{
+		printk("%s: Unable to get region %lx, %d\n", 
+			__FUNCTION__, edev->base_address[0], (int)sizeof(*wd_dev.regs));
+	}
+
+	wd_dev.regs = 
+		(struct wd_regblk *)edev->base_address[0];
+	request_region(
+		(unsigned long)wd_dev.regs, sizeof(*wd_dev.regs), WD_OBPNAME);
+
+	if(NULL == wd_dev.regs) {
+		printk("%s: unable to map registers\n", WD_OBPNAME);
+		return(-ENODEV);
+	}
+
+	/* initialize device structure from OBP parameters */
+	wd_dev.irq 			= edev->irqs[0];
+	wd_dev.opt_enable	= wd_opt_enable();
+	wd_dev.opt_reboot	= wd_opt_reboot();
+	wd_dev.opt_timeout	= wd_opt_timeout();
+	wd_dev.isbaddoggie	= wd_isbroken();
+
+	/* disable all interrupts unless watchdog-enabled? == true */
+	if(! wd_dev.opt_enable) {
+		wd_toggleintr(NULL, WD_INTR_OFF);
+	}
+
+	/* register miscellaneous devices */
+	for(id = WD0_ID; id < WD_NUMDEVS; ++id) {
+		if(0 != wd_inittimer(id)) {
+			printk("%s%i: unable to initialize\n", WD_OBPNAME, id);
+		}
+	}
+
+	/* warn about possible defective PLD */
+	if(wd_dev.isbaddoggie) {
+		init_timer(&wd_timer);
+		wd_timer.function 	= wd_brokentimer;
+		wd_timer.data		= (unsigned long)&wd_dev;
+		wd_timer.expires	= WD_BTIMEOUT;
+
+		printk("%s: PLD defect workaround enabled for model %s\n",
+			WD_OBPNAME, WD_BADMODEL);
+	}
+	return(0);
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+	int id;
+
+	/* if 'watchdog-enable?' == TRUE, timers are not stopped 
+	 * when module is unloaded.  All brokenstopped timers will
+	 * also now eventually trip. 
+	 */
+	for(id = WD0_ID; id < WD_NUMDEVS; ++id) {
+		if(WD_S_RUNNING == wd_readb(wd_dev.watchdog[id].regs->status)) {
+			if(wd_dev.opt_enable) {
+				printk(KERN_WARNING "%s%i: timer not stopped at release\n",
+					WD_OBPNAME, id);
+			}
+			else {
+				wd_stoptimer(&wd_dev.watchdog[id]);
+				if(wd_dev.watchdog[id].runstatus & WD_STAT_BSTOP) {
+					wd_resetbrokentimer(&wd_dev.watchdog[id]);
+					printk(KERN_WARNING 
+							"%s%i: defect workaround disabled at release, "\
+							"timer expires in ~%01i sec\n",
+							WD_OBPNAME, id, 
+							wd_readw(wd_dev.watchdog[id].regs->limit) / 10);
+				}
+			}
+		}
+	}
+
+	if(wd_dev.isbaddoggie && timer_pending(&wd_timer)) {
+		del_timer(&wd_timer);
+	}
+	if(0 != (wd_dev.watchdog[WD0_ID].runstatus & WD_STAT_INIT)) {
+		misc_deregister(&wd0_miscdev);
+	}
+	if(0 != (wd_dev.watchdog[WD1_ID].runstatus & WD_STAT_INIT)) {
+		misc_deregister(&wd1_miscdev);
+	}
+	if(0 != (wd_dev.watchdog[WD2_ID].runstatus & WD_STAT_INIT)) {
+		misc_deregister(&wd2_miscdev);
+	}
+	if(0 != wd_dev.initialized) {
+		free_irq(wd_dev.irq, (void *)wd_dev.regs);
+	}
+	release_region((unsigned long)wd_dev.regs, sizeof(*wd_dev.regs));
+}
+#endif /* ifdef MODULE */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sbus/char/zs.c linux.19p18/drivers/sbus/char/zs.c
--- linux.vanilla/drivers/sbus/char/zs.c	Sun Jun 11 21:44:15 2000
+++ linux.19p18/drivers/sbus/char/zs.c	Tue Jan  9 11:57:27 2001
@@ -1,4 +1,4 @@
-/* $Id: zs.c,v 1.41.2.6 2000/04/17 05:46:05 davem Exp $
+/* $Id: zs.c,v 1.41.2.7 2001/01/03 08:07:04 ecd Exp $
  * zs.c: Zilog serial port driver for the Sparc.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -904,7 +904,6 @@
  */
 static void change_speed(struct sun_serial *info)
 {
-	unsigned short port;
 	unsigned cflag;
 	int	quot = 0;
 	int	i;
@@ -913,7 +912,7 @@
 	if (!info->tty || !info->tty->termios)
 		return;
 	cflag = info->tty->termios->c_cflag;
-	if (!(port = info->port))
+	if (!info->port)
 		return;
 	i = cflag & CBAUD;
 	if (cflag & CBAUDEX) {
@@ -1857,7 +1856,7 @@
 
 static void show_serial_version(void)
 {
-	char *revision = "$Revision: 1.41.2.6 $";
+	char *revision = "$Revision: 1.41.2.7 $";
 	char *version, *p;
 
 	version = strchr(revision, ' ');
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/3w-xxxx.c linux.19p18/drivers/scsi/3w-xxxx.c
--- linux.vanilla/drivers/scsi/3w-xxxx.c	Sat Sep  9 18:42:40 2000
+++ linux.19p18/drivers/scsi/3w-xxxx.c	Sat Mar  3 22:35:15 2001
@@ -3,8 +3,10 @@
 
    Written By: Adam Radford <linux@3ware.com>
    Modifications By: Joel Jacobson <linux@3ware.com>
+		     Arnaldo Carvalho de Melo <acme@conectiva.com.br>
 
-   Copyright (C) 1999-2000 3ware Inc.
+
+   Copyright (C) 1999-2001 3ware Inc.
 
    Kernel compatablity By: 	Andre Hedrick <andre@suse.com>
    Non-Copyright (C) 2000	Andre Hedrick <andre@suse.com>
@@ -64,6 +66,17 @@
                  Bug fix so hot spare drives don't show up.
    1.02.00.002 - Fix bug with tw_setfeature() call that caused oops on some
                  systems.
+   12/09/2000  - release previously allocated resources on failure at
+		 tw_allocate_memory (acme)
+   1.02.00.003 - Fix tw_interrupt() to report error to scsi layer when
+                 controller status is non-zero.
+                 Added handling of request_sense opcode.
+                 Fix possible null pointer dereference in
+                 tw_reset_device_extension()
+   1.02.00.004 - Add support for device id of 3ware 7000 series controllers.
+                 Make tw_setfeature() call with interrupts disabled.
+                 Register interrupt handler before enabling interrupts.
+                 Clear attention interrupt before draining aen queue. 
 */
 
 #include <linux/module.h>
@@ -115,7 +128,7 @@
 };
 
 /* Globals */
-char *tw_driver_version="1.02.00.002";
+char *tw_driver_version="1.02.00.004";
 TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
 int tw_device_extension_count = 0;
 
@@ -416,37 +429,29 @@
 /* This function will allocate memory and check if it is 16 d-word aligned */
 int tw_allocate_memory(TW_Device_Extension *tw_dev, int request_id, int size, int which)
 {
-	u32 *virt_addr;
+	u32 *virt_addr = kmalloc(size, GFP_ATOMIC);
 
 	dprintk(KERN_NOTICE "3w-xxxx: tw_allocate_memory()\n");
 
+	if (!virt_addr) {
+		printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): kmalloc() failed.\n");
+		return 1;
+	}
+
+	if ((u32)virt_addr % TW_ALIGNMENT) {
+		kfree(virt_addr);
+		printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): Found unaligned address.\n");
+		return 1;
+	}
+
 	if (which == 0) {
-		/* Allocate command packet memory */
-		virt_addr = kmalloc(size, GFP_ATOMIC);
-		if (virt_addr == NULL) {
-			printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): kmalloc() failed.\n");
-			return 1;
-		}
-		if ((u32)virt_addr % TW_ALIGNMENT) {
-			printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): Found unaligned address.\n");
-			return 1;
-		}
 		tw_dev->command_packet_virtual_address[request_id] = virt_addr;
 		tw_dev->command_packet_physical_address[request_id] = 
-		virt_to_bus(virt_addr);
+			virt_to_bus(virt_addr);
 	} else {
-		/* Allocate generic buffer */
-		virt_addr = kmalloc(size, GFP_ATOMIC);
-		if (virt_addr == NULL) {
-			printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): kmalloc() failed.\n");
-			return 1;
-		}
-		if ((u32)virt_addr % TW_ALIGNMENT) {
-			printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): Found unaligned address.\n");
-			return 1;
-		}
 		tw_dev->alignment_virtual_address[request_id] = virt_addr;
-		tw_dev->alignment_physical_address[request_id] = virt_to_bus(virt_addr);
+		tw_dev->alignment_physical_address[request_id] =
+			virt_to_bus(virt_addr);
 	}
 	return 0;
 } /* End tw_allocate_memory() */
@@ -593,173 +598,178 @@
 	struct pci_dev *tw_pci_dev = pci_devices;
 	u32 status_reg_value;
 	unsigned char c = 1;
+	int i;
+	u16 device[TW_NUMDEVICES] = { TW_DEVICE_ID, TW_DEVICE_ID2 };
 
 	dprintk(KERN_NOTICE "3w-xxxx: tw_findcards()\n");
-	while ((tw_pci_dev = pci_find_device(TW_VENDOR_ID, TW_DEVICE_ID, tw_pci_dev))) {
-		/* Prepare temporary device extension */
-		tw_dev=(TW_Device_Extension *)kmalloc(sizeof(TW_Device_Extension), GFP_ATOMIC);
-		if (tw_dev == NULL) {
-			printk(KERN_WARNING "3w-xxxx: tw_findcards(): kmalloc() failed for card %d.\n", numcards);
-			continue;
-		}
-		memset(tw_dev, 0, sizeof(TW_Device_Extension));
-
-		error = tw_initialize_device_extension(tw_dev);
-		if (error) {
-			printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize device extension for card %d.\n", numcards);
-			tw_free_device_extension(tw_dev);
-			kfree(tw_dev);
-			continue;
-		}
-
-		/* Calculate the cards register addresses */
-		tw_dev->registers.base_addr = tw_pci_dev->base_address[0];
-		tw_dev->registers.control_reg_addr = (tw_pci_dev->base_address[0] & ~15);
-		tw_dev->registers.status_reg_addr = ((tw_pci_dev->base_address[0] & ~15) + 0x4);
-		tw_dev->registers.command_que_addr = ((tw_pci_dev->base_address[0] & ~15) + 0x8);
-		tw_dev->registers.response_que_addr = ((tw_pci_dev->base_address[0] & ~15) + 0xC);
-		/* Save pci_dev struct to device extension */
-		tw_dev->tw_pci_dev = tw_pci_dev;
-
-		/* Poll status register for 60 secs for 'Controller Ready' flag */
-		if (tw_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY, 60)) {
-			printk(KERN_WARNING "3w-xxxx: tw_findcards(): Microcontroller not ready for card %d.\n", numcards);
-			tw_free_device_extension(tw_dev);
-			kfree(tw_dev);
-			continue;
-		}
-
-		/* Disable interrupts on the card */
-		tw_disable_interrupts(tw_dev);
-
-		while (tries < TW_MAX_RESET_TRIES) {
-			/* Do soft reset */
-			tw_soft_reset(tw_dev);
-
-			error = tw_aen_drain_queue(tw_dev);
+	
+	for (i=0;i<TW_NUMDEVICES;i++) {
+		while ((tw_pci_dev = pci_find_device(TW_VENDOR_ID, device[i], tw_pci_dev))) {
+			/* Prepare temporary device extension */
+			tw_dev=(TW_Device_Extension *)kmalloc(sizeof(TW_Device_Extension), GFP_ATOMIC);
+			if (tw_dev == NULL) {
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): kmalloc() failed for card %d.\n", numcards);
+				continue;
+			}
+			memset(tw_dev, 0, sizeof(TW_Device_Extension));
+			
+			error = tw_initialize_device_extension(tw_dev);
 			if (error) {
-				printk(KERN_WARNING "3w-xxxx: tw_findcards(): No attention interrupt for card %d.\n", numcards);
-				tries++;
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize device extension for card %d.\n", numcards);
+				tw_free_device_extension(tw_dev);
+				kfree(tw_dev);
 				continue;
 			}
-
-			/* Check for controller errors */
-			if (tw_check_errors(tw_dev)) {
-				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller errors found, soft resetting card %d.\n", numcards);
-				tries++;
+			
+			/* Calculate the cards register addresses */
+			tw_dev->registers.base_addr = tw_pci_dev->base_address[0];
+			tw_dev->registers.control_reg_addr = (tw_pci_dev->base_address[0] & ~15);
+			tw_dev->registers.status_reg_addr = ((tw_pci_dev->base_address[0] & ~15) + 0x4);
+			tw_dev->registers.command_que_addr = ((tw_pci_dev->base_address[0] & ~15) + 0x8);
+			tw_dev->registers.response_que_addr = ((tw_pci_dev->base_address[0] & ~15) + 0xC);
+			/* Save pci_dev struct to device extension */
+			tw_dev->tw_pci_dev = tw_pci_dev;
+			
+			/* Poll status register for 60 secs for 'Controller Ready' flag */
+			if (tw_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY, 60)) {
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Microcontroller not ready for card %d.\n", numcards);
+				tw_free_device_extension(tw_dev);
+				kfree(tw_dev);
 				continue;
 			}
-
-			/* Empty the response queue */
-			error = tw_empty_response_que(tw_dev);
+			
+			/* Disable interrupts on the card */
+			tw_disable_interrupts(tw_dev);
+			
+			while (tries < TW_MAX_RESET_TRIES) {
+				/* Do soft reset */
+				tw_soft_reset(tw_dev);
+				
+				error = tw_aen_drain_queue(tw_dev);
+				if (error) {
+					printk(KERN_WARNING "3w-xxxx: tw_findcards(): No attention interrupt for card %d.\n", numcards);
+					tries++;
+					continue;
+				}
+				
+				/* Check for controller errors */
+				if (tw_check_errors(tw_dev)) {
+					printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller errors found, soft resetting card %d.\n", numcards);
+					tries++;
+					continue;
+				}
+				
+				/* Empty the response queue */
+				error = tw_empty_response_que(tw_dev);
+				if (error) {
+					printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't empty response queue for card %d.\n", numcards);
+					tries++;
+					continue;
+				}
+				
+				/* Now the controller is in a good state */
+				break;
+			}
+			
+			if (tries >= TW_MAX_RESET_TRIES) {
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller error or no attention interrupt: giving up for card %d.\n", numcards);
+				tw_free_device_extension(tw_dev);
+				kfree(tw_dev);
+				continue;
+			}
+			
+			/* Make sure that io region isn't already taken */
+			if (check_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE)) {
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't get io range 0x%lx-0x%lx for card %d.\n", 
+				       (tw_dev->tw_pci_dev->base_address[0]), 
+				       (tw_dev->tw_pci_dev->base_address[0]) + 
+				       TW_IO_ADDRESS_RANGE, numcards);
+				tw_free_device_extension(tw_dev);
+				kfree(tw_dev);
+				continue;
+			}
+			
+			/* Reserve the io address space */
+			request_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE, TW_DEVICE_NAME);
+			error = tw_initialize_units(tw_dev);
 			if (error) {
-				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't empty response queue for card %d.\n", numcards);
-				tries++;
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize units for card %d.\n", numcards);
+				release_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE);
+				tw_free_device_extension(tw_dev);
+				kfree(tw_dev);
 				continue;
 			}
-
-			/* Now the controller is in a good state */
-			break;
-		}
-
-		if (tries >= TW_MAX_RESET_TRIES) {
-			printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller error or no attention interrupt: giving up for card %d.\n", numcards);
-			tw_free_device_extension(tw_dev);
-			kfree(tw_dev);
-			continue;
-		}
-
-		/* Make sure that io region isn't already taken */
-		if (check_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE)) {
-			printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't get io range 0x%lx-0x%lx for card %d.\n", 
-				(tw_dev->tw_pci_dev->base_address[0]), 
-				(tw_dev->tw_pci_dev->base_address[0]) + 
-				TW_IO_ADDRESS_RANGE, numcards);
-			tw_free_device_extension(tw_dev);
-			kfree(tw_dev);
-			continue;
-		}
-    
-		/* Reserve the io address space */
-		request_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE, TW_DEVICE_NAME);
-		error = tw_initialize_units(tw_dev);
-		if (error) {
-			printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize units for card %d.\n", numcards);
-			release_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE);
-			tw_free_device_extension(tw_dev);
-			kfree(tw_dev);
-			continue;
-		}
-
-		error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS);
-		if (error) {
-			printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initconnection for card %d.\n", numcards);
-			release_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE);
-			tw_free_device_extension(tw_dev);
-			kfree(tw_dev);
-			continue;
-		}
-
-		/* Calculate max cmds per lun */
-		if (tw_dev->num_units > 0)
-			tw_host->cmd_per_lun = (TW_Q_LENGTH-2)/tw_dev->num_units;
-
-		/* Register the card with the kernel SCSI layer */
-		host = scsi_register(tw_host, sizeof(TW_Device_Extension));
-		
-		/* FIXME - check for NULL */
-
-		status_reg_value = inl(tw_dev->registers.status_reg_addr);
-
-		dprintk(KERN_NOTICE "scsi%d : Found a 3ware Storage Controller at 0x%x, IRQ: %d P-chip: %d.%d\n", host->host_no,
+			
+			error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS);
+			if (error) {
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initconnection for card %d.\n", numcards);
+				release_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE);
+				tw_free_device_extension(tw_dev);
+				kfree(tw_dev);
+				continue;
+			}
+			
+			/* Calculate max cmds per lun */
+			if (tw_dev->num_units > 0)
+				tw_host->cmd_per_lun = (TW_Q_LENGTH-2)/tw_dev->num_units;
+			
+			/* Register the card with the kernel SCSI layer */
+			host = scsi_register(tw_host, sizeof(TW_Device_Extension));
+			
+			/* FIXME - check for NULL */
+			
+			status_reg_value = inl(tw_dev->registers.status_reg_addr);
+			
+			dprintk(KERN_NOTICE "scsi%d : Found a 3ware Storage Controller at 0x%x, IRQ: %d P-chip: %d.%d\n", host->host_no,
 				(u32)(tw_pci_dev->base_address[0]), tw_pci_dev->irq, 
 				(status_reg_value & TW_STATUS_MAJOR_VERSION_MASK) >> 28, 
 				(status_reg_value & TW_STATUS_MINOR_VERSION_MASK) >> 24);
+			
+			if (host->hostdata) {
+				tw_dev2 = (TW_Device_Extension *)host->hostdata;
+				memcpy(tw_dev2, tw_dev, sizeof(TW_Device_Extension));
+				tw_device_extension_list[tw_device_extension_count] = tw_dev2;
+				numcards++;
+				tw_device_extension_count = numcards;
+				tw_dev2->host = host;
+			} else { 
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Bad scsi host data for card %d.\n", numcards-1);
+				scsi_unregister(host);
+				release_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE);
+				tw_free_device_extension(tw_dev);
+				kfree(tw_dev);
+				continue;
+			}
+			
+			/* Tell the firmware we support shutdown notification*/
+			tw_setfeature(tw_dev2, 2, 1, &c);
+			
+			/* Now setup the interrupt handler */
+			error = tw_setup_irq(tw_dev2);
+			if (error) {
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Error requesting irq for card %d.\n", numcards-1);
+				scsi_unregister(host);
+				release_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE);
+				
+				tw_free_device_extension(tw_dev);
+				kfree(tw_dev);
+				numcards--;
+				continue;
+			}
 
-		if (host->hostdata) {
-			tw_dev2 = (TW_Device_Extension *)host->hostdata;
-			memcpy(tw_dev2, tw_dev, sizeof(TW_Device_Extension));
-			tw_device_extension_list[tw_device_extension_count] = tw_dev2;
-			numcards++;
-			tw_device_extension_count = numcards;
-			tw_dev2->host = host;
-		} else { 
-			printk(KERN_WARNING "3w-xxxx: tw_findcards(): Bad scsi host data for card %d.\n", numcards-1);
-			scsi_unregister(host);
-			release_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE);
-			tw_free_device_extension(tw_dev);
-			kfree(tw_dev);
-			continue;
-		}
-    
-		/* Re-enable interrupts on the card */
-		tw_enable_interrupts(tw_dev2);
-
-		/* Now setup the interrupt handler */
-		error = tw_setup_irq(tw_dev2);
-		if (error) {
-			printk(KERN_WARNING "3w-xxxx: tw_findcards(): Error requesting irq for card %d.\n", numcards-1);
-			scsi_unregister(host);
-			release_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE);
-
-			tw_free_device_extension(tw_dev);
-			kfree(tw_dev);
-			numcards--;
-			continue;
+			/* Re-enable interrupts on the card */
+			tw_enable_interrupts(tw_dev2);
+			
+			/* Free the temporary device extension */
+			if (tw_dev)
+				kfree(tw_dev);
 		}
-
-		/* Free the temporary device extension */
-		if (tw_dev)
-			kfree(tw_dev);
-		/* Tell the firmware we support shutdown notification*/
-		tw_setfeature(tw_dev2, 2, 1, &c);
 	}
-
 	if (numcards == 0) 
 		printk(KERN_WARNING "3w-xxxx: tw_findcards(): No cards found.\n");
 	else
-	  register_reboot_notifier(&tw_notifier);
-
+		register_reboot_notifier(&tw_notifier);
+	
 	return numcards;
 } /* End tw_findcards() */
 
@@ -1090,15 +1100,14 @@
 		/* Handle attention interrupt */
 		if (do_attention_interrupt) {
 			dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received attention interrupt.\n");
+			dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Clearing attention interrupt.\n");
+			tw_clear_attention_interrupt(tw_dev);
 			tw_state_request_start(tw_dev, &request_id);
 			error = tw_aen_read_queue(tw_dev, request_id);
 			if (error) {
 				printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Error reading aen queue.\n");
 				tw_dev->state[request_id] = TW_S_COMPLETED;
 				tw_state_request_finish(tw_dev, request_id);
-			} else {
-				dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Clearing attention interrupt.\n");
-				tw_clear_attention_interrupt(tw_dev);
 			}
 		}
 
@@ -1134,13 +1143,15 @@
 				response_que.value = inl(response_que_addr);
 				request_id = response_que.u.response_id;
 				command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+				error = 0;
 				if (command_packet->status != 0) {
-					printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
+					printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Bad response, status = 0x%x, flags = 0x%x, unit = 0x%x.\n", command_packet->status, command_packet->flags, command_packet->byte3.unit);
+					error = 1;
 				}
 				if (tw_dev->state[request_id] != TW_S_POSTED) {
 					printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Received a request id (%d) (opcode = 0x%x) that wasn't posted.\n", request_id, command_packet->byte0.opcode);
+					error = 1;
 				}
-				error = 0;
 				dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Response queue request id: %d.\n", request_id);
 				/* Check for internal command */
 				if (tw_dev->srb[request_id] == 0) {
@@ -1184,8 +1195,8 @@
 					}
 					if (error) {
 						/* Tell scsi layer there was an error */
-						printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Scsi Error.\n");
-						tw_dev->srb[request_id]->result = (DID_ERROR << 16);
+						dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Scsi Error.\n");
+						tw_dev->srb[request_id]->result = (DID_RESET << 16);
 					} else {
 						/* Tell scsi layer command was a success */
 						tw_dev->srb[request_id]->result = (DID_OK << 16);
@@ -1467,8 +1478,10 @@
 		    (tw_dev->state[i] != TW_S_INITIAL) &&
 		    (tw_dev->state[i] != TW_S_COMPLETED)) {
 			srb = tw_dev->srb[i];
-			srb->result = (DID_RESET << 16);
-			tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
+			if (srb != NULL) {
+				srb->result = (DID_RESET << 16);
+				tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
+			}
 		}
 	}
 
@@ -1813,6 +1826,10 @@
 			dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught READ_CAPACITY.\n");
 			error = tw_scsiop_read_capacity(tw_dev, request_id);
 			break;
+		case REQUEST_SENSE:
+			dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught REQUEST_SENSE.\n");
+			error = tw_scsiop_request_sense(tw_dev, request_id);
+			break;
 		case TW_IOCTL:
 			dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught TW_SCSI_IOCTL.\n");
 			error = tw_ioctl(tw_dev, request_id);
@@ -2168,6 +2185,23 @@
 
 	return 0;
 } /* End tw_scsiop_read_write() */
+
+/* This function will handle the request sense scsi command */
+int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id)
+{
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_request_sense()\n");
+	
+	/* For now we just zero the sense buffer */
+	memset(tw_dev->srb[request_id]->request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
+	tw_dev->state[request_id] = TW_S_COMPLETED;
+	tw_state_request_finish(tw_dev, request_id);
+	
+	/* If we got a request_sense, we probably want a reset, return error */
+	tw_dev->srb[request_id]->result = (DID_ERROR << 16);
+	tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+
+	return 0;
+} /* End tw_scsiop_request_sense() */
 
 /* This function will handle test unit ready scsi command */
 int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/3w-xxxx.h linux.19p18/drivers/scsi/3w-xxxx.h
--- linux.vanilla/drivers/scsi/3w-xxxx.h	Sat Sep  9 18:42:40 2000
+++ linux.19p18/drivers/scsi/3w-xxxx.h	Sat Mar 10 23:19:10 2001
@@ -3,8 +3,9 @@
    
    Written By: Adam Radford <linux@3ware.com>
    Modifications By: Joel Jacobson <linux@3ware.com>
+		     Arnaldo Carvalho de Melo <acme@conectiva.com.br>
 
-   Copyright (C) 1999, 2000 3ware Inc.
+   Copyright (C) 1999-2001 3ware Inc.
 
    Kernel compatablity By:	Andre Hedrick <andre@suse.com>
    Non-Copyright (C) 2000	Andre Hedrick <andre@suse.com>
@@ -97,6 +98,8 @@
 #define TW_DEVICE_NAME			       "3ware Storage Controller"
 #define TW_VENDOR_ID (0x13C1)	/* 3ware */
 #define TW_DEVICE_ID (0x1000)	/* Storage Controller */
+#define TW_DEVICE_ID2 (0x1001)  /* 7000 series controller */
+#define TW_NUMDEVICES 2
 
 /* Command packet opcodes */
 #define TW_OP_NOP	      0x0
@@ -330,6 +333,7 @@
 int tw_scsiop_read_capacity(TW_Device_Extension *tw_dev, int request_id);
 int tw_scsiop_read_capacity_complete(TW_Device_Extension *tw_dev, int request_id);
 int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id);
+int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id);
 int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id);
 int tw_setfeature(TW_Device_Extension *tw_dev, int parm, int param_size, unsigned char *val);
 int tw_setup_irq(TW_Device_Extension *tw_dev);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/Config.in linux.19p18/drivers/scsi/Config.in
--- linux.vanilla/drivers/scsi/Config.in	Mon Dec 11 22:12:53 2000
+++ linux.19p18/drivers/scsi/Config.in	Thu Feb 15 16:19:20 2001
@@ -2,6 +2,7 @@
 
 dep_tristate 'SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI
 dep_tristate 'SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI
+dep_tristate 'OnStream SC-x0 SCSI tape support' CONFIG_CHR_DEV_OSST $CONFIG_SCSI
 dep_tristate 'SCSI CD-ROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI
 if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then
   bool '  Enable vendor-specific extensions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR
@@ -29,9 +30,8 @@
 dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI
 if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then
     bool '   Enable Tagged Command Queueing (TCQ) by default' CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
-    int  '   Maximum number of TCQ commands per device' CONFIG_AIC7XXX_CMDS_PER_DEVICE 8
-    bool '   Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS N
-    int  '   Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 5
+    int  '   Maximum number of TCQ commands per device' CONFIG_AIC7XXX_CMDS_PER_DEVICE 24
+    bool '   Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS
 fi
 dep_tristate 'IBM ServeRAID support' CONFIG_SCSI_IPS $CONFIG_SCSI
 dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI
@@ -71,7 +71,7 @@
   dep_tristate 'Initio 9100U(W) support' CONFIG_SCSI_INITIO $CONFIG_SCSI
   dep_tristate 'Initio INI-A100U2W support' CONFIG_SCSI_INIA100 $CONFIG_SCSI
 fi
-if [ "$CONFIG_PARPORT" != "n" ]; then
+if [ "$CONFIG_PARPORT" = "y" -o "$CONFIG_PARPORT" = "m" ]; then
   dep_tristate 'IOMEGA parallel port (ppa - older drives)' CONFIG_SCSI_PPA $CONFIG_SCSI $CONFIG_PARPORT
   dep_tristate 'IOMEGA parallel port (imm - newer drives)' CONFIG_SCSI_IMM $CONFIG_SCSI $CONFIG_PARPORT
   if [ "$CONFIG_SCSI_PPA" != "n" -o "$CONFIG_SCSI_IMM" != "n" ]; then
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/Makefile linux.19p18/drivers/scsi/Makefile
--- linux.vanilla/drivers/scsi/Makefile	Mon Dec 11 22:12:53 2000
+++ linux.19p18/drivers/scsi/Makefile	Wed Dec 13 21:31:47 2000
@@ -61,6 +61,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_CHR_DEV_OSST),y)
+L_OBJS += osst.o
+else
+  ifeq ($(CONFIG_CHR_DEV_OSST),m)
+  M_OBJS += osst.o
+  endif
+endif
+
 ifeq ($(CONFIG_BLK_DEV_SD),y)
 L_OBJS += sd.o sd_ioctl.o
 else
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/README.aic7xxx linux.19p18/drivers/scsi/README.aic7xxx
--- linux.vanilla/drivers/scsi/README.aic7xxx	Fri Apr 21 12:46:31 2000
+++ linux.19p18/drivers/scsi/README.aic7xxx	Mon Feb 12 14:57:23 2001
@@ -14,50 +14,17 @@
     Adaptec Cards
     ----------------------------
     AHA-274x
-    AHA-274xT               
-    AHA-2842
-    AHA-2910B               
-    AHA-2920C
-    AHA-2930
-    AHA-2930U
-    AHA-2930CU
-    AHA-2930U2
-    AHA-2940               
-    AHA-2940W              
-    AHA-2940U              
-    AHA-2940UW
-    AHA-2940UW-PRO
-    AHA-2940AU 
-    AHA-2940U2W
-    AHA-2940U2
-    AHA-2940U2B
-    AHA-2940U2BOEM
-    AHA-2944D              
-    AHA-2944WD
-    AHA-2944UD
-    AHA-2944UWD
-    AHA-2950U2
-    AHA-2950U2W
-    AHA-2950U2B
-    AHA-29160M
-    AHA-3940
-    AHA-3940U
-    AHA-3940W
-    AHA-3940UW
-    AHA-3940AUW
-    AHA-3940U2W
-    AHA-3950U2B
-    AHA-3950U2D
-    AHA-3960D
-    AHA-39160M
-    AHA-3985
-    AHA-3985U
-    AHA-3985W
-    AHA-3985UW
+    AHA-274xT
+    AHA-274xW
+    AHA-284x
+    AHA-284xW
+    All PCI based cards using any of the chipsets listed under motherboard
+    chipsets.  In general, this means *all* of the Adaptec SCSI controllers
+    except the ones specifically excluded later on in this document.
 
     Motherboard Chipsets
     ----------------------------
-    AIC-777x   
+    AIC-777x
     AIC-785x
     AIC-786x
     AIC-787x
@@ -71,15 +38,14 @@
         SCSI-1/SCSI-2 50pin devices, transfer rates up to 20MB/s.
     U - Ultra SCSI, transfer rates up to 40MB/s.
     U2- Ultra 2 SCSI, transfer rates up to 80MB/s.
+    U3- Ultra 3 SCSI, transfer rates up to 160MB/s.
     D - Differential SCSI.
     T - Twin Channel SCSI. Up to 14 SCSI devices.
 
     AHA-274x - EISA SCSI controller
     AHA-284x - VLB SCSI controller
     AHA-29xx - PCI SCSI controller
-    AHA-394x - PCI controllers with two separate SCSI controllers on-board.
-    AHA-398x - PCI RAID controllers with three separate SCSI controllers
-               on-board.
+    AHA-39xx - PCI controllers with multiple separate SCSI channels on-board.
 
   Not Supported Devices
   ------------------------------
@@ -93,7 +59,7 @@
 
     Motherboard Chipsets
     ----------------------------
-    AIC-7810
+    AIC-781x
 
     Bus Types
     ----------------------------
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/README.osst linux.19p18/drivers/scsi/README.osst
--- linux.vanilla/drivers/scsi/README.osst	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/scsi/README.osst	Sat Dec 30 19:50:25 2000
@@ -0,0 +1,218 @@
+README file for the osst driver
+===============================
+(w) Kurt Garloff <garloff@suse.de> 11/2000
+
+This file describes the osst driver as of version 0.8.x/0.9.x, the released
+version of the osst driver.
+It is intended to help advanced users to understand the role of osst and to
+get them started using (and maybe debugging) it.
+It won't address issues like "How do I compile a kernel?" or "How do I load
+a module?", as these are too basic.
+Once the OnStream got merged into the official kernel, the distro makers
+will provide the OnStream support for those who are not familiar with
+hacking their kernels.
+
+
+Purpose
+-------
+The osst driver was developed, because the standard SCSI tape driver in
+Linux, st, does not support the OnStream SC-x0 SCSI tape. The st is not to
+blame for that, as the OnStream tape drives do not support the standard SCSI
+command set for Serial Access Storage Devices (SASDs), which basically
+corresponds to the QIC-157 spec.
+Nevertheless, the OnStream tapes are nice pieces of hardware and therefore
+the osst driver has been written to make these tape devs supported by Linux.
+The driver is free software. It's released under the GNU GPL and planned to
+be integrated into the mainstream kernel.
+
+
+Implementation
+--------------
+The osst is a new high-level SCSI driver, just like st, sr, sd and sg. It
+can be compiled into the kernel or loaded as a module.
+As it represents a new device, it got assigned a new device node: /dev/osstX
+are character devices with major no 206 and minor numbers like the /dev/stX
+devices. If those are not present, you may create them by calling
+Makedevs.sh as root (see below).
+The driver started being a copy of st and as such, the osst devices'
+behavior looks very much the same as st to the userspace applications.
+
+
+History
+-------
+In the first place, osst shared it's identity very much with st. That meant
+that it used the same kernel structures and the same device node as st.
+So you could only have either of them being present in the kernel. This has
+been fixed by registering an own device, now.
+st and osst can coexist, each only accessing the devices it can support by
+their own device.
+
+
+Installation
+------------
+osst got integrated into the linux kernel. Select it during kernel
+configuration as module or compile statically into the kernel.
+Compile your kernel and install the modules.
+
+Now, your osst driver is inside the kernel or available as a module,
+depending on your choice during kernel config. You may still need to create
+the device nodes by calling the Makedevs.sh script (see below) manually,
+unless you use a devfs kernel, where this won't be needed.
+
+To load your module, you may use the command 
+modprobe osst
+as root. dmesg should show you, whether your OnStream tapes have been
+recognized.
+
+If you want to have the module autoloaded on access to /dev/osst, you may
+add something like
+alias char-major-206 osst
+to your /etc/modules.conf (old name: conf.modules).
+
+You may find it convenient to create a symbolic link 
+ln -s nosst0 /dev/tape
+to make programs assuming a default name of /dev/tape more convenient to
+use.
+
+The device nodes for osst have to be created. Use the Makedevs.sh script
+attached to this file.
+
+
+Using it
+--------
+You may use the OnStream tape driver with your standard backup software,
+which may be tar, cpio, amanda, arkeia, BRU, Lone Tar, ...
+by specifying /dev/(n)osst0 as the tape device to use or using the above
+symlink trick. The IOCTLs to control tape operation are also mostly
+supported and you may try the mt (or mt_st) program to jump between
+filemarks, eject the tape, ...
+
+There's one limitation: You need to use a block size of 32kB.
+
+(This limitation is worked on and will be fixed in version 0.8.7 of
+ this driver.)
+
+If you just want to get started with standard software, here is an example
+for creating and restoring a full backup:
+# Backup
+tar cvf - / --exclude /proc | buffer -s 32k -m 24M -B -t -o /dev/nosst0
+# Restore
+buffer -s 32k -m 8M -B -t -i /dev/osst0 | tar xvf - -C /
+
+The buffer command has been used to buffer the data before it goes to the
+tape (or the file system) in order to smooth out the data stream and prevent
+the tape from needing to stop and rewind. The OnStream does have an internal
+buffer and a variable speed which help this, but especially on writing, the
+buffering still proves useful in most cases. It also pads the data to
+guarantees the block size of 32k. (Otherwise you may pass the -b64 option to
+tar.)
+Expect something like 1.8MB/s for the SC-x0 drives and 0.9MB/s for the DI-30.
+The USB drive will give you about 0.7MB/s.
+On a fast machine, you may profit from software data compression (z flag for
+tar).
+
+
+USB and IDE
+-----------
+Via the SCSI emulation layers usb-storage and ide-scsi, you can also use the
+osst driver to drive the USB-30 and the DI-30 drives. (Unfortunately, there
+is no such layer for the parallel port, otherwise the DP-30 would work as
+well.) For the USB support, you need the latest 2.4.0-test kernels and the 
+latest usb-storage driver from 
+http://www.linux-usb.org/
+http://sourceforge.net/cvs/?group_id=3581
+
+Note that the ide-tape driver as of 1.16f uses a slightly outdated on-tape
+format and therefore is not completely interoperable with osst tapes.
+
+The ADR-x0 line is fully SCSI-2 compliant and is supported by st, not osst.
+The on-tape format is supposed to be compatible with the one used by osst.
+
+
+Feedback and updates
+--------------------
+The driver development is coordinated through a mailing list
+<osst@linux1.onstream.nl>
+a CVS repository and some web pages. 
+The tester's pages which contain recent news and updated drivers to download
+can be found on
+http://linux1.onstream.nl/test/
+
+If you find any problems, please have a look at the tester's page in order
+to see whether the problem is already known and solved. Otherwise, please
+report it to the mailing list. Your feedback is welcome. (This holds also
+for reports of successful usage, of course.) 
+In case of trouble, please do always provide the following info:
+* driver and kernel version used (see syslog)
+* driver messages (syslog)
+* SCSI config and OnStream Firmware (/proc/scsi/scsi)
+* description of error. Is it reproducible?
+* software and commands used
+
+You may subscribe to the mailing list, BTW, it's a majordomo list.
+
+
+Status
+------
+0.8.0 was the first widespread BETA release. Since then a lot of reports
+have been sent, but mostly reported success or only minor trouble.
+All the issues have been addressed.
+Check the web pages for more info about the current developments.
+
+
+Acknowledgments
+----------------
+The driver has been started by making a copy of Kai Makisara's st driver.
+Most of the development has been done by Willem Riede. The presence of the
+userspace program osg (onstreamsg) from Terry Hardie has been rather
+helpful. The same holds for Gadi Oxman's ide-tape support for the DI-30.
+I did add some patches to those drivers as well and coordinated things a
+little bit. 
+Note that most of them did mostly spend their spare time for the creation of
+this driver.
+The people from OnStream, especially Jack Bombeeck did support this project
+and always tried to answer HW or FW related questions. Furthermore, he
+pushed the FW developers to do the right things.
+SuSE did support this project by allowing me to work on it during my working
+time for them and by integrating the driver into their distro.
+
+More people did help by sending useful comments. Sorry to those who have
+been forgotten. Thanks to all the GNU/FSF and Linux developers who made this
+platform such an interesting, nice and stable platform.
+Thanks go to those who tested the drivers and did send useful reports. Your
+help is needed!
+
+
+Makedevs.sh
+-----------
+#!/bin/sh
+# Script to create OnStream SC-x0 device nodes (major 206)
+# Usage: Makedevs.sh [nos [path to dev]]
+# $Id: README.osst.kernel,v 1.1.2.2 2000/12/20 14:08:38 garloff Exp $
+major=206
+nrs=4
+dir=/dev
+test -z "$1" || nrs=$1
+test -z "$2" || dir=$2
+declare -i nr
+nr=0
+test -d $dir || mkdir -p $dir
+while test $nr -lt $nrs; do
+  mknod $dir/osst$nr c $major $nr
+  chown 0.disk $dir/osst$nr; chmod 660 $dir/osst$nr;
+  mknod $dir/nosst$nr c $major $[nr+128]
+  chown 0.disk $dir/nosst$nr; chmod 660 $dir/nosst$nr;
+  mknod $dir/osst${nr}l c $major $[nr+32]
+  chown 0.disk $dir/osst${nr}l; chmod 660 $dir/osst${nr}l;
+  mknod $dir/nosst${nr}l c $major $[nr+160]
+  chown 0.disk $dir/nosst${nr}l; chmod 660 $dir/nosst${nr}l;
+  mknod $dir/osst${nr}m c $major $[nr+64]
+  chown 0.disk $dir/osst${nr}m; chmod 660 $dir/osst${nr}m;
+  mknod $dir/nosst${nr}m c $major $[nr+192]
+  chown 0.disk $dir/nosst${nr}m; chmod 660 $dir/nosst${nr}m;
+  mknod $dir/osst${nr}a c $major $[nr+96]
+  chown 0.disk $dir/osst${nr}a; chmod 660 $dir/osst${nr}a;
+  mknod $dir/nosst${nr}a c $major $[nr+224]
+  chown 0.disk $dir/nosst${nr}a; chmod 660 $dir/nosst${nr}a;
+  let nr+=1
+done
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/README.tmscsim linux.19p18/drivers/scsi/README.tmscsim
--- linux.vanilla/drivers/scsi/README.tmscsim	Sat Sep  9 18:42:40 2000
+++ linux.19p18/drivers/scsi/README.tmscsim	Sat Dec 30 19:46:46 2000
@@ -9,6 +9,7 @@
 6. Potential improvements
 7. Bug reports, debugging and updates
 8. Acknowledgements
+9. Copyright
 
 
 1. Purpose and history
@@ -25,7 +26,7 @@
 Tekram DC390(T) adapter. This is where the name comes from: tm = Tekram
 scsi = SCSI driver, m = AMD (?) as opposed to w for the DC390W/U/F
 (NCR53c8X5, X=2/7) driver. Yes, there was also a driver for the latter,
-tmscsimw, which supported DC390W/U/F adapters. It's not maintained any more,
+tmscsiw, which supported DC390W/U/F adapters. It's not maintained any more,
 as the ncr53c8xx is perfectly supporting these adpaters since some time.
 
 The driver first appeared in April 1996, exclusively supported the DC390 
@@ -56,10 +57,13 @@
 driver. Of course you have to choose to compile SCSI support and DC390(T)
 support into your kernel or as module when configuring your kernel for
 compiling.
+NEW: You may as well compile this module outside your kernel, using the
+supplied Makefile.
 
  If you got an old kernel (pre 2.1.127, pre 2.0.37p1) with an old version of
  this driver: Get dc390-21125-20b.diff.gz or dc390-2036p21-20b1.diff.gz from
- my website and apply the patch. 
+ my web page and apply the patch. Apply further patches to upgrade to the 
+ latest version of the driver.
 
  If you want to do it manually, you should copy the files (dc390.h,
  tmscsim.h, tmscsim.c, scsiiom.c and README.tmscsim) from this directory to
@@ -91,6 +95,8 @@
   tune2fs -e remount-ro /dev/sd??
 * have copies of your SCSI disk's partition tables on some safe location:
   dd if=/dev/sda of=/mnt/floppy/sda bs=512 count=1
+  or just print it with:
+  fdisk -l | lpr
 * make sure you are able to boot Linux (e.g. from floppy disk using InitRD)
   if your SCSI disk gets corrupted. You can use 
   ftp://student.physik.uni-dortmund.de/pub/linux/kernel/bootdisk.gz
@@ -102,7 +108,7 @@
 than the 33.33 MHz being in the PCI spec.
 
 If you want to share the IRQ with another device and the driver refuses to
-do, you might succeed with changing the DC390_IRQ type in tmscsim.c to 
+do so, you might succeed with changing the DC390_IRQ type in tmscsim.c to 
 SA_SHIRQ | SA_INTERRUPT.
 
 
@@ -121,11 +127,12 @@
  * Dynamically configurable by writing to /proc/scsi/tmscsim/?
  * Dynamic allocation of resources
  * SMP support: Locking on io_request lock (Linux 2.1/2.2) or adapter 
-    specific locks (Linux 2.3)
+    specific locks (Linux 2.5?)
  * Uniform source code for Linux-2.x.y
  * Support for dyn. addition/removal of devices via add/remove-single-device
-   (Try: echo "scsi add-single-device H C I L" >/proc/scsi/scsi 
-    H = Host, C = Channel, I = SCSI ID, L = SCSI LUN.) Use with care!
+   (Try: echo "scsi add-single-device C B T U" >/proc/scsi/scsi 
+    C = Controller, B = Bus, T = Target SCSI ID, U = Unit SCSI LUN.) 
+    Use with care!
  * Try to use the partition table for the determination of the mapping
 
 
@@ -139,20 +146,21 @@
 the attached devices and their settings.
 
 Here's an example:
-garloff@kg1:/home/garloff > cat /proc/scsi/tmscsim/0
-Tekram DC390/AM53C974 PCI SCSI Host Adapter, Driver Version 1.20s, 1998/08/20
-SCSI Host Nr 0, AM53C974 Adapter Nr 0
-IOPortBase 0x6200, IRQLevel 0x09
-MaxID 7, MaxLUN 8, AdapterID 7, SelTimeout 250 ms
-TagMaxNum 16, Status 0, ACBFlag 0, GlitchEater 24 ns
-Statistics: Nr of Cmnds 39563, Cmnds not sent directly 0, Out of SRB conds 0
-            Nr of lost arbitrations 17
+garloff@kurt:/home/garloff > cat /proc/scsi/tmscsim/0
+Tekram DC390/AM53C974 PCI SCSI Host Adapter, Driver Version 2.0e7 2000-11-28
+SCSI Host Nr 1, AM53C974 Adapter Nr 0
+IOPortBase 0xb000, IRQ 10
+MaxID 8, MaxLUN 8, AdapterID 6, SelTimeout 250 ms, DelayReset 1 s
+TagMaxNum 16, Status 0x00, ACBFlag 0x00, GlitchEater 24 ns
+Statistics: Cmnds 1470165, Cmnds not sent directly 0, Out of SRB conds 0
+            Lost arbitrations 587,  Sel. connected 0, Connected: No
 Nr of attached devices: 4, Nr of DCBs: 4
-Idx ID LUN Prty Sync DsCn SndS TagQ STOP NegoPeriod SyncSpeed SyncOffs
-00  00  00  Yes  Yes  Yes  Yes  Yes  No    100 ns    10.0 M      15
-01  01  00  Yes  Yes  Yes  Yes  Yes  No    100 ns    10.0 M      15
-02  03  00  Yes  Yes  Yes  Yes  No   No    100 ns    10.0 M      15
-03  05  00  Yes  No   Yes  Yes  No   No   (200 ns)
+Map of attached LUNs: 01 00 00 03 01 00 00 00
+Idx ID LUN Prty Sync DsCn SndS TagQ NegoPeriod SyncSpeed SyncOffs MaxCmd
+00  00  00  Yes  Yes  Yes  Yes  Yes   100 ns    10.0 M      15      16
+01  03  00  Yes  Yes  Yes  Yes  No    100 ns    10.0 M      15      01
+02  03  01  Yes  Yes  Yes  Yes  No    100 ns    10.0 M      15      01
+03  04  00  Yes  Yes  Yes  Yes  No    100 ns    10.0 M      15      01
 
 Note that the settings MaxID and MaxLUN are not zero- but one-based, which
 means that a setting MaxLUN=4, will result in the support of LUNs 0..3. This
@@ -178,9 +186,8 @@
 The last values are only shown, if Sync is enabled. (NegoPeriod is still
 displayed in brackets to show the values which will be used after enabling
 Sync.)
-The STOP parameter is for testing/debugging purposes only and should bet set
-to No. Please don't fiddle with it, unless you want to get rid of the
-contents of your disk.
+MaxCmd ist the number of commands (=tags) which can be processed at the same
+time by the device.
 
 If you want to change a setting, you can do that by writing to
 /proc/scsi/tmscsim/?. Basically you have to imitate the output of driver.
@@ -196,8 +203,8 @@
      echo "MaxLUN=8 seltimeout 200" >/proc/scsi/tmscsim/0
 
     Note that you can only change MaxID, MaxLUN, AdapterID, SelTimeOut,
-    TagMaxNum, ACBFlag and GlitchEater. Don't change ACBFlag unless you
-    want to see what happens, if the driver hangs.
+    TagMaxNum, ACBFlag, GlitchEater and DelayReset. Don't change ACBFlag
+    unless you want to see what happens, if the driver hangs.
 
 (2) Change device settings: You write a config line to the driver. The Nr
     must match the ID and LUN given. If you give "-" as parameter, it is
@@ -207,8 +214,8 @@
     an INQUIRY on the device if necessary to check if it is capable to operate
     with the given settings (Sync, TagQ).
     Examples:
-     echo "0 0 0 y y y - y - 10" >/proc/scsi/tmscsim/0
-     echo "3 5 0 y n y" >/proc/scsi/tmscsim/0
+     echo "0 0 0 y y y - y - 10 " >/proc/scsi/tmscsim/0
+     echo "3 5 0 y n y " >/proc/scsi/tmscsim/0
 
     To give a short explanation of the first example: 
     The first three numbers, "0 0 0" (Device index 0, SCSI ID 0, SCSI LUN 0),
@@ -223,22 +230,26 @@
     discussed above. The values used in this example will result in maximum
     performance.
 
-(3) Special commands: You can force a SCSI bus reset, an INQUIRY command and
-    the removal of a device's DCB.
+(3) Special commands: You can force a SCSI bus reset, an INQUIRY command, the
+    removal or the addition of a device's DCB and a SCSI register dump.
     This is only used for debugging when you meet problems. The parameter of
-    the INQUIRY and remove command is the device index as shown by the
+    the INQUIRY and REMOVE commands is the device index as shown by the
     output of /proc/scsi/tmscsim/? in the device listing in the first column
-    (Idx).
+    (Idx). ADD takes the SCSI ID and LUN.
     Examples:
      echo "reset" >/proc/scsi/tmscsim/0
      echo "inquiry 1" >/proc/scsi/tmscsim/0
      echo "remove 2" >/proc/scsi/tmscsim/1
+     echo "add 2 3" >/proc/scsi/tmscsim/?
+     echo "dump" >/proc/scsi/tmscsim/0
 
-    Note that you will meet problems when you remove a device's DCB with the
+    Note that you will meet problems when you REMOVE a device's DCB with the
     remove command if it contains partitions which are mounted. Only use it
     after unmounting its partitions, telling the SCSI mid-level code to
     remove it (scsi remove-single-device) and you really need a few bytes of
     memory.
+    The ADD command allows you to configure a device before you tell the
+    mid-level code to try detection.
 
 
 I'd suggest reviewing the output of /proc/scsi/tmscsim/? after changing
@@ -247,18 +258,20 @@
 
 5. Configuration via boot/module parameters
 -------------------------------------------
-With the DC390, the driver reads its EEPROM settings and IGNORES boot / 
-module parameters. If you want to override the EEPROM settings of a DC390, 
-you have to use the /proc/scsi/tmscsim/? interface described in the above
-chapter.
-
-However, if you do have another AM53C974 based adapter you might want to
-adjust some settings before you are able to write to the /proc/scsi/tmscsim/?
-pseudo-file, e.g. if you want to use another adapter ID than 7. (Note that
-the log message "DC390: No EEPROM found!" is normal without a DC390.)
+With the DC390, the driver reads its EEPROM settings and tries to use them.
+But you may want to override the settings prior to being able to change the
+driver configuration via /proc/scsi/tmscsim/?.
+If you do have another AM53C974 based adapter, that's even the only
+possibility to adjust settings before you are able to write to the
+/proc/scsi/tmscsim/? pseudo-file, e.g. if you want to use another 
+adapter ID than 7.  
+(BTW, the log message "DC390: No EEPROM found!" is normal without a DC390.)
 For this purpose, you can pass options to the driver before it is initialised
 by using kernel or module parameters. See lilo(8) or modprobe(1) manual
 pages on how to pass params to the kernel or a module.
+[NOTE: Formerly, it was not possible to override the EEPROM supplied
+ settings of the DC390 with cmd line parameters. This has changed since
+ 2.0e7]
 
 The syntax of the params is much shorter than the syntax of the /proc/...
 interface. This makes it a little bit more difficult to use. However, long
@@ -269,7 +282,7 @@
 DC390 EEPROM, the settings are given in a DC390 BIOS' way.
 
 Here's the syntax:
-tmscsim=AdaptID,SpdIdx,DevMode,AdaptMode,TaggedCmnds
+tmscsim=AdaptID,SpdIdx,DevMode,AdaptMode,TaggedCmnds,DelayReset
 
 Each of the parameters is a number, containing the described information:
 
@@ -278,7 +291,7 @@
 
 * SpdIdx: The index of the maximum speed as in the DC390 BIOS. The values
   0..7 mean 10, 8.0, 6.7, 5.7, 5.0, 4.0, 3.1 and 2 MHz resp. Default is
-  1 (8.0 MHz).
+  0 (10.0 MHz).
 
 * DevMode is a bit mapped value describing the per-device features. It
   applies to all devices. (Sync, Disc and TagQ will only apply, if the
@@ -289,7 +302,7 @@
    *1	 0x02	    2	  Synchronous Negotiation
    *2	 0x04	    4	  Disconnection
    *3	 0x08	    8	  Send Start command on startup. (Not used)
-   *4	 0x10	   16	  Tagged Queueing
+   *4	 0x10	   16	  Tagged Command Queueing
 
   As usual, the desired value is obtained by adding the wanted values. If
   you want to enable all values, e.g., you would use 31(0x1f). Default is 31.
@@ -315,18 +328,23 @@
     *3		16
      4		32
 
+* DelayReset is the time in seconds (minus 0.5s), the adapter waits, after a
+  bus reset. Default is 1 (corresp. to 1.5s).
+
 Example:
  modprobe tmscsim tmscsim=6,2,31
 would set the adapter ID to 6, max. speed to 6.7 MHz, enable all device
-features and leave the adapter features and the number of Tagged Commands 
-to the defaults.
-
-As you can see, you don't need to specify all of the five params.
+features and leave the adapter features, the number of Tagged Commands
+and the Delay after a reset to the defaults.
 
-The defaults (7,1,31,15,3) are aggressive to allow good performance. You can
-use tmscsim=7,0,31,63,4 for maximum performance, if your SCSI chain is
-perfect. If you meet problems, you can use tmscsim=-1 which is a shortcut
-for tmscsim=7,4,9,15,2. 
+As you can see, you don't need to specify all of the six params.
+If you want values to be ignored (i.e. the EEprom settings or the defaults
+will be used), you may pass -2 (not 0!) at the corresponding position.
+
+The defaults (7,0,31,15,3,1) are aggressive to allow good performance. You
+can use tmscsim=7,0,31,63,4,0 for maximum performance, if your SCSI chain
+allows it. If you meet problems, you can use tmscsim=-1 which is a shortcut
+for tmscsim=7,4,9,15,2,10.
 
 
 6. Potential improvements
@@ -334,42 +352,47 @@
 Most of the intended work on the driver has been done. Here are a few ideas
 to further improve its usability:
 
+* Cleanly separate per-Target and per-LUN properties (DCB)
 * More intelligent abort() routine
-* Implement new_eh code (Linux-2.1+)
-* Have the mid-level code (and not the driver) handle more of the various
-  conditions.
-* Rework command queueing in the driver
+* Use new_eh code (Linux-2.1+)
+* Have the mid-level (ML) code (and not the driver) handle more of the
+  various conditions.
+* Command queueing in the driver: Eliminate Query list and use ML instead.
 * More user friendly boot/module param syntax
 
 Further investigation on these problems:
 
 * Driver hangs with sync readcdda (xcdroast) (most probably VIA PCI error)
 
-Known problems:
+Known problems: 
+Please see http://www.garloff.de/kurt/linux/dc390/problems.html
 
-* There was a report that with a certain Scanner, the last SCSI command
-  won't be finished correctly. This might be a command queueing bug or a bug
-  in SCSI implementation of the scanner. Issueing another command to the
-  scanner seems to help. (Try echo "INQUIRY x" >/proc/scsi/tmscsim/?, where
-  x is the index (not the SCSI ID!) of the scanner. See 4.(3).)
+* Changing the parameters of multi-lun by the tmscsim/? interface will
+  cause problems, cause these settings are mostly per Target and not per LUN
+  and should be updated accordingly. To be fixed for 2.0d24.
+* CDRs (eg Yam CRW4416) not recognized, because some buggy devices don't 
+  recover from a SCSI reset in time. Use a higher delay or don't issue
+  a SCSI bus reset on driver initialization. See problems page.
+  For the CRW4416S, this seems to be solved with firmware 1.0g (reported by 
+  Jean-Yves Barbier).
+* TEAC CD-532S not being recognized. (Works with 1.11).
+* Scanners (eg. Astra UMAX 1220S) don't work: Disable Sync Negotiation.
+  If this does not help, try echo "INQUIRY t" >/proc/scsi/tmscsim/? (t
+  replaced by the dev index of your scanner). You may try to reset your SCSI
+  bus afterwards (echo "RESET" >/proc/scsi/tmscsim/?).
+  The problem seems to be solved as of 2.0d18, thanks to Andreas Rick.
 * If there is a valid partition table, the driver will use it for determing
-  the mapping. Other operating systems may not like this mapping, though
+  the mapping. If there's none, a reasonable mapping (Symbios-like) will be
+  assumed. Other operating systems may not like this mapping, though
   it's consistent with the BIOS' behaviour. Old DC390 drivers ignored the
   partition table and used a H/S = 64/32 or 255/63 translation. So if you
   want to be compatible to those, use this old mapping when creating
-  partition tables.
-* In some situations, the driver will get stuck in an abort loop. Please
-  disable DsCn, if you meet this problem. Please contact me for further
-  debugging.
-* 2.1.115+: Linux misses locks in sr_ioctl.c and scsi_ioctl.c
-  There used to be a patch included here, which partially solved the
-  problem. I suggest you contact Chiaki Ishikawa <ishikawa@yk.rim.or.jp>, 
-  Richard Waltham <dormouse@farsrobt.demon.co.uk> or Doug Ledford
-  <dledford@dialnet.net>, if you want to help further debugging it.
-* 2.0.35: CD changers (e.g. NAKAMICHI MBR-7.{0,2}) have problems because
-  the mid-level code doesn't handle BLIST_SINGLELUN correctly. There used
-  to be a patch included here to fix this, but I was told that it is fixed
-  in 2.0.36.
+  partition tables. Even worse, on bootup the DC390 might complain if other
+  mappings are found, so auto rebooting may fail.
+* In some situations, the driver will get stuck in an abort loop. This is a
+  bad interaction between the Mid-Layer of Linux' SCSI code and the driver.
+  Try to disable DsCn, if you meet this problem. Please contact me for
+  further debugging.
 
 
 7. Bug reports, debugging and updates
@@ -394,25 +417,33 @@
 
 The latest version of the driver can be found at:
  http://www.garloff.de/kurt/linux/dc390/
-and
- ftp://student.physik.uni-dortmund.de/pub/linux/kernel/dc390/
-(The latter might shut down some day.)
+ ftp://ftp.suse.com/pub/people/garloff/linux/dc390/
 
 
 8. Acknowledgements
 -------------------
-Thanks to Linus Torvalds, Alan Cox, David Miller, Rik v. Riel, the FSF
-people, the XFree86 team and all the others for the wonderful OS and
-software. 
+Thanks to Linus Torvalds, Alan Cox, the FSF people, the XFree86 team and 
+all the others for the wonderful OS and software.
 Thanks to C.L. Huang and Philip Giang (Tekram) for the initial driver
 release and support.
-Thanks to Doug Ledford, Gerard Roudier for support with SCSI coding.
+Thanks to Doug Ledford, Gérard Roudier for support with SCSI coding.
 Thanks to a lot of people (espec. Chiaki Ishikawa, Andreas Haumer, Hubert 
 Tonneau) for intensively testing the driver (and even risking data loss
-doing this during early revisions). 
+doing this during early revisions).
+Recently, SuSE GmbH, Nuernberg, FRG, has been paying me for the driver
+development and maintenance. Special thanks!
+
 
+9. Copyright
+------------
+ This driver 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; version 2 of the License.
+ If you want to use any later version of the GNU GPL, you will probably
+ be allowed to, but you have to ask me and Tekram <erich@tekram.com.tw>
+ before.
 
 -------------------------------------------------------------------------
 Written by Kurt Garloff <kurt@garloff.de> 1998/06/11
-Last updated 1998/12/25, driver revision 2.0d
-$Id: README.tmscsim,v 2.9 1998/12/25 18:04:20 garloff Exp $
+Last updated 2000/11/28, driver revision 2.0e7
+$Id: README.tmscsim,v 2.25.2.7 2000/12/20 01:07:12 garloff Exp $
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aha1542.c linux.19p18/drivers/scsi/aha1542.c
--- linux.vanilla/drivers/scsi/aha1542.c	Mon Dec 11 22:12:53 2000
+++ linux.19p18/drivers/scsi/aha1542.c	Sun Feb 25 23:17:32 2001
@@ -560,7 +560,9 @@
       done(SCpnt); return 0;});
     
     if(*cmd == REQUEST_SENSE){
-#ifndef DEBUG
+#if 0
+      /* scsi_request_sense() provides a buffer of size 256,
+         so there is no reason to expect equality */
       if (bufflen != sizeof(SCpnt->sense_buffer)) {
 	printk("Wrong buffer length supplied for request sense (%d)\n",bufflen);
       };
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aha1740.c linux.19p18/drivers/scsi/aha1740.c
--- linux.vanilla/drivers/scsi/aha1740.c	Fri Apr 21 12:46:27 2000
+++ linux.19p18/drivers/scsi/aha1740.c	Sun Feb 25 23:19:07 2001
@@ -324,11 +324,13 @@
 
     if(*cmd == REQUEST_SENSE)
     {
+#if 0
 	if (bufflen != sizeof(SCpnt->sense_buffer))
 	{
 	    printk("Wrong buffer length supplied for request sense (%d)\n",
 		   bufflen);
 	}
+#endif	
 	SCpnt->result = 0;
 	done(SCpnt); 
 	return 0;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx/aic7xxx.h linux.19p18/drivers/scsi/aic7xxx/aic7xxx.h
--- linux.vanilla/drivers/scsi/aic7xxx/aic7xxx.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/scsi/aic7xxx/aic7xxx.h	Mon Feb 12 14:57:23 2001
@@ -0,0 +1,114 @@
+/*+M*************************************************************************
+ * Adaptec AIC7xxx device driver for Linux.
+ *
+ * Copyright (c) 1994 John Aycock
+ *   The University of Calgary Department of Computer Science.
+ *
+ * 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, 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; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * 
+ * $Id: aic7xxx.h,v 3.2 1996/07/23 03:37:26 deang Exp $
+ *-M*************************************************************************/
+#ifndef _aic7xxx_h
+#define _aic7xxx_h
+
+#define AIC7XXX_H_VERSION  "3.2.4"
+
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+
+#ifndef KERNEL_VERSION
+#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
+#endif
+
+#if defined(__i386__)
+#  define AIC7XXX_BIOSPARAM aic7xxx_biosparam
+#else
+#  define AIC7XXX_BIOSPARAM NULL
+#endif
+
+/*
+ * Scsi_Host_Template (see hosts.h) for AIC-7xxx - some fields
+ * to do with card config are filled in after the card is detected.
+ */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,65)
+#define AIC7XXX	{						\
+	next: NULL,						\
+	module: NULL,						\
+	proc_dir: NULL,						\
+	proc_info: aic7xxx_proc_info,				\
+	name: NULL,						\
+	detect: aic7xxx_detect,					\
+	release: aic7xxx_release,				\
+	info: aic7xxx_info,					\
+	command: NULL,						\
+	queuecommand: aic7xxx_queue,				\
+	eh_strategy_handler: NULL,				\
+	eh_abort_handler: NULL,					\
+	eh_device_reset_handler: NULL,				\
+	eh_bus_reset_handler: NULL,				\
+	eh_host_reset_handler: NULL,				\
+	abort: aic7xxx_abort,					\
+	reset: aic7xxx_reset,					\
+	slave_attach: NULL,					\
+	bios_param: AIC7XXX_BIOSPARAM,				\
+	can_queue: 255,		/* max simultaneous cmds      */\
+	this_id: -1,		/* scsi id of host adapter    */\
+	sg_tablesize: 0,	/* max scatter-gather cmds    */\
+	cmd_per_lun: 3,		/* cmds per lun (linked cmds) */\
+	present: 0,		/* number of 7xxx's present   */\
+	unchecked_isa_dma: 0,	/* no memory DMA restrictions */\
+	use_clustering: ENABLE_CLUSTERING,			\
+	use_new_eh_code: 0					\
+}
+#else
+#define AIC7XXX	{						\
+	next: NULL,						\
+	usage_count: NULL,					\
+	proc_dir: NULL, 					\
+	proc_info: aic7xxx_proc_info,				\
+	name: NULL,						\
+	detect: aic7xxx_detect,					\
+	release: aic7xxx_release,				\
+	info: aic7xxx_info,					\
+	command: NULL,						\
+	queuecommand: aic7xxx_queue,				\
+	abort: aic7xxx_abort,					\
+	reset: aic7xxx_reset,					\
+	slave_attach: NULL,					\
+	bios_param: AIC7XXX_BIOSPARAM,				\
+	can_queue: 255,		/* max simultaneous cmds      */\
+	this_id: -1,		/* scsi id of host adapter    */\
+	sg_tablesize: 0,	/* max scatter-gather cmds    */\
+	cmd_per_lun: 3,		/* cmds per lun (linked cmds) */\
+	present: 0,		/* number of 7xxx's present   */\
+	unchecked_isa_dma: 0,	/* no memory DMA restrictions */\
+	use_clustering: ENABLE_CLUSTERING			\
+}
+#endif
+
+extern int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
+extern int aic7xxx_biosparam(Disk *, kdev_t, int[]);
+extern int aic7xxx_detect(Scsi_Host_Template *);
+extern int aic7xxx_command(Scsi_Cmnd *);
+extern int aic7xxx_reset(Scsi_Cmnd *, unsigned int);
+extern int aic7xxx_abort(Scsi_Cmnd *);
+extern int aic7xxx_release(struct Scsi_Host *);
+
+extern const char *aic7xxx_info(struct Scsi_Host *);
+
+extern int aic7xxx_proc_info(char *, char **, off_t, int, int, int);
+
+#endif /* _aic7xxx_h */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx/aic7xxx.reg linux.19p18/drivers/scsi/aic7xxx/aic7xxx.reg
--- linux.vanilla/drivers/scsi/aic7xxx/aic7xxx.reg	Fri Apr 21 12:46:27 2000
+++ linux.19p18/drivers/scsi/aic7xxx/aic7xxx.reg	Mon Feb 12 14:57:23 2001
@@ -703,7 +703,12 @@
 						 * it that it can fill the
 						 * message buffer.
 						 */
-	mask	TRACEPOINT	0xb0|SEQINT
+	mask	SEQ_SG_FIXUP	0xb0|SEQINT	/* need help with fixing up
+						 * the sg array pointer after
+						 * a phasemis with no valid
+						 * sg elements in the shadow
+						 * pipeline.
+						 */
 	mask	TRACEPOINT2	0xc0|SEQINT
 	mask	MSGIN_PHASEMIS	0xd0|SEQINT	/*
 						 * Target changed phase on us
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx/aic7xxx.seq linux.19p18/drivers/scsi/aic7xxx/aic7xxx.seq
--- linux.vanilla/drivers/scsi/aic7xxx/aic7xxx.seq	Sat Sep  9 18:42:40 2000
+++ linux.19p18/drivers/scsi/aic7xxx/aic7xxx.seq	Mon Feb 12 14:57:23 2001
@@ -332,12 +332,15 @@
 	/* clear target specific flags */
 	clr	SEQ_FLAGS ret;
 
+
+data_phase_reinit:
 /*
  * If we re-enter the data phase after going through another phase, the
  * STCNT may have been cleared, so restore it from the residual field.
+ * On Ultra2, we have to put it into the HCNT field because we have to
+ * drop the data down into the shadow layer via the preload ability.
  */
-data_phase_reinit:
-	if ((p->features & AHC_ULTRA2) != 0) {
+ 	if ((p->features & AHC_ULTRA2) != 0) {
 		bmov	HADDR, SHADDR, 4;
 		bmov    HCNT, SCB_RESID_DCNT, 3;
 	}
@@ -349,27 +352,24 @@
 		mvi	SCB_RESID_DCNT	call bcopy_3;
 	}
 	jmp	data_phase_loop;
-
 p_data:
-	if ((p->features & AHC_ULTRA2) != 0) {
+ 	if ((p->features & AHC_ULTRA2) != 0) {
 		mvi	DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN;
 	} else {
 		mvi	DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET;
 	}
 	test	LASTPHASE, IOI jnz . + 2;
 	or	DMAPARAMS, DIRECTION;
-	call	assert;			/*
-					 * Ensure entering a data
-					 * phase is okay - seen identify, etc.
-					 */
+	call	assert;		/*
+				 * Ensure entering a data
+				 * phase is okay - seen identify, etc.
+				 */
 	if ((p->features & AHC_CMD_CHAN) != 0) {
 		mvi	CCSGADDR, CCSGADDR_MAX;
 	}
-	test	SEQ_FLAGS, DPHASE	jnz data_phase_reinit;
-
-	/* We have seen a data phase */
-	or	SEQ_FLAGS, DPHASE;
 
+	test	SEQ_FLAGS, DPHASE	jnz data_phase_reinit;
+	or	SEQ_FLAGS, DPHASE;	/* we've seen a data phase */
 	/*
 	 * Initialize the DMA address and counter from the SCB.
 	 * Also set SG_COUNT and SG_NEXT in memory since we cannot
@@ -378,8 +378,10 @@
 	 */
 	if ((p->features & AHC_CMD_CHAN) != 0) {
 		bmov	HADDR, SCB_DATAPTR, 7;
-		bmov    STCNT, HCNT, 3;
 		bmov    SG_COUNT, SCB_SGCOUNT, 5;
+		if ((p->features & AHC_ULTRA2) == 0) {
+			bmov    STCNT, HCNT, 3;
+		}
 	} else {
 		mvi	DINDEX, HADDR;
 		mvi	SCB_DATAPTR	call bcopy_7;
@@ -387,9 +389,8 @@
 		mvi	DINDEX, SG_COUNT;
 		mvi	SCB_SGCOUNT	call bcopy_5;
 	}
-
 data_phase_loop:
-/* Guard against overruns */
+	/* Guard against overruns */
 	test	SG_COUNT, 0xff jnz data_phase_inbounds;
 /*
  * Turn on 'Bit Bucket' mode, set the transfer count to
@@ -399,66 +400,62 @@
  */
 	or	SXFRCTL1,BITBUCKET;
 	and	DMAPARAMS, ~(HDMAEN|SDMAEN);
-	if ((p->features & AHC_CMD_CHAN) != 0) {
-		if ((p->features & AHC_ULTRA2) != 0) {
-			bmov	HCNT, ALLONES, 3;
-		}
+	if ((p->features & AHC_ULTRA2) != 0) {
+		bmov	HCNT, ALLONES, 3;
+	}
+	if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
 		bmov	STCNT, ALLONES, 3;
-	} else {
+	}
+	if ((p->features & AHC_CMD_CHAN) == 0) {
 		mvi	STCNT[0], 0xFF;
 		mvi	STCNT[1], 0xFF;
 		mvi	STCNT[2], 0xFF;
 	}
+
 data_phase_inbounds:
 /* If we are the last SG block, tell the hardware. */
-	cmp	SG_COUNT,0x01 jne data_phase_wideodd;
-	if ((p->features & AHC_ULTRA2) == 0) {
-		and	DMAPARAMS, ~WIDEODD;
+	if ((p->features & AHC_ULTRA2) != 0) {
+		shl	A, 2, SG_COUNT;
+		cmp	SG_COUNT,0x01 jne data_phase_wideodd;
+		or	A, LAST_SEG;
 	} else {
-		mvi	SG_CACHEPTR, LAST_SEG;
+		cmp	SG_COUNT,0x01 jne data_phase_wideodd;
+		and	DMAPARAMS, ~WIDEODD;
 	}
 data_phase_wideodd:
-	if ((p->features & AHC_ULTRA2) != 0) {
-		mov	SINDEX, ALLONES;
-		mov	DFCNTRL, DMAPARAMS;
-		test	SSTAT0, SDONE jnz .;
-data_phase_dma_loop:
-		test	SSTAT0, SDONE jnz data_phase_dma_done;
-		test	SSTAT1,PHASEMIS	jz data_phase_dma_loop;	/* ie. underrun */
-data_phase_dma_phasemis:
-		test	SSTAT0,SDONE	jnz data_phase_dma_done;
-		clr	SINDEX;			/* Remember the phasemiss */
+	if ((p->features & AHC_ULTRA2) != 0) {	
+		mov	SG_CACHEPTR, A;
+		mov	DFCNTRL, DMAPARAMS; /* start the operation */
+		test	SXFRCTL1, BITBUCKET jnz data_phase_overrun;
+u2_preload_wait:
+		test	SSTAT1, PHASEMIS jnz u2_phasemis;
+		test	DFSTATUS, PRELOAD_AVAIL jz u2_preload_wait;
 	} else {
 		mov	DMAPARAMS  call dma;
-	}
-
 data_phase_dma_done:
 /* Go tell the host about any overruns */
-	test	SXFRCTL1,BITBUCKET jnz data_phase_overrun;
+		test	SXFRCTL1,BITBUCKET jnz data_phase_overrun;
 
 /* Exit if we had an underrun.  dma clears SINDEX in this case. */
-	test	SINDEX,0xff	jz data_phase_finish;
-
+		test	SINDEX,0xff	jz data_phase_finish;
+	}
 /*
- * Advance the scatter-gather pointers if needed 
+ * Advance the scatter-gather pointers 
  */
 sg_advance:
-	dec	SG_COUNT;	/* one less segment to go */
+	if ((p->features & AHC_ULTRA2) != 0) {
+		cmp	SG_COUNT, 0x01	je u2_data_phase_finish;
+	} else {
+		dec	SG_COUNT;
+		test	SG_COUNT, 0xff	jz data_phase_finish;
+	}
 
-	test	SG_COUNT, 0xff	jz data_phase_finish; /* Are we done? */
-/*
- * Load a struct scatter and set up the data address and length.
- * If the working value of the SG count is nonzero, then
- * we need to load a new set of values.
- *
- * This, like all DMA's, assumes little-endian host data storage.
- */
-sg_load:
 	if ((p->features & AHC_CMD_CHAN) != 0) {
+
 		/*
 		 * Do we have any prefetch left???
 		 */
-		cmp	CCSGADDR, CCSGADDR_MAX jne prefetched_segs_avail;
+		cmp	CCSGADDR, CCSGADDR_MAX jne prefetch_avail;
 
 		/*
 		 * Fetch MIN(CCSGADDR_MAX, (SG_COUNT * 8)) bytes.
@@ -474,10 +471,12 @@
 		and	CCSGCTL, ~CCSGEN;
 		test	CCSGCTL, CCSGEN jnz .;
 		mvi	CCSGCTL, CCSGRESET;
-prefetched_segs_avail:
+prefetch_avail:
 		bmov 	HADDR, CCSGRAM, 8;
 		if ((p->features & AHC_ULTRA2) == 0) {
 			bmov    STCNT, HCNT, 3;
+		} else {
+			dec	SG_COUNT;
 		}
 	} else {
 		mvi	DINDEX, HADDR;
@@ -491,30 +490,63 @@
 
 		call	dma_finish;
 
-		/*
-		 * Copy data from FIFO into SCB data pointer and data count.
-		 * This assumes that the SG segments are of the form:
-		 * struct ahc_dma_seg {
-		 *	u_int32_t	addr;	four bytes, little-endian order
-		 *	u_int32_t	len;	four bytes, little endian order
-		 * };
-		 */
-		mvi	HADDR	call dfdat_in_7;
+/*
+ * Copy data from FIFO into SCB data pointer and data count.
+ * This assumes that the SG segments are of the form:
+ * struct ahc_dma_seg {
+ *	u_int32_t	addr;	four bytes, little-endian order
+ *	u_int32_t	len;	four bytes, little endian order
+ * };
+ */
+ 		mvi	DINDEX, HADDR;
+		call	dfdat_in_7;
 		call	set_stcnt_from_hcnt;
 	}
-
 /* Advance the SG pointer */
-	clr	A;			/* add sizeof(struct scatter) */
+	clr	A;		/* add sizeof(struct scatter) */
 	add	SG_NEXT[0],SG_SIZEOF;
 	adc	SG_NEXT[1],A;
 
-	test    SSTAT1, REQINIT jz .;
-	test	SSTAT1,PHASEMIS	jz data_phase_loop;
+	if ((p->features & AHC_ULTRA2) != 0) {
+		jmp	data_phase_loop;
+	} else {
+		test    SSTAT1, REQINIT jz .;
+		test	SSTAT1,PHASEMIS	jz data_phase_loop;
+	}
+
 
-/* This drops the last SG segment down to the shadow layer for us */
+/*
+ * We've loaded all of our segments into the preload layer.  Now, we simply
+ * have to wait for it to finish or for us to get a phasemis.  And, since
+ * we'll get a phasemis if we do finish, all we really need to do is wait
+ * for a phasemis then check if we did actually complete all the segments.
+ */
 	if ((p->features & AHC_ULTRA2) != 0) {
-		mov	DFCNTRL, DMAPARAMS;
-		test	SSTAT0, SDONE	jnz .;
+u2_data_phase_finish:
+		test	SSTAT1, PHASEMIS jnz u2_phasemis;
+		test	SG_CACHEPTR, LAST_SEG_DONE jz u2_data_phase_finish;
+		clr	SG_COUNT;
+		test	SSTAT1, REQINIT	jz .;
+		test	SSTAT1, PHASEMIS jz data_phase_loop;
+u2_phasemis:
+		call	ultra2_dmafinish;
+		test	SG_CACHEPTR, LAST_SEG_DONE jnz data_phase_finish;
+		test	SSTAT2, SHVALID jnz u2_fixup_residual;
+		mvi	INTSTAT, SEQ_SG_FIXUP;
+		jmp	data_phase_finish;
+u2_fixup_residual:
+		shr	ARG_1, 2, SG_CACHEPTR;
+u2_phasemis_loop:
+		and	A, 0x3f, SG_COUNT;
+		cmp	ARG_1, A je data_phase_finish;
+/*
+ * Subtract SG_SIZEOF from the SG_NEXT pointer and add 1 to the SG_COUNT
+ */
+ 		clr	A;
+		add	SG_NEXT[0], -SG_SIZEOF;
+		adc	SG_NEXT[1], 0xff;
+		inc	SG_COUNT;
+		jmp	u2_phasemis_loop;
 	}
 
 data_phase_finish:
@@ -523,64 +555,83 @@
  * We use STCNT instead of HCNT, since it's a reflection of how many bytes 
  * were transferred on the SCSI (as opposed to the host) bus.
  */
-	if ((p->features & AHC_ULTRA2) != 0) {
-		call	ultra2_dmafinish;
-	}
-	if ((p->features & AHC_ULTRA2) == 0) {
-		if ((p->features & AHC_CMD_CHAN) != 0) {
-			bmov    SCB_RESID_DCNT, STCNT, 3;
-			mov	SCB_RESID_SGCNT, SG_COUNT;
-		} else {
-			mov	SCB_RESID_DCNT[0],STCNT[0];
-			mov	SCB_RESID_DCNT[1],STCNT[1];
-			mov	SCB_RESID_DCNT[2],STCNT[2];
-			mov	SCB_RESID_SGCNT, SG_COUNT;
+	if ((p->features & AHC_CMD_CHAN) != 0) {
+		bmov    SCB_RESID_DCNT, STCNT, 3;
+		mov	SCB_RESID_SGCNT, SG_COUNT;
+		if ((p->features & AHC_ULTRA2) != 0) {
+			or	SXFRCTL0, CLRSTCNT|CLRCHN;
 		}
+	} else {
+		mov	SCB_RESID_DCNT[0],STCNT[0];
+		mov	SCB_RESID_DCNT[1],STCNT[1];
+		mov	SCB_RESID_DCNT[2],STCNT[2];
+		mov	SCB_RESID_SGCNT, SG_COUNT;
 	}
 
 	jmp	ITloop;
 
 data_phase_overrun:
-	if ((p->features & AHC_ULTRA2) != 0) {
-		call	ultra2_dmafinish;
-	}
 /*
  * Turn off BITBUCKET mode and notify the host
  */
+	if ((p->features & AHC_ULTRA2) != 0) {
+/*
+ * Wait for the target to quit transferring data on the SCSI bus
+ */
+ 		test	SSTAT1, PHASEMIS jz .;
+		call	ultra2_dmafinish;
+	}
 	and	SXFRCTL1, ~BITBUCKET;
 	mvi	INTSTAT,DATA_OVERRUN;
 	jmp	ITloop;
 
-ultra2_dmafinish:
+
+
+
+/*
+ * Actually turn off the DMA hardware, save our current position into the
+ * proper residual variables, wait for the next REQ signal, then jump to
+ * the ITloop.  Jumping to the ITloop ensures that if we happen to get
+ * brought into the data phase again (or are still in it after our last
+ * segment) that we will properly signal an overrun to the kernel.
+ */
 	if ((p->features & AHC_ULTRA2) != 0) {
+ultra2_dmafinish:
 		test	DFCNTRL, DIRECTION jnz ultra2_dmahalt;
 		and	DFCNTRL, ~SCSIEN;
 		test	DFCNTRL, SCSIEN jnz .;
+		if ((p->bugs & AHC_BUG_AUTOFLUSH) != 0) {
+			or	DFCNTRL, FIFOFLUSH;
+		}
 ultra2_dmafifoflush:
-		or	DFCNTRL, FIFOFLUSH;
-		test	DFSTATUS, FIFOEMP jz . - 1;
-		/*
-		 * hardware bug alert!  This needless set of jumps is to
-		 * protect against a FIFOEMP status bit glitch in the
-		 * silicon.
-		 */
-		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
-		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
-		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
-		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+		if ((p->bugs & AHC_BUG_AUTOFLUSH) != 0) {
+			/*
+			 * hardware bug alert!  This needless set of jumps
+			 * works around a glitch in the silicon.  When the
+			 * PCI DMA fifo goes empty, but there is still SCSI
+			 * data to be flushed into the PCI DMA fifo (and from
+			 * there on into main memory), the FIFOEMP bit will
+			 * come on between the time when the PCI DMA buffer
+			 * went empty and the next bit of data is copied from
+			 * the SCSI fifo into the PCI fifo.  It should only
+			 * come on when both FIFOs (meaning the entire FIFO
+			 * chain) are emtpy.  Since it can take up to 4 cycles
+			 * for new data to be copied from the SCSI fifo into
+			 * the PCI fifo, testing for FIFOEMP status for 4
+			 * extra times gives the needed time for any
+			 * remaining SCSI fifo data to be put in the PCI fifo
+			 * before we declare it *truly* empty.
+			 */
+			test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+			test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+			test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+			test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+		}
 		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
 		test	DFSTATUS, MREQPEND	jnz .;
 ultra2_dmahalt:
-		test	SCSIOFFSET, 0x7f	jnz ultra2_shutdown;
-ultra2_await_nreq:
-		test	SCSISIGI, REQI	jz ultra2_shutdown;
-		test	SSTAT1, (PHASEMIS|REQINIT)	jz ultra2_await_nreq;
-ultra2_shutdown:
 		and     DFCNTRL, ~(HDMAEN|SCSIEN);
 		test	DFCNTRL, (HDMAEN|SCSIEN) jnz .;
-		bmov	SCB_RESID_DCNT, STCNT, 3;
-		mov	SCB_RESID_SGCNT, SG_COUNT;
-		or	SXFRCTL0, CLRSTCNT|CLRCHN;
 		ret;
 	}
 
@@ -1021,6 +1072,7 @@
 inb_last:
 	mov	NONE,SCSIDATL ret;		/*dummy read from latch to ACK*/
 
+	
 mesgin_phasemis:
 /*
  * We expected to receive another byte, but the target changed phase
@@ -1080,7 +1132,9 @@
 	 * to drain the data fifo until there is space for the input
 	 * latch to drain and HDMAEN de-asserts.
 	 */
-	mov	NONE, DFDAT;
+	if ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0) {
+		mov	NONE, DFDAT;
+	}
 	test	DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt;
 }
 return:
@@ -1306,20 +1360,30 @@
 		cmp	CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .;
 		jmp	dma_scb_finish;
 dma_scb_tohost:
-		if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
+		if ((p->features & AHC_ULTRA2) == 0) {
 			mvi	CCSCBCTL, CCSCBRESET;
 			bmov	CCSCBRAM, SCB_CONTROL, 32;
 			or	CCSCBCTL, CCSCBEN|CCSCBRESET;
 			test	CCSCBCTL, CCSCBDONE jz .;
-		} else {
-			mvi	CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET;
-			cmp	CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .;
+		}
+		if ((p->features & AHC_ULTRA2) != 0) {
+			if ((p->bugs & AHC_BUG_SCBCHAN_UPLOAD) != 0) {
+				mvi     CCSCBCTL, CCARREN|CCSCBRESET;
+				cmp     CCSCBCTL, ARRDONE|CCARREN jne .;
+                        	mvi     CCHCNT, 32;
+				mvi     CCSCBCTL, CCSCBEN|CCSCBRESET;
+				cmp     CCSCBCTL, CCSCBDONE|CCSCBEN jne .;
+			} else {
+				mvi	CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET;
+				cmp	CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .;
+			}
 		}
 dma_scb_finish:
 		clr	CCSCBCTL;
 		test	CCSCBCTL, CCARREN|CCSCBEN jnz .;
 		ret;
-	} else {
+	}
+	if ((p->features & AHC_CMD_CHAN) == 0) {
 		mvi	DINDEX, HADDR;
 		mvi	HSCB_ADDR call set_32byte_addr;
 		mvi	HCNT[0], 32;
@@ -1342,17 +1406,81 @@
 		mov	DFDAT,SINDIR;
 		cmp	SINDEX, A jne copy_scb_tofifo_loop;
 		or	DFCNTRL, HDMAEN|FIFOFLUSH;
+		jmp	dma_finish;
 dma_scb_fromhost:
-		call	dma_finish;
-		/* If we were putting the SCB, we are done */
-		test	DMAPARAMS, DIRECTION	jz	return;
-		mvi	SCB_CONTROL  call dfdat_in_7;
-		call	dfdat_in_7_continued;
-		call	dfdat_in_7_continued;
-		jmp	dfdat_in_7_continued;
+		mvi	DINDEX, SCB_CONTROL;
+		if ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0) {
+			/*
+			 * Set the A to -24.  It it hits 0, then we let
+			 * our code fall through to dfdat_in_8 to complete
+			 * the last of the copy.
+			 *
+			 * Also, things happen 8 bytes at a time in this
+			 * case, so we may need to drain the fifo at most
+			 * 3 times to keep things flowing
+			 */
+			mvi	A, -24;
+dma_scb_hang_fifo:
+			/* Wait for the first bit of data to hit the fifo */
+			test	DFSTATUS, FIFOEMP jnz .;
+dma_scb_hang_wait:
+			/* OK, now they've started to transfer into the fifo,
+			 * so wait for them to stop trying to transfer any
+			 * more data.
+			 */
+			test	DFSTATUS, MREQPEND jnz .;
+			/*
+			 * OK, they started, then they stopped, now see if they
+			 * managed to complete the job before stopping.  Try
+			 * it multiple times to give the chip a few cycles to
+			 * set the flag if it did complete.
+			 */
+			test	DFSTATUS, HDONE jnz dma_scb_hang_dma_done;
+			test	DFSTATUS, HDONE jnz dma_scb_hang_dma_done;
+			test	DFSTATUS, HDONE jnz dma_scb_hang_dma_done;
+			/*
+			 * Too bad, the chip didn't complete the DMA, but there
+			 * aren't any more memory requests pending, so that
+			 * means it stopped part way through and hung.  That's
+			 * our bug, so now we drain what data there is in the
+			 * fifo in order to get things going again.
+			 */
+dma_scb_hang_empty_fifo:
+			call	dfdat_in_8;
+			add	A, 8;
+			add	SINDEX, A, HCNT;
+			/*
+			 * If there are another 8 bytes of data waiting in the
+			 * fifo, then the carry bit will be set as a result
+			 * of the above add command (unless A is non-negative,
+			 * in which case the carry bit won't be set).
+			 */
+			jc	dma_scb_hang_empty_fifo;
+			/*
+			 * We've emptied the fifo now, but we wouldn't have got
+			 * here if the memory transfer hadn't stopped part way
+			 * through, so go back up to the beginning of the
+			 * loop and start over.  When it succeeds in getting
+			 * all the data down, HDONE will be set and we'll
+			 * jump to the code just below here.
+			 */
+			jmp	dma_scb_hang_fifo;
+dma_scb_hang_dma_done:
+			and	DFCNTRL, ~HDMAEN;
+			test	DFCNTRL, HDMAEN jnz .;
+			call	dfdat_in_8;
+			add	A, 8;
+			cmp	A, 8 jne . - 2;
+			ret;
+		} else {
+			call	dma_finish;
+			call	dfdat_in_8;
+			call	dfdat_in_8;
+			call	dfdat_in_8;
+		}
+dfdat_in_8:
+		mov	DINDIR,DFDAT;
 dfdat_in_7:
-		mov     DINDEX,SINDEX;
-dfdat_in_7_continued:
 		mov	DINDIR,DFDAT;
 		mov	DINDIR,DFDAT;
 		mov	DINDIR,DFDAT;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx/aic7xxx_proc.c linux.19p18/drivers/scsi/aic7xxx/aic7xxx_proc.c
--- linux.vanilla/drivers/scsi/aic7xxx/aic7xxx_proc.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/scsi/aic7xxx/aic7xxx_proc.c	Mon Feb 12 14:57:23 2001
@@ -0,0 +1,414 @@
+/*+M*************************************************************************
+ * Adaptec AIC7xxx device driver proc support for Linux.
+ *
+ * Copyright (c) 1995, 1996 Dean W. Gehnert
+ *
+ * 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, 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; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * ----------------------------------------------------------------
+ *  o Modified from the EATA-DMA /proc support.
+ *  o Additional support for device block statistics provided by
+ *    Matthew Jacob.
+ *  o Correction of overflow by Heinz Mauelshagen
+ *  o Adittional corrections by Doug Ledford
+ *
+ *  Dean W. Gehnert, deang@teleport.com, 05/01/96
+ *
+ *  $Id: aic7xxx_proc.c,v 4.1 1997/06/97 08:23:42 deang Exp $
+ *-M*************************************************************************/
+
+#include <linux/config.h>
+
+#define	BLS	(&aic7xxx_buffer[size])
+#define HDRB \
+"             < 2K      2K+     4K+     8K+    16K+    32K+    64K+   128K+"
+
+#ifdef PROC_DEBUG
+extern int vsprintf(char *, const char *, va_list);
+
+static void
+proc_debug(const char *fmt, ...)
+{
+  va_list ap;
+  char buf[256];
+
+  va_start(ap, fmt);
+  vsprintf(buf, fmt, ap);
+  printk(buf);
+  va_end(ap);
+}
+#else /* PROC_DEBUG */
+#  define proc_debug(fmt, args...)
+#endif /* PROC_DEBUG */
+
+static int aic7xxx_buffer_size = 0;
+static char *aic7xxx_buffer = NULL;
+
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_set_info
+ *
+ * Description:
+ *   Set parameters for the driver from the /proc filesystem.
+ *-F*************************************************************************/
+int
+aic7xxx_set_info(char *buffer, int length, struct Scsi_Host *HBAptr)
+{
+  proc_debug("aic7xxx_set_info(): %s\n", buffer);
+  return (-ENOSYS);  /* Currently this is a no-op */
+}
+
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_proc_info
+ *
+ * Description:
+ *   Return information to handle /proc support for the driver.
+ *-F*************************************************************************/
+int
+aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length, 
+                    int hostno, int inout)
+{
+  struct Scsi_Host *HBAptr;
+  struct aic7xxx_host *p;
+  int    size = 0;
+  unsigned char i;
+  struct aic7xxx_xferstats *sp;
+  unsigned char target;
+
+  HBAptr = NULL;
+
+  for(p=first_aic7xxx; p->host->host_no != hostno; p=p->next)
+    ;
+
+  if (!p)
+  {
+    size += sprintf(buffer, "Can't find adapter for host number %d\n", hostno);
+    if (size > length)
+    {
+      return (size);
+    }
+    else
+    {
+      return (length);
+    }
+  }
+
+  HBAptr = p->host;
+
+  if (inout == TRUE) /* Has data been written to the file? */ 
+  {
+    return (aic7xxx_set_info(buffer, length, HBAptr));
+  }
+
+  p = (struct aic7xxx_host *) HBAptr->hostdata;
+
+  /*
+   * It takes roughly 1K of space to hold all relevant card info, not
+   * counting any proc stats, so we start out with a 1.5k buffer size and
+   * if proc_stats is defined, then we sweep the stats structure to see
+   * how many drives we will be printing out for and add 384 bytes per
+   * device with active stats.
+   *
+   * Hmmmm...that 1.5k seems to keep growing as items get added so they
+   * can be easily viewed for debugging purposes.  So, we bumped that
+   * 1.5k to 4k so we can quit having to bump it all the time.
+   */
+
+  size = 4096;
+  for (target = 0; target < MAX_TARGETS; target++)
+  {
+    if (p->dev_flags[target] & DEVICE_PRESENT)
+#ifdef AIC7XXX_PROC_STATS
+      size += 512;
+#else
+      size += 256;
+#endif
+  }
+  if (aic7xxx_buffer_size != size)
+  {
+    if (aic7xxx_buffer != NULL) 
+    {
+      kfree(aic7xxx_buffer);
+      aic7xxx_buffer_size = 0;
+    }
+    aic7xxx_buffer = kmalloc(size, GFP_KERNEL);
+  }
+  if (aic7xxx_buffer == NULL)
+  {
+    size = sprintf(buffer, "AIC7xxx - kmalloc error at line %d\n",
+        __LINE__);
+    return size;
+  }
+  aic7xxx_buffer_size = size;
+
+  size = 0;
+  size += sprintf(BLS, "Adaptec AIC7xxx driver version: ");
+  size += sprintf(BLS, "%s/", AIC7XXX_C_VERSION);
+  size += sprintf(BLS, "%s", AIC7XXX_H_VERSION);
+  size += sprintf(BLS, "\n");
+  size += sprintf(BLS, "Compile Options:\n");
+#ifdef CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
+  size += sprintf(BLS, "  TCQ Enabled By Default : Enabled\n");
+#else
+  size += sprintf(BLS, "  TCQ Enabled By Default : Disabled\n");
+#endif
+#ifdef AIC7XXX_PROC_STATS
+  size += sprintf(BLS, "  AIC7XXX_PROC_STATS     : Enabled\n");
+#else
+  size += sprintf(BLS, "  AIC7XXX_PROC_STATS     : Disabled\n");
+#endif
+  size += sprintf(BLS, "  AIC7XXX_RESET_DELAY    : %d\n", AIC7XXX_RESET_DELAY);
+  size += sprintf(BLS, "\n");
+  size += sprintf(BLS, "Adapter Configuration:\n");
+  size += sprintf(BLS, "           SCSI Adapter: %s\n",
+      board_names[p->board_name_index]);
+  if (p->flags & AHC_TWIN)
+    size += sprintf(BLS, "                         Twin Channel Controller ");
+  else
+  {
+    char *channel = "";
+    char *ultra = "";
+    char *wide = "Narrow ";
+    if (p->flags & AHC_MULTI_CHANNEL)
+    {
+      channel = " Channel A";
+      if (p->flags & (AHC_CHNLB|AHC_CHNLC))
+        channel = (p->flags & AHC_CHNLB) ? " Channel B" : " Channel C";
+    }
+    if (p->features & AHC_WIDE)
+      wide = "Wide ";
+    if (p->features & AHC_ULTRA3)
+    {
+      switch(p->chip & AHC_CHIPID_MASK)
+      {
+        case AHC_AIC7892:
+        case AHC_AIC7899:
+          ultra = "Ultra-160/m LVD/SE ";
+          break;
+        default:
+          ultra = "Ultra-3 LVD/SE ";
+          break;
+      }
+    }
+    else if (p->features & AHC_ULTRA2)
+      ultra = "Ultra-2 LVD/SE ";
+    else if (p->features & AHC_ULTRA)
+      ultra = "Ultra ";
+    size += sprintf(BLS, "                           %s%sController%s ",
+      ultra, wide, channel);
+  }
+  switch(p->chip & ~AHC_CHIPID_MASK)
+  {
+    case AHC_VL:
+      size += sprintf(BLS, "at VLB slot %d\n", p->pci_device_fn);
+      break;
+    case AHC_EISA:
+      size += sprintf(BLS, "at EISA slot %d\n", p->pci_device_fn);
+      break;
+    default:
+      size += sprintf(BLS, "at PCI %d/%d/%d\n", p->pci_bus,
+        PCI_SLOT(p->pci_device_fn), PCI_FUNC(p->pci_device_fn));
+      break;
+  }
+  if( !(p->maddr) )
+  {
+    size += sprintf(BLS, "    Programmed I/O Base: %lx\n", p->base);
+  }
+  else
+  {
+    size += sprintf(BLS, "    PCI MMAPed I/O Base: 0x%lx\n", p->mbase);
+  }
+  if( (p->chip & (AHC_VL | AHC_EISA)) )
+  {
+    size += sprintf(BLS, "    BIOS Memory Address: 0x%08x\n", p->bios_address);
+  }
+  size += sprintf(BLS, " Adapter SEEPROM Config: %s\n",
+          (p->flags & AHC_SEEPROM_FOUND) ? "SEEPROM found and used." :
+         ((p->flags & AHC_USEDEFAULTS) ? "SEEPROM not found, using defaults." :
+           "SEEPROM not found, using leftover BIOS values.") );
+  size += sprintf(BLS, "      Adaptec SCSI BIOS: %s\n",
+          (p->flags & AHC_BIOS_ENABLED) ? "Enabled" : "Disabled");
+  size += sprintf(BLS, "                    IRQ: %d\n", HBAptr->irq);
+  size += sprintf(BLS, "                   SCBs: Active %d, Max Active %d,\n",
+            p->activescbs, p->max_activescbs);
+  size += sprintf(BLS, "                         Allocated %d, HW %d, "
+            "Page %d\n", p->scb_data->numscbs, p->scb_data->maxhscbs,
+            p->scb_data->maxscbs);
+  if (p->flags & AHC_EXTERNAL_SRAM)
+    size += sprintf(BLS, "                         Using External SCB SRAM\n");
+  size += sprintf(BLS, "             Interrupts: %ld", p->isr_count);
+  if (p->chip & AHC_EISA)
+  {
+    size += sprintf(BLS, " %s\n",
+        (p->pause & IRQMS) ? "(Level Sensitive)" : "(Edge Triggered)");
+  }
+  else
+  {
+    size += sprintf(BLS, "\n");
+  }
+  size += sprintf(BLS, "      BIOS Control Word: 0x%04x\n",
+            p->bios_control);
+  size += sprintf(BLS, "   Adapter Control Word: 0x%04x\n",
+            p->adapter_control);
+  size += sprintf(BLS, "   Extended Translation: %sabled\n",
+      (p->flags & AHC_EXTEND_TRANS_A) ? "En" : "Dis");
+  size += sprintf(BLS, "Disconnect Enable Flags: 0x%04x\n", p->discenable);
+  if (p->features & (AHC_ULTRA | AHC_ULTRA2))
+  {
+    size += sprintf(BLS, "     Ultra Enable Flags: 0x%04x\n", p->ultraenb);
+  }
+  size += sprintf(BLS, " Tag Queue Enable Flags: 0x%04x\n", p->tagenable);
+  size += sprintf(BLS, "Ordered Queue Tag Flags: 0x%04x\n", p->orderedtag);
+  size += sprintf(BLS, "Default Tag Queue Depth: %d\n", AIC7XXX_CMDS_PER_DEVICE);
+  size += sprintf(BLS, "    Tagged Queue By Device array for aic7xxx host "
+                       "instance %d:\n", p->instance);
+  size += sprintf(BLS, "      {");
+  for(i=0; i < (MAX_TARGETS - 1); i++)
+    size += sprintf(BLS, "%d,",aic7xxx_tag_info[p->instance].tag_commands[i]);
+  size += sprintf(BLS, "%d}\n",aic7xxx_tag_info[p->instance].tag_commands[i]);
+  size += sprintf(BLS, "    Actual queue depth per device for aic7xxx host "
+                       "instance %d:\n", p->instance);
+  size += sprintf(BLS, "      {");
+  for(i=0; i < (MAX_TARGETS - 1); i++)
+    size += sprintf(BLS, "%d,", p->dev_max_queue_depth[i]);
+  size += sprintf(BLS, "%d}\n", p->dev_max_queue_depth[i]);
+
+  size += sprintf(BLS, "\n");
+  size += sprintf(BLS, "Statistics:\n\n");
+  for (target = 0; target < MAX_TARGETS; target++)
+  {
+    sp = &p->stats[target];
+    if ((p->dev_flags[target] & DEVICE_PRESENT) == 0)
+    {
+      continue;
+    }
+    if (p->features & AHC_TWIN)
+    {
+      size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
+          p->host_no, (target >> 3), (target & 0x7), 0);
+    }
+    else
+    {
+      size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
+          p->host_no, 0, target, 0);
+    }
+    size += sprintf(BLS, "  Device using %s/%s",
+          (p->transinfo[target].cur_width == MSG_EXT_WDTR_BUS_16_BIT) ?
+          "Wide" : "Narrow",
+          (p->transinfo[target].cur_offset != 0) ?
+          "Sync transfers at " : "Async transfers.\n" );
+    if (p->transinfo[target].cur_offset != 0)
+    {
+      struct aic7xxx_syncrate *sync_rate;
+      unsigned char options = p->transinfo[target].cur_options;
+      int period = p->transinfo[target].cur_period;
+      int rate = (p->transinfo[target].cur_width ==
+                  MSG_EXT_WDTR_BUS_16_BIT) ? 1 : 0;
+
+      sync_rate = aic7xxx_find_syncrate(p, &period, 0, &options);
+      if (sync_rate != NULL)
+      {
+        size += sprintf(BLS, "%s MByte/sec, offset %d\n",
+                        sync_rate->rate[rate],
+                        p->transinfo[target].cur_offset );
+      }
+      else
+      {
+        size += sprintf(BLS, "3.3 MByte/sec, offset %d\n",
+                        p->transinfo[target].cur_offset );
+      }
+    }
+    size += sprintf(BLS, "  Transinfo settings: ");
+    size += sprintf(BLS, "current(%d/%d/%d/%d), ",
+                    p->transinfo[target].cur_period,
+                    p->transinfo[target].cur_offset,
+                    p->transinfo[target].cur_width,
+                    p->transinfo[target].cur_options);
+    size += sprintf(BLS, "goal(%d/%d/%d/%d), ",
+                    p->transinfo[target].goal_period,
+                    p->transinfo[target].goal_offset,
+                    p->transinfo[target].goal_width,
+                    p->transinfo[target].goal_options);
+    size += sprintf(BLS, "user(%d/%d/%d/%d)\n",
+                    p->transinfo[target].user_period,
+                    p->transinfo[target].user_offset,
+                    p->transinfo[target].user_width,
+                    p->transinfo[target].user_options);
+#ifdef AIC7XXX_PROC_STATS
+    size += sprintf(BLS, "  Total transfers %ld (%ld reads and %ld writes)\n",
+        sp->r_total + sp->w_total, sp->r_total, sp->w_total);
+    size += sprintf(BLS, "%s\n", HDRB);
+    size += sprintf(BLS, "   Reads:");
+    for (i = 0; i < NUMBER(sp->r_bins); i++)
+    {
+      size += sprintf(BLS, " %7ld", sp->r_bins[i]);
+    }
+    size += sprintf(BLS, "\n");
+    size += sprintf(BLS, "  Writes:");
+    for (i = 0; i < NUMBER(sp->w_bins); i++)
+    {
+      size += sprintf(BLS, " %7ld", sp->w_bins[i]);
+    }
+    size += sprintf(BLS, "\n");
+#else
+    size += sprintf(BLS, "  Total transfers %ld (%ld reads and %ld writes)\n",
+        sp->r_total + sp->w_total, sp->r_total, sp->w_total);
+#endif /* AIC7XXX_PROC_STATS */
+    size += sprintf(BLS, "\n\n");
+  }
+
+  if (size >= aic7xxx_buffer_size)
+  {
+    printk(KERN_WARNING "aic7xxx: Overflow in aic7xxx_proc.c\n");
+  }
+
+  if (offset > size - 1)
+  {
+    kfree(aic7xxx_buffer);
+    aic7xxx_buffer = NULL;
+    aic7xxx_buffer_size = length = 0;
+    *start = NULL;
+  }
+  else
+  {
+    *start = buffer;
+    length = MIN(length, size - offset);
+    memcpy(buffer, &aic7xxx_buffer[offset], length);
+  }
+
+  return (length);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 2
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -2
+ * c-argdecl-indent: 2
+ * c-label-offset: -2
+ * c-continued-statement-offset: 2
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx/aic7xxx_reg.h linux.19p18/drivers/scsi/aic7xxx/aic7xxx_reg.h
--- linux.vanilla/drivers/scsi/aic7xxx/aic7xxx_reg.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/scsi/aic7xxx/aic7xxx_reg.h	Mon Feb 12 14:57:23 2001
@@ -0,0 +1,629 @@
+/*
+  * DO NOT EDIT - This file is automatically generated.
+  */
+
+#define	SCSISEQ         		0x00
+#define		TEMODE          	0x80
+#define		ENSELO          	0x40
+#define		ENSELI          	0x20
+#define		ENRSELI         	0x10
+#define		ENAUTOATNO      	0x08
+#define		ENAUTOATNI      	0x04
+#define		ENAUTOATNP      	0x02
+#define		SCSIRSTO        	0x01
+
+#define	SXFRCTL0        		0x01
+#define		DFON            	0x80
+#define		DFPEXP          	0x40
+#define		FAST20          	0x20
+#define		CLRSTCNT        	0x10
+#define		SPIOEN          	0x08
+#define		SCAMEN          	0x04
+#define		CLRCHN          	0x02
+
+#define	SXFRCTL1        		0x02
+#define		BITBUCKET       	0x80
+#define		SWRAPEN         	0x40
+#define		ENSPCHK         	0x20
+#define		STIMESEL        	0x18
+#define		ENSTIMER        	0x04
+#define		ACTNEGEN        	0x02
+#define		STPWEN          	0x01
+
+#define	SCSISIGO        		0x03
+#define		CDO             	0x80
+#define		IOO             	0x40
+#define		MSGO            	0x20
+#define		ATNO            	0x10
+#define		SELO            	0x08
+#define		BSYO            	0x04
+#define		REQO            	0x02
+#define		ACKO            	0x01
+
+#define	SCSISIGI        		0x03
+#define		ATNI            	0x10
+#define		SELI            	0x08
+#define		BSYI            	0x04
+#define		REQI            	0x02
+#define		ACKI            	0x01
+
+#define	SCSIRATE        		0x04
+#define		WIDEXFER        	0x80
+#define		SXFR_ULTRA2     	0x7f
+#define		SXFR            	0x70
+#define		SOFS            	0x0f
+
+#define	SCSIID          		0x05
+#define	SCSIOFFSET      		0x05
+#define		SOFS_ULTRA2     	0x7f
+
+#define	SCSIDATL        		0x06
+
+#define	SCSIDATH        		0x07
+
+#define	STCNT           		0x08
+
+#define	OPTIONMODE      		0x08
+#define		AUTORATEEN      	0x80
+#define		AUTOACKEN       	0x40
+#define		ATNMGMNTEN      	0x20
+#define		BUSFREEREV      	0x10
+#define		EXPPHASEDIS     	0x08
+#define		SCSIDATL_IMGEN  	0x04
+#define		AUTO_MSGOUT_DE  	0x02
+#define		DIS_MSGIN_DUALEDGE	0x01
+
+#define	CLRSINT0        		0x0b
+#define		CLRSELDO        	0x40
+#define		CLRSELDI        	0x20
+#define		CLRSELINGO      	0x10
+#define		CLRSWRAP        	0x08
+#define		CLRSPIORDY      	0x02
+
+#define	SSTAT0          		0x0b
+#define		TARGET          	0x80
+#define		SELDO           	0x40
+#define		SELDI           	0x20
+#define		SELINGO         	0x10
+#define		IOERR           	0x08
+#define		SWRAP           	0x08
+#define		SDONE           	0x04
+#define		SPIORDY         	0x02
+#define		DMADONE         	0x01
+
+#define	CLRSINT1        		0x0c
+#define		CLRSELTIMEO     	0x80
+#define		CLRATNO         	0x40
+#define		CLRSCSIRSTI     	0x20
+#define		CLRBUSFREE      	0x08
+#define		CLRSCSIPERR     	0x04
+#define		CLRPHASECHG     	0x02
+#define		CLRREQINIT      	0x01
+
+#define	SSTAT1          		0x0c
+#define		SELTO           	0x80
+#define		ATNTARG         	0x40
+#define		SCSIRSTI        	0x20
+#define		PHASEMIS        	0x10
+#define		BUSFREE         	0x08
+#define		SCSIPERR        	0x04
+#define		PHASECHG        	0x02
+#define		REQINIT         	0x01
+
+#define	SSTAT2          		0x0d
+#define		OVERRUN         	0x80
+#define		SHVALID         	0x40
+#define		WIDE_RES        	0x20
+#define		SFCNT           	0x1f
+#define		EXP_ACTIVE      	0x10
+#define		CRCVALERR       	0x08
+#define		CRCENDERR       	0x04
+#define		CRCREQERR       	0x02
+#define		DUAL_EDGE_ERROR 	0x01
+
+#define	SSTAT3          		0x0e
+#define		SCSICNT         	0xf0
+#define		OFFCNT          	0x0f
+
+#define	SCSIID_ULTRA2   		0x0f
+#define		OID             	0x0f
+
+#define	SIMODE0         		0x10
+#define		ENSELDO         	0x40
+#define		ENSELDI         	0x20
+#define		ENSELINGO       	0x10
+#define		ENIOERR         	0x08
+#define		ENSWRAP         	0x08
+#define		ENSDONE         	0x04
+#define		ENSPIORDY       	0x02
+#define		ENDMADONE       	0x01
+
+#define	SIMODE1         		0x11
+#define		ENSELTIMO       	0x80
+#define		ENATNTARG       	0x40
+#define		ENSCSIRST       	0x20
+#define		ENPHASEMIS      	0x10
+#define		ENBUSFREE       	0x08
+#define		ENSCSIPERR      	0x04
+#define		ENPHASECHG      	0x02
+#define		ENREQINIT       	0x01
+
+#define	SCSIBUSL        		0x12
+
+#define	SCSIBUSH        		0x13
+
+#define	SHADDR          		0x14
+
+#define	SELTIMER        		0x18
+#define		STAGE6          	0x20
+#define		STAGE5          	0x10
+#define		STAGE4          	0x08
+#define		STAGE3          	0x04
+#define		STAGE2          	0x02
+#define		STAGE1          	0x01
+
+#define	SELID           		0x19
+#define		SELID_MASK      	0xf0
+#define		ONEBIT          	0x08
+
+#define	SPIOCAP         		0x1b
+#define		SOFT1           	0x80
+#define		SOFT0           	0x40
+#define		SOFTCMDEN       	0x20
+#define		HAS_BRDCTL      	0x10
+#define		SEEPROM         	0x08
+#define		EEPROM          	0x04
+#define		ROM             	0x02
+#define		SSPIOCPS        	0x01
+
+#define	BRDCTL          		0x1d
+#define		BRDDAT7         	0x80
+#define		BRDDAT6         	0x40
+#define		BRDDAT5         	0x20
+#define		BRDDAT4         	0x10
+#define		BRDSTB          	0x10
+#define		BRDCS           	0x08
+#define		BRDDAT3         	0x08
+#define		BRDDAT2         	0x04
+#define		BRDRW           	0x04
+#define		BRDRW_ULTRA2    	0x02
+#define		BRDCTL1         	0x02
+#define		BRDSTB_ULTRA2   	0x01
+#define		BRDCTL0         	0x01
+
+#define	SEECTL          		0x1e
+#define		EXTARBACK       	0x80
+#define		EXTARBREQ       	0x40
+#define		SEEMS           	0x20
+#define		SEERDY          	0x10
+#define		SEECS           	0x08
+#define		SEECK           	0x04
+#define		SEEDO           	0x02
+#define		SEEDI           	0x01
+
+#define	SBLKCTL         		0x1f
+#define		DIAGLEDEN       	0x80
+#define		DIAGLEDON       	0x40
+#define		AUTOFLUSHDIS    	0x20
+#define		ENAB40          	0x08
+#define		ENAB20          	0x04
+#define		SELWIDE         	0x02
+#define		XCVR            	0x01
+
+#define	SRAM_BASE       		0x20
+
+#define	TARG_SCSIRATE   		0x20
+
+#define	ULTRA_ENB       		0x30
+
+#define	DISC_DSB        		0x32
+
+#define	MSG_OUT         		0x34
+
+#define	DMAPARAMS       		0x35
+#define		PRELOADEN       	0x80
+#define		WIDEODD         	0x40
+#define		SCSIEN          	0x20
+#define		SDMAENACK       	0x10
+#define		SDMAEN          	0x10
+#define		HDMAEN          	0x08
+#define		HDMAENACK       	0x08
+#define		DIRECTION       	0x04
+#define		FIFOFLUSH       	0x02
+#define		FIFORESET       	0x01
+
+#define	SEQ_FLAGS       		0x36
+#define		IDENTIFY_SEEN   	0x80
+#define		SCBPTR_VALID    	0x20
+#define		DPHASE          	0x10
+#define		AMTARGET        	0x08
+#define		WIDE_BUS        	0x02
+#define		TWIN_BUS        	0x01
+
+#define	SAVED_TCL       		0x37
+
+#define	SG_COUNT        		0x38
+
+#define	SG_NEXT         		0x39
+
+#define	LASTPHASE       		0x3d
+#define		P_MESGIN        	0xe0
+#define		PHASE_MASK      	0xe0
+#define		P_STATUS        	0xc0
+#define		P_MESGOUT       	0xa0
+#define		P_COMMAND       	0x80
+#define		CDI             	0x80
+#define		IOI             	0x40
+#define		P_DATAIN        	0x40
+#define		MSGI            	0x20
+#define		P_BUSFREE       	0x01
+#define		P_DATAOUT       	0x00
+
+#define	WAITING_SCBH    		0x3e
+
+#define	DISCONNECTED_SCBH		0x3f
+
+#define	FREE_SCBH       		0x40
+
+#define	HSCB_ADDR       		0x41
+
+#define	SCBID_ADDR      		0x45
+
+#define	TMODE_CMDADDR   		0x49
+
+#define	KERNEL_QINPOS   		0x4d
+
+#define	QINPOS          		0x4e
+
+#define	QOUTPOS         		0x4f
+
+#define	TMODE_CMDADDR_NEXT		0x50
+
+#define	ARG_1           		0x51
+#define	RETURN_1        		0x51
+#define		SEND_MSG        	0x80
+#define		SEND_SENSE      	0x40
+#define		SEND_REJ        	0x20
+#define		MSGOUT_PHASEMIS 	0x10
+
+#define	ARG_2           		0x52
+#define	RETURN_2        		0x52
+
+#define	LAST_MSG        		0x53
+
+#define	PREFETCH_CNT    		0x54
+
+#define	SCSICONF        		0x5a
+#define		TERM_ENB        	0x80
+#define		RESET_SCSI      	0x40
+#define		HWSCSIID        	0x0f
+#define		HSCSIID         	0x07
+
+#define	HOSTCONF        		0x5d
+
+#define	HA_274_BIOSCTRL 		0x5f
+#define		BIOSMODE        	0x30
+#define		BIOSDISABLED    	0x30
+#define		CHANNEL_B_PRIMARY	0x08
+
+#define	SEQCTL          		0x60
+#define		PERRORDIS       	0x80
+#define		PAUSEDIS        	0x40
+#define		FAILDIS         	0x20
+#define		FASTMODE        	0x10
+#define		BRKADRINTEN     	0x08
+#define		STEP            	0x04
+#define		SEQRESET        	0x02
+#define		LOADRAM         	0x01
+
+#define	SEQRAM          		0x61
+
+#define	SEQADDR0        		0x62
+
+#define	SEQADDR1        		0x63
+#define		SEQADDR1_MASK   	0x01
+
+#define	ACCUM           		0x64
+
+#define	SINDEX          		0x65
+
+#define	DINDEX          		0x66
+
+#define	ALLONES         		0x69
+
+#define	ALLZEROS        		0x6a
+
+#define	NONE            		0x6a
+
+#define	FLAGS           		0x6b
+#define		ZERO            	0x02
+#define		CARRY           	0x01
+
+#define	SINDIR          		0x6c
+
+#define	DINDIR          		0x6d
+
+#define	FUNCTION1       		0x6e
+
+#define	STACK           		0x6f
+
+#define	TARG_OFFSET     		0x70
+
+#define	BCTL            		0x84
+#define		ACE             	0x08
+#define		ENABLE          	0x01
+
+#define	DSCOMMAND0      		0x84
+#define		INTSCBRAMSEL    	0x08
+#define		RAMPS           	0x04
+#define		USCBSIZE32      	0x02
+#define		CIOPARCKEN      	0x01
+
+#define	DSCOMMAND       		0x84
+#define		CACHETHEN       	0x80
+#define		DPARCKEN        	0x40
+#define		MPARCKEN        	0x20
+#define		EXTREQLCK       	0x10
+
+#define	BUSTIME         		0x85
+#define		BOFF            	0xf0
+#define		BON             	0x0f
+
+#define	BUSSPD          		0x86
+#define		DFTHRSH         	0xc0
+#define		STBOFF          	0x38
+#define		STBON           	0x07
+
+#define	DSPCISTATUS     		0x86
+#define		DFTHRSH_100     	0xc0
+
+#define	HCNTRL          		0x87
+#define		POWRDN          	0x40
+#define		SWINT           	0x10
+#define		IRQMS           	0x08
+#define		PAUSE           	0x04
+#define		INTEN           	0x02
+#define		CHIPRST         	0x01
+#define		CHIPRSTACK      	0x01
+
+#define	HADDR           		0x88
+
+#define	HCNT            		0x8c
+
+#define	SCBPTR          		0x90
+
+#define	INTSTAT         		0x91
+#define		SEQINT_MASK     	0xf1
+#define		DATA_OVERRUN    	0xe1
+#define		MSGIN_PHASEMIS  	0xd1
+#define		TRACEPOINT2     	0xc1
+#define		SEQ_SG_FIXUP    	0xb1
+#define		AWAITING_MSG    	0xa1
+#define		RESIDUAL        	0x81
+#define		BAD_STATUS      	0x71
+#define		REJECT_MSG      	0x61
+#define		WIDE_RESIDUE    	0x51
+#define		EXTENDED_MSG    	0x41
+#define		NO_MATCH        	0x31
+#define		NO_IDENT        	0x21
+#define		SEND_REJECT     	0x11
+#define		INT_PEND        	0x0f
+#define		BRKADRINT       	0x08
+#define		SCSIINT         	0x04
+#define		CMDCMPLT        	0x02
+#define		BAD_PHASE       	0x01
+#define		SEQINT          	0x01
+
+#define	CLRINT          		0x92
+#define		CLRPARERR       	0x10
+#define		CLRBRKADRINT    	0x08
+#define		CLRSCSIINT      	0x04
+#define		CLRCMDINT       	0x02
+#define		CLRSEQINT       	0x01
+
+#define	ERROR           		0x92
+#define		CIOPARERR       	0x80
+#define		PCIERRSTAT      	0x40
+#define		MPARERR         	0x20
+#define		DPARERR         	0x10
+#define		SQPARERR        	0x08
+#define		ILLOPCODE       	0x04
+#define		DSCTMOUT        	0x02
+#define		ILLSADDR        	0x02
+#define		ILLHADDR        	0x01
+
+#define	DFCNTRL         		0x93
+
+#define	DFSTATUS        		0x94
+#define		PRELOAD_AVAIL   	0x80
+#define		DWORDEMP        	0x20
+#define		MREQPEND        	0x10
+#define		HDONE           	0x08
+#define		DFTHRESH        	0x04
+#define		FIFOFULL        	0x02
+#define		FIFOEMP         	0x01
+
+#define	DFDAT           		0x99
+
+#define	SCBCNT          		0x9a
+#define		SCBAUTO         	0x80
+#define		SCBCNT_MASK     	0x1f
+
+#define	QINFIFO         		0x9b
+
+#define	QINCNT          		0x9c
+
+#define	SCSIDATL_IMG    		0x9c
+
+#define	QOUTFIFO        		0x9d
+
+#define	CRCCONTROL1     		0x9d
+#define		CRCONSEEN       	0x80
+#define		CRCVALCHKEN     	0x40
+#define		CRCENDCHKEN     	0x20
+#define		CRCREQCHKEN     	0x10
+#define		TARGCRCENDEN    	0x08
+#define		TARGCRCCNTEN    	0x04
+
+#define	SCSIPHASE       		0x9e
+#define		SP_STATUS       	0x20
+#define		SP_COMMAND      	0x10
+#define		SP_MSG_IN       	0x08
+#define		SP_MSG_OUT      	0x04
+#define		SP_DATA_IN      	0x02
+#define		SP_DATA_OUT     	0x01
+
+#define	QOUTCNT         		0x9e
+
+#define	SFUNCT          		0x9f
+#define		ALT_MODE        	0x80
+
+#define	SCB_CONTROL     		0xa0
+#define		MK_MESSAGE      	0x80
+#define		DISCENB         	0x40
+#define		TAG_ENB         	0x20
+#define		DISCONNECTED    	0x04
+#define		SCB_TAG_TYPE    	0x03
+
+#define	SCB_BASE        		0xa0
+
+#define	SCB_TCL         		0xa1
+#define		TID             	0xf0
+#define		SELBUSB         	0x08
+#define		LID             	0x07
+
+#define	SCB_TARGET_STATUS		0xa2
+
+#define	SCB_SGCOUNT     		0xa3
+
+#define	SCB_SGPTR       		0xa4
+
+#define	SCB_RESID_SGCNT 		0xa8
+
+#define	SCB_RESID_DCNT  		0xa9
+
+#define	SCB_DATAPTR     		0xac
+
+#define	SCB_DATACNT     		0xb0
+
+#define	SCB_CMDPTR      		0xb4
+
+#define	SCB_CMDLEN      		0xb8
+
+#define	SCB_TAG         		0xb9
+
+#define	SCB_NEXT        		0xba
+
+#define	SCB_PREV        		0xbb
+
+#define	SCB_BUSYTARGETS 		0xbc
+
+#define	SEECTL_2840     		0xc0
+#define		CS_2840         	0x04
+#define		CK_2840         	0x02
+#define		DO_2840         	0x01
+
+#define	STATUS_2840     		0xc1
+#define		EEPROM_TF       	0x80
+#define		BIOS_SEL        	0x60
+#define		ADSEL           	0x1e
+#define		DI_2840         	0x01
+
+#define	CCHADDR         		0xe0
+
+#define	CCHCNT          		0xe8
+
+#define	CCSGRAM         		0xe9
+
+#define	CCSGADDR        		0xea
+
+#define	CCSGCTL         		0xeb
+#define		CCSGDONE        	0x80
+#define		CCSGEN          	0x08
+#define		FLAG            	0x02
+#define		CCSGRESET       	0x01
+
+#define	CCSCBRAM        		0xec
+
+#define	CCSCBADDR       		0xed
+
+#define	CCSCBCTL        		0xee
+#define		CCSCBDONE       	0x80
+#define		ARRDONE         	0x40
+#define		CCARREN         	0x10
+#define		CCSCBEN         	0x08
+#define		CCSCBDIR        	0x04
+#define		CCSCBRESET      	0x01
+
+#define	CCSCBCNT        		0xef
+
+#define	CCSCBPTR        		0xf1
+
+#define	HNSCB_QOFF      		0xf4
+
+#define	HESCB_QOFF      		0xf5
+
+#define	SNSCB_QOFF      		0xf6
+
+#define	SESCB_QOFF      		0xf7
+
+#define	SDSCB_QOFF      		0xf8
+
+#define	QOFF_CTLSTA     		0xfa
+#define		ESTABLISH_SCB_AVAIL	0x80
+#define		SCB_AVAIL       	0x40
+#define		SNSCB_ROLLOVER  	0x20
+#define		SDSCB_ROLLOVER  	0x10
+#define		SESCB_ROLLOVER  	0x08
+#define		SCB_QSIZE       	0x07
+#define		SCB_QSIZE_256   	0x06
+
+#define	DFF_THRSH       		0xfb
+#define		WR_DFTHRSH      	0x70
+#define		WR_DFTHRSH_MAX  	0x70
+#define		WR_DFTHRSH_90   	0x60
+#define		WR_DFTHRSH_85   	0x50
+#define		WR_DFTHRSH_75   	0x40
+#define		WR_DFTHRSH_63   	0x30
+#define		WR_DFTHRSH_50   	0x20
+#define		WR_DFTHRSH_25   	0x10
+#define		RD_DFTHRSH_MAX  	0x07
+#define		RD_DFTHRSH      	0x07
+#define		RD_DFTHRSH_90   	0x06
+#define		RD_DFTHRSH_85   	0x05
+#define		RD_DFTHRSH_75   	0x04
+#define		RD_DFTHRSH_63   	0x03
+#define		RD_DFTHRSH_50   	0x02
+#define		RD_DFTHRSH_25   	0x01
+#define		WR_DFTHRSH_MIN  	0x00
+#define		RD_DFTHRSH_MIN  	0x00
+
+#define	SG_CACHEPTR     		0xfc
+#define		SG_USER_DATA    	0xfc
+#define		LAST_SEG        	0x02
+#define		LAST_SEG_DONE   	0x01
+
+
+#define	CMD_GROUP2_BYTE_DELTA	0xfa
+#define	MAX_OFFSET_8BIT	0x0f
+#define	BUS_16_BIT	0x01
+#define	QINFIFO_OFFSET	0x02
+#define	CMD_GROUP5_BYTE_DELTA	0x0b
+#define	CMD_GROUP_CODE_SHIFT	0x05
+#define	MAX_OFFSET_ULTRA2	0x7f
+#define	MAX_OFFSET_16BIT	0x08
+#define	BUS_8_BIT	0x00
+#define	QOUTFIFO_OFFSET	0x01
+#define	UNTAGGEDSCB_OFFSET	0x00
+#define	CCSGRAM_MAXSEGS	0x10
+#define	SCB_LIST_NULL	0xff
+#define	SG_SIZEOF	0x08
+#define	CMD_GROUP4_BYTE_DELTA	0x04
+#define	CMD_GROUP0_BYTE_DELTA	0xfc
+#define	HOST_MSG	0xff
+#define	BUS_32_BIT	0x02
+#define	CCSGADDR_MAX	0x80
+
+
+/* Downloaded Constant Definitions */
+#define	TMODE_NUMCMDS	0x00
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx/aic7xxx_seq.c linux.19p18/drivers/scsi/aic7xxx/aic7xxx_seq.c
--- linux.vanilla/drivers/scsi/aic7xxx/aic7xxx_seq.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/scsi/aic7xxx/aic7xxx_seq.c	Mon Feb 12 14:57:23 2001
@@ -0,0 +1,817 @@
+/*
+  * DO NOT EDIT - This file is automatically generated.
+  */
+static unsigned char seqprog[] = {
+	0xff, 0x6a, 0x06, 0x08,
+	0x7f, 0x02, 0x04, 0x08,
+	0x12, 0x6a, 0x00, 0x00,
+	0xff, 0x6a, 0xd6, 0x09,
+	0xff, 0x6a, 0xdc, 0x09,
+	0x00, 0x65, 0xca, 0x58,
+	0xf7, 0x01, 0x02, 0x08,
+	0xff, 0x4e, 0xc8, 0x08,
+	0xbf, 0x60, 0xc0, 0x08,
+	0x60, 0x0b, 0x86, 0x68,
+	0x40, 0x00, 0x0c, 0x68,
+	0x08, 0x1f, 0x3e, 0x10,
+	0x60, 0x0b, 0x86, 0x68,
+	0x40, 0x00, 0x0c, 0x68,
+	0x08, 0x1f, 0x3e, 0x10,
+	0xff, 0x3e, 0x48, 0x60,
+	0x40, 0xfa, 0x10, 0x78,
+	0xff, 0xf6, 0xd4, 0x08,
+	0x01, 0x4e, 0x9c, 0x18,
+	0x40, 0x60, 0xc0, 0x00,
+	0x00, 0x4d, 0x10, 0x70,
+	0x01, 0x4e, 0x9c, 0x18,
+	0xbf, 0x60, 0xc0, 0x08,
+	0x00, 0x6a, 0x86, 0x5c,
+	0xff, 0x4e, 0xc8, 0x18,
+	0x02, 0x6a, 0x70, 0x5b,
+	0xff, 0x52, 0x20, 0x09,
+	0x0d, 0x6a, 0x6a, 0x00,
+	0x00, 0x52, 0xe6, 0x5b,
+	0x03, 0xb0, 0x52, 0x31,
+	0xff, 0xb0, 0x52, 0x09,
+	0xff, 0xb1, 0x54, 0x09,
+	0xff, 0xb2, 0x56, 0x09,
+	0xff, 0xa3, 0x50, 0x09,
+	0xff, 0x3e, 0x74, 0x09,
+	0xff, 0x90, 0x7c, 0x08,
+	0xff, 0x3e, 0x20, 0x09,
+	0x00, 0x65, 0x4e, 0x58,
+	0x00, 0x65, 0x0c, 0x40,
+	0xf7, 0x1f, 0xca, 0x08,
+	0x08, 0xa1, 0xc8, 0x08,
+	0x00, 0x65, 0xca, 0x00,
+	0xff, 0x65, 0x3e, 0x08,
+	0xf0, 0xa1, 0xc8, 0x08,
+	0x0f, 0x0f, 0x1e, 0x08,
+	0x00, 0x0f, 0x1e, 0x00,
+	0xf0, 0xa1, 0xc8, 0x08,
+	0x0f, 0x05, 0x0a, 0x08,
+	0x00, 0x05, 0x0a, 0x00,
+	0xff, 0x6a, 0x0c, 0x08,
+	0x5a, 0x6a, 0x00, 0x04,
+	0x12, 0x65, 0x02, 0x00,
+	0x31, 0x6a, 0xca, 0x00,
+	0x80, 0x37, 0x6e, 0x68,
+	0xff, 0x65, 0xca, 0x18,
+	0xff, 0x37, 0xdc, 0x08,
+	0xff, 0x6e, 0xc8, 0x08,
+	0x00, 0x6c, 0x76, 0x78,
+	0x20, 0x01, 0x02, 0x00,
+	0x4c, 0x37, 0xc8, 0x28,
+	0x08, 0x1f, 0x7e, 0x78,
+	0x08, 0x37, 0x6e, 0x00,
+	0x08, 0x64, 0xc8, 0x00,
+	0x70, 0x64, 0xca, 0x18,
+	0xff, 0x6c, 0x0a, 0x08,
+	0x20, 0x64, 0xca, 0x18,
+	0xff, 0x6c, 0x08, 0x0c,
+	0x40, 0x0b, 0x96, 0x68,
+	0x20, 0x6a, 0x16, 0x00,
+	0xf0, 0x19, 0x6e, 0x08,
+	0x08, 0x6a, 0x18, 0x00,
+	0x08, 0x11, 0x22, 0x00,
+	0x08, 0x6a, 0x66, 0x58,
+	0x08, 0x6a, 0x68, 0x00,
+	0x00, 0x65, 0xaa, 0x40,
+	0x12, 0x6a, 0x00, 0x00,
+	0x40, 0x6a, 0x16, 0x00,
+	0xff, 0x3e, 0x20, 0x09,
+	0xff, 0xba, 0x7c, 0x08,
+	0xff, 0xa1, 0x6e, 0x08,
+	0x08, 0x6a, 0x18, 0x00,
+	0x08, 0x11, 0x22, 0x00,
+	0x08, 0x6a, 0x66, 0x58,
+	0x80, 0x6a, 0x68, 0x00,
+	0x80, 0x36, 0x6c, 0x00,
+	0x00, 0x65, 0xba, 0x5b,
+	0xff, 0x3d, 0xc8, 0x08,
+	0xbf, 0x64, 0xe2, 0x78,
+	0x80, 0x64, 0xc8, 0x71,
+	0xa0, 0x64, 0xf8, 0x71,
+	0xc0, 0x64, 0xf0, 0x71,
+	0xe0, 0x64, 0x38, 0x72,
+	0x01, 0x6a, 0x22, 0x01,
+	0x00, 0x65, 0xaa, 0x40,
+	0xf7, 0x11, 0x22, 0x08,
+	0x00, 0x65, 0xca, 0x58,
+	0xff, 0x06, 0xd4, 0x08,
+	0xf7, 0x01, 0x02, 0x08,
+	0x09, 0x0c, 0xc4, 0x78,
+	0x08, 0x0c, 0x0c, 0x68,
+	0x01, 0x6a, 0x22, 0x01,
+	0xff, 0x6a, 0x26, 0x09,
+	0x02, 0x6a, 0x08, 0x30,
+	0xff, 0x6a, 0x08, 0x08,
+	0xdf, 0x01, 0x02, 0x08,
+	0x01, 0x6a, 0x7a, 0x00,
+	0xff, 0x6a, 0x6c, 0x0c,
+	0x04, 0x14, 0x10, 0x31,
+	0x03, 0xa9, 0x18, 0x31,
+	0x03, 0xa9, 0x10, 0x30,
+	0x08, 0x6a, 0xcc, 0x00,
+	0xa9, 0x6a, 0xd0, 0x5b,
+	0x00, 0x65, 0x02, 0x41,
+	0xa8, 0x6a, 0x6a, 0x00,
+	0x79, 0x6a, 0x6a, 0x00,
+	0x40, 0x3d, 0xea, 0x68,
+	0x04, 0x35, 0x6a, 0x00,
+	0x00, 0x65, 0x2a, 0x5b,
+	0x80, 0x6a, 0xd4, 0x01,
+	0x10, 0x36, 0xd6, 0x68,
+	0x10, 0x36, 0x6c, 0x00,
+	0x07, 0xac, 0x10, 0x31,
+	0x05, 0xa3, 0x70, 0x30,
+	0x03, 0x8c, 0x10, 0x30,
+	0x88, 0x6a, 0xcc, 0x00,
+	0xac, 0x6a, 0xc8, 0x5b,
+	0x00, 0x65, 0xc2, 0x5b,
+	0x38, 0x6a, 0xcc, 0x00,
+	0xa3, 0x6a, 0xcc, 0x5b,
+	0xff, 0x38, 0x12, 0x69,
+	0x80, 0x02, 0x04, 0x00,
+	0xe7, 0x35, 0x6a, 0x08,
+	0x03, 0x69, 0x18, 0x31,
+	0x03, 0x69, 0x10, 0x30,
+	0xff, 0x6a, 0x10, 0x00,
+	0xff, 0x6a, 0x12, 0x00,
+	0xff, 0x6a, 0x14, 0x00,
+	0x22, 0x38, 0xc8, 0x28,
+	0x01, 0x38, 0x1c, 0x61,
+	0x02, 0x64, 0xc8, 0x00,
+	0x01, 0x38, 0x1c, 0x61,
+	0xbf, 0x35, 0x6a, 0x08,
+	0xff, 0x64, 0xf8, 0x09,
+	0xff, 0x35, 0x26, 0x09,
+	0x80, 0x02, 0xa4, 0x69,
+	0x10, 0x0c, 0x7a, 0x69,
+	0x80, 0x94, 0x22, 0x79,
+	0x00, 0x35, 0x0a, 0x5b,
+	0x80, 0x02, 0xa4, 0x69,
+	0xff, 0x65, 0x94, 0x79,
+	0x01, 0x38, 0x70, 0x71,
+	0xff, 0x38, 0x70, 0x18,
+	0xff, 0x38, 0x94, 0x79,
+	0x80, 0xea, 0x4a, 0x61,
+	0xef, 0x38, 0xc8, 0x18,
+	0x80, 0x6a, 0xc8, 0x00,
+	0x00, 0x65, 0x3c, 0x49,
+	0x33, 0x38, 0xc8, 0x28,
+	0xff, 0x64, 0xd0, 0x09,
+	0x04, 0x39, 0xc0, 0x31,
+	0x09, 0x6a, 0xd6, 0x01,
+	0x80, 0xeb, 0x42, 0x79,
+	0xf7, 0xeb, 0xd6, 0x09,
+	0x08, 0xeb, 0x46, 0x69,
+	0x01, 0x6a, 0xd6, 0x01,
+	0x08, 0xe9, 0x10, 0x31,
+	0x03, 0x8c, 0x10, 0x30,
+	0xff, 0x38, 0x70, 0x18,
+	0x88, 0x6a, 0xcc, 0x00,
+	0x39, 0x6a, 0xce, 0x5b,
+	0x08, 0x6a, 0x18, 0x01,
+	0xff, 0x6a, 0x1a, 0x09,
+	0xff, 0x6a, 0x1c, 0x09,
+	0x0d, 0x93, 0x26, 0x01,
+	0x00, 0x65, 0x78, 0x5c,
+	0x88, 0x6a, 0xcc, 0x00,
+	0x00, 0x65, 0x6a, 0x5c,
+	0x00, 0x65, 0xc2, 0x5b,
+	0xff, 0x6a, 0xc8, 0x08,
+	0x08, 0x39, 0x72, 0x18,
+	0x00, 0x3a, 0x74, 0x20,
+	0x00, 0x65, 0x02, 0x41,
+	0x01, 0x0c, 0x6c, 0x79,
+	0x10, 0x0c, 0x02, 0x79,
+	0x10, 0x0c, 0x7a, 0x69,
+	0x01, 0xfc, 0x70, 0x79,
+	0xff, 0x6a, 0x70, 0x08,
+	0x01, 0x0c, 0x76, 0x79,
+	0x10, 0x0c, 0x02, 0x79,
+	0x00, 0x65, 0xae, 0x59,
+	0x01, 0xfc, 0x94, 0x69,
+	0x40, 0x0d, 0x84, 0x69,
+	0xb1, 0x6a, 0x22, 0x01,
+	0x00, 0x65, 0x94, 0x41,
+	0x2e, 0xfc, 0xa2, 0x28,
+	0x3f, 0x38, 0xc8, 0x08,
+	0x00, 0x51, 0x94, 0x71,
+	0xff, 0x6a, 0xc8, 0x08,
+	0xf8, 0x39, 0x72, 0x18,
+	0xff, 0x3a, 0x74, 0x20,
+	0x01, 0x38, 0x70, 0x18,
+	0x00, 0x65, 0x86, 0x41,
+	0x03, 0x08, 0x52, 0x31,
+	0xff, 0x38, 0x50, 0x09,
+	0x12, 0x01, 0x02, 0x00,
+	0xff, 0x08, 0x52, 0x09,
+	0xff, 0x09, 0x54, 0x09,
+	0xff, 0x0a, 0x56, 0x09,
+	0xff, 0x38, 0x50, 0x09,
+	0x00, 0x65, 0xaa, 0x40,
+	0x10, 0x0c, 0xa4, 0x79,
+	0x00, 0x65, 0xae, 0x59,
+	0x7f, 0x02, 0x04, 0x08,
+	0xe1, 0x6a, 0x22, 0x01,
+	0x00, 0x65, 0xaa, 0x40,
+	0x04, 0x93, 0xc2, 0x69,
+	0xdf, 0x93, 0x26, 0x09,
+	0x20, 0x93, 0xb2, 0x69,
+	0x02, 0x93, 0x26, 0x01,
+	0x01, 0x94, 0xb6, 0x79,
+	0x01, 0x94, 0xb6, 0x79,
+	0x01, 0x94, 0xb6, 0x79,
+	0x01, 0x94, 0xb6, 0x79,
+	0x01, 0x94, 0xb6, 0x79,
+	0x10, 0x94, 0xc0, 0x69,
+	0xd7, 0x93, 0x26, 0x09,
+	0x28, 0x93, 0xc4, 0x69,
+	0xff, 0x6a, 0xd4, 0x0c,
+	0x00, 0x65, 0x2a, 0x5b,
+	0x05, 0xb4, 0x10, 0x31,
+	0x02, 0x6a, 0x1a, 0x31,
+	0x03, 0x8c, 0x10, 0x30,
+	0x88, 0x6a, 0xcc, 0x00,
+	0xb4, 0x6a, 0xcc, 0x5b,
+	0xff, 0x6a, 0x1a, 0x09,
+	0xff, 0x6a, 0x1c, 0x09,
+	0x00, 0x65, 0xc2, 0x5b,
+	0x3d, 0x6a, 0x0a, 0x5b,
+	0xac, 0x6a, 0x26, 0x01,
+	0x04, 0x0b, 0xde, 0x69,
+	0x04, 0x0b, 0xe4, 0x69,
+	0x10, 0x0c, 0xe0, 0x79,
+	0x02, 0x03, 0xe8, 0x79,
+	0x11, 0x0c, 0xe4, 0x79,
+	0xd7, 0x93, 0x26, 0x09,
+	0x28, 0x93, 0xea, 0x69,
+	0x12, 0x01, 0x02, 0x00,
+	0x00, 0x65, 0xaa, 0x40,
+	0x00, 0x65, 0x2a, 0x5b,
+	0xff, 0x06, 0x44, 0x09,
+	0x00, 0x65, 0xaa, 0x40,
+	0x10, 0x3d, 0x06, 0x00,
+	0xff, 0x34, 0xca, 0x08,
+	0x80, 0x65, 0x1c, 0x62,
+	0x0f, 0xa1, 0xca, 0x08,
+	0x07, 0xa1, 0xca, 0x08,
+	0x40, 0xa0, 0xc8, 0x08,
+	0x00, 0x65, 0xca, 0x00,
+	0x80, 0x65, 0xca, 0x00,
+	0x80, 0xa0, 0x0c, 0x7a,
+	0xff, 0x65, 0x0c, 0x08,
+	0x00, 0x65, 0x1e, 0x42,
+	0x20, 0xa0, 0x24, 0x7a,
+	0xff, 0x65, 0x0c, 0x08,
+	0x00, 0x65, 0xba, 0x5b,
+	0xa0, 0x3d, 0x2c, 0x62,
+	0x23, 0xa0, 0x0c, 0x08,
+	0x00, 0x65, 0xba, 0x5b,
+	0xa0, 0x3d, 0x2c, 0x62,
+	0x00, 0xb9, 0x24, 0x42,
+	0xff, 0x65, 0x24, 0x62,
+	0xa1, 0x6a, 0x22, 0x01,
+	0xff, 0x6a, 0xd4, 0x08,
+	0x10, 0x51, 0x2c, 0x72,
+	0x40, 0x6a, 0x18, 0x00,
+	0xff, 0x65, 0x0c, 0x08,
+	0x00, 0x65, 0xba, 0x5b,
+	0xa0, 0x3d, 0xf6, 0x71,
+	0x40, 0x6a, 0x18, 0x00,
+	0xff, 0x34, 0xa6, 0x08,
+	0x80, 0x34, 0x34, 0x62,
+	0x7f, 0xa0, 0x40, 0x09,
+	0x08, 0x6a, 0x68, 0x00,
+	0x00, 0x65, 0xaa, 0x40,
+	0x64, 0x6a, 0x00, 0x5b,
+	0x80, 0x64, 0xaa, 0x6a,
+	0x04, 0x64, 0x8c, 0x72,
+	0x02, 0x64, 0x92, 0x72,
+	0x00, 0x6a, 0x54, 0x72,
+	0x03, 0x64, 0xa6, 0x72,
+	0x01, 0x64, 0x88, 0x72,
+	0x07, 0x64, 0xe8, 0x72,
+	0x08, 0x64, 0x50, 0x72,
+	0x23, 0x64, 0xec, 0x72,
+	0x11, 0x6a, 0x22, 0x01,
+	0x07, 0x6a, 0xf2, 0x5a,
+	0xff, 0x06, 0xd4, 0x08,
+	0x00, 0x65, 0xaa, 0x40,
+	0xff, 0xa8, 0x58, 0x6a,
+	0xff, 0xa2, 0x70, 0x7a,
+	0x01, 0x6a, 0x6a, 0x00,
+	0x00, 0xb9, 0xe6, 0x5b,
+	0xff, 0xa2, 0x70, 0x7a,
+	0x71, 0x6a, 0x22, 0x01,
+	0xff, 0x6a, 0xd4, 0x08,
+	0x40, 0x51, 0x70, 0x62,
+	0x0d, 0x6a, 0x6a, 0x00,
+	0x00, 0xb9, 0xe6, 0x5b,
+	0xff, 0x3e, 0x74, 0x09,
+	0xff, 0x90, 0x7c, 0x08,
+	0x00, 0x65, 0x4e, 0x58,
+	0x00, 0x65, 0xbc, 0x40,
+	0x20, 0xa0, 0x78, 0x6a,
+	0xff, 0x37, 0xc8, 0x08,
+	0x00, 0x6a, 0x90, 0x5b,
+	0xff, 0x6a, 0xa6, 0x5b,
+	0xff, 0xf8, 0xc8, 0x08,
+	0xff, 0x4f, 0xc8, 0x08,
+	0x01, 0x6a, 0x90, 0x5b,
+	0x00, 0xb9, 0xa6, 0x5b,
+	0x01, 0x4f, 0x9e, 0x18,
+	0x02, 0x6a, 0x22, 0x01,
+	0x00, 0x65, 0x80, 0x5c,
+	0x00, 0x65, 0xbc, 0x40,
+	0x41, 0x6a, 0x22, 0x01,
+	0x00, 0x65, 0xaa, 0x40,
+	0x04, 0xa0, 0x40, 0x01,
+	0x00, 0x65, 0x98, 0x5c,
+	0x00, 0x65, 0xbc, 0x40,
+	0x10, 0x36, 0x50, 0x7a,
+	0x05, 0x38, 0x46, 0x31,
+	0x04, 0x14, 0x58, 0x31,
+	0x03, 0xa9, 0x60, 0x31,
+	0xa3, 0x6a, 0xcc, 0x00,
+	0x38, 0x6a, 0xcc, 0x5b,
+	0xac, 0x6a, 0xcc, 0x00,
+	0x14, 0x6a, 0xce, 0x5b,
+	0xa9, 0x6a, 0xd0, 0x5b,
+	0x00, 0x65, 0x50, 0x42,
+	0xef, 0x36, 0x6c, 0x08,
+	0x00, 0x65, 0x50, 0x42,
+	0x0f, 0x64, 0xc8, 0x08,
+	0x07, 0x64, 0xc8, 0x08,
+	0x00, 0x37, 0x6e, 0x00,
+	0xff, 0x6a, 0xa4, 0x00,
+	0x00, 0x65, 0x60, 0x5b,
+	0xff, 0x51, 0xbc, 0x72,
+	0x20, 0x36, 0xc6, 0x7a,
+	0x00, 0x90, 0x4e, 0x5b,
+	0x00, 0x65, 0xc8, 0x42,
+	0xff, 0x06, 0xd4, 0x08,
+	0x00, 0x65, 0xba, 0x5b,
+	0xe0, 0x3d, 0xe2, 0x62,
+	0x20, 0x12, 0xe2, 0x62,
+	0x51, 0x6a, 0xf6, 0x5a,
+	0x00, 0x65, 0x48, 0x5b,
+	0xff, 0x37, 0xc8, 0x08,
+	0x00, 0xa1, 0xda, 0x62,
+	0x04, 0xa0, 0xda, 0x7a,
+	0xfb, 0xa0, 0x40, 0x09,
+	0x80, 0x36, 0x6c, 0x00,
+	0x80, 0xa0, 0x50, 0x7a,
+	0x7f, 0xa0, 0x40, 0x09,
+	0xff, 0x6a, 0xf2, 0x5a,
+	0x00, 0x65, 0x50, 0x42,
+	0x04, 0xa0, 0xe0, 0x7a,
+	0x00, 0x65, 0x98, 0x5c,
+	0x00, 0x65, 0xe2, 0x42,
+	0x00, 0x65, 0x80, 0x5c,
+	0x31, 0x6a, 0x22, 0x01,
+	0x0c, 0x6a, 0xf2, 0x5a,
+	0x00, 0x65, 0x50, 0x42,
+	0x61, 0x6a, 0x22, 0x01,
+	0x00, 0x65, 0x50, 0x42,
+	0x51, 0x6a, 0xf6, 0x5a,
+	0x51, 0x6a, 0x22, 0x01,
+	0x00, 0x65, 0x50, 0x42,
+	0x10, 0x3d, 0x06, 0x00,
+	0xff, 0x65, 0x68, 0x0c,
+	0xff, 0x06, 0xd4, 0x08,
+	0x01, 0x0c, 0xf8, 0x7a,
+	0x04, 0x0c, 0xfa, 0x6a,
+	0xe0, 0x03, 0x7a, 0x08,
+	0xe0, 0x3d, 0x06, 0x63,
+	0xff, 0x65, 0xcc, 0x08,
+	0xff, 0x12, 0xda, 0x0c,
+	0xff, 0x06, 0xd4, 0x0c,
+	0xd1, 0x6a, 0x22, 0x01,
+	0x00, 0x65, 0xaa, 0x40,
+	0xff, 0x65, 0x26, 0x09,
+	0x01, 0x0b, 0x1a, 0x6b,
+	0x10, 0x0c, 0x0c, 0x7b,
+	0x04, 0x0b, 0x14, 0x6b,
+	0xff, 0x6a, 0xca, 0x08,
+	0x04, 0x93, 0x18, 0x6b,
+	0x01, 0x94, 0x16, 0x7b,
+	0x10, 0x94, 0x18, 0x6b,
+	0x80, 0x3d, 0x1e, 0x73,
+	0x0f, 0x04, 0x22, 0x6b,
+	0x02, 0x03, 0x22, 0x7b,
+	0x11, 0x0c, 0x1e, 0x7b,
+	0xc7, 0x93, 0x26, 0x09,
+	0xff, 0x99, 0xd4, 0x08,
+	0x38, 0x93, 0x24, 0x6b,
+	0xff, 0x6a, 0xd4, 0x0c,
+	0x80, 0x36, 0x28, 0x6b,
+	0x21, 0x6a, 0x22, 0x05,
+	0xff, 0x65, 0x20, 0x09,
+	0xff, 0x51, 0x36, 0x63,
+	0xff, 0x37, 0xc8, 0x08,
+	0xa1, 0x6a, 0x42, 0x43,
+	0xff, 0x51, 0xc8, 0x08,
+	0xb9, 0x6a, 0x42, 0x43,
+	0xff, 0x90, 0xa4, 0x08,
+	0xff, 0xba, 0x46, 0x73,
+	0xff, 0xba, 0x20, 0x09,
+	0xff, 0x65, 0xca, 0x18,
+	0x00, 0x6c, 0x3a, 0x63,
+	0xff, 0x90, 0xca, 0x0c,
+	0xff, 0x6a, 0xca, 0x04,
+	0x20, 0x36, 0x5a, 0x7b,
+	0x00, 0x90, 0x2e, 0x5b,
+	0xff, 0x65, 0x5a, 0x73,
+	0xff, 0x52, 0x58, 0x73,
+	0xff, 0xba, 0xcc, 0x08,
+	0xff, 0x52, 0x20, 0x09,
+	0xff, 0x66, 0x74, 0x09,
+	0xff, 0x65, 0x20, 0x0d,
+	0xff, 0xba, 0x7e, 0x0c,
+	0x00, 0x6a, 0x86, 0x5c,
+	0x0d, 0x6a, 0x6a, 0x00,
+	0x00, 0x51, 0xe6, 0x43,
+	0xff, 0x3f, 0xb4, 0x73,
+	0xff, 0x6a, 0xa2, 0x00,
+	0x00, 0x3f, 0x2e, 0x5b,
+	0xff, 0x65, 0xb4, 0x73,
+	0x20, 0x36, 0x6c, 0x00,
+	0x20, 0xa0, 0x6e, 0x6b,
+	0xff, 0xb9, 0xa2, 0x0c,
+	0xff, 0x6a, 0xa2, 0x04,
+	0xff, 0x65, 0xa4, 0x08,
+	0xe0, 0x6a, 0xcc, 0x00,
+	0x45, 0x6a, 0xda, 0x5b,
+	0x01, 0x6a, 0xd0, 0x01,
+	0x09, 0x6a, 0xd6, 0x01,
+	0x80, 0xeb, 0x7a, 0x7b,
+	0x01, 0x6a, 0xd6, 0x01,
+	0x01, 0xe9, 0xa4, 0x34,
+	0x88, 0x6a, 0xcc, 0x00,
+	0x45, 0x6a, 0xda, 0x5b,
+	0x01, 0x6a, 0x18, 0x01,
+	0xff, 0x6a, 0x1a, 0x09,
+	0xff, 0x6a, 0x1c, 0x09,
+	0x0d, 0x6a, 0x26, 0x01,
+	0x00, 0x65, 0x78, 0x5c,
+	0xff, 0x99, 0xa4, 0x0c,
+	0xff, 0x65, 0xa4, 0x08,
+	0xe0, 0x6a, 0xcc, 0x00,
+	0x45, 0x6a, 0xda, 0x5b,
+	0x01, 0x6a, 0xd0, 0x01,
+	0x01, 0x6a, 0xdc, 0x05,
+	0x88, 0x6a, 0xcc, 0x00,
+	0x45, 0x6a, 0xda, 0x5b,
+	0x01, 0x6a, 0x18, 0x01,
+	0xff, 0x6a, 0x1a, 0x09,
+	0xff, 0x6a, 0x1c, 0x09,
+	0x01, 0x6a, 0x26, 0x05,
+	0x01, 0x65, 0xd8, 0x31,
+	0x09, 0xee, 0xdc, 0x01,
+	0x80, 0xee, 0xaa, 0x7b,
+	0xff, 0x6a, 0xdc, 0x0d,
+	0xff, 0x65, 0x32, 0x09,
+	0x0a, 0x93, 0x26, 0x01,
+	0x00, 0x65, 0x78, 0x44,
+	0xff, 0x37, 0xc8, 0x08,
+	0x00, 0x6a, 0x70, 0x5b,
+	0xff, 0x52, 0xa2, 0x0c,
+	0x01, 0x0c, 0xba, 0x7b,
+	0x04, 0x0c, 0xba, 0x6b,
+	0xe0, 0x03, 0x06, 0x08,
+	0xe0, 0x03, 0x7a, 0x0c,
+	0xff, 0x8c, 0x10, 0x08,
+	0xff, 0x8d, 0x12, 0x08,
+	0xff, 0x8e, 0x14, 0x0c,
+	0xff, 0x6c, 0xda, 0x08,
+	0xff, 0x6c, 0xda, 0x08,
+	0xff, 0x6c, 0xda, 0x08,
+	0xff, 0x6c, 0xda, 0x08,
+	0xff, 0x6c, 0xda, 0x08,
+	0xff, 0x6c, 0xda, 0x08,
+	0xff, 0x6c, 0xda, 0x0c,
+	0x3d, 0x64, 0xa4, 0x28,
+	0x55, 0x64, 0xc8, 0x28,
+	0x00, 0x6c, 0xda, 0x18,
+	0xff, 0x52, 0xc8, 0x08,
+	0x00, 0x6c, 0xda, 0x20,
+	0xff, 0x6a, 0xc8, 0x08,
+	0x00, 0x6c, 0xda, 0x20,
+	0x00, 0x6c, 0xda, 0x24,
+	0xff, 0x65, 0xc8, 0x08,
+	0xe0, 0x6a, 0xcc, 0x00,
+	0x41, 0x6a, 0xd6, 0x5b,
+	0xff, 0x90, 0xe2, 0x09,
+	0x20, 0x6a, 0xd0, 0x01,
+	0x04, 0x35, 0xf8, 0x7b,
+	0x1d, 0x6a, 0xdc, 0x01,
+	0xdc, 0xee, 0xf4, 0x63,
+	0x00, 0x65, 0x0e, 0x44,
+	0x01, 0x6a, 0xdc, 0x01,
+	0x20, 0xa0, 0xd8, 0x31,
+	0x09, 0xee, 0xdc, 0x01,
+	0x80, 0xee, 0xfe, 0x7b,
+	0x11, 0x6a, 0xdc, 0x01,
+	0x50, 0xee, 0x02, 0x64,
+	0x20, 0x6a, 0xd0, 0x01,
+	0x09, 0x6a, 0xdc, 0x01,
+	0x88, 0xee, 0x08, 0x64,
+	0x19, 0x6a, 0xdc, 0x01,
+	0xd8, 0xee, 0x0c, 0x64,
+	0xff, 0x6a, 0xdc, 0x09,
+	0x18, 0xee, 0x10, 0x6c,
+	0xff, 0x6a, 0xd4, 0x0c,
+	0x88, 0x6a, 0xcc, 0x00,
+	0x41, 0x6a, 0xd6, 0x5b,
+	0x20, 0x6a, 0x18, 0x01,
+	0xff, 0x6a, 0x1a, 0x09,
+	0xff, 0x6a, 0x1c, 0x09,
+	0xff, 0x35, 0x26, 0x09,
+	0x04, 0x35, 0x3c, 0x6c,
+	0xa0, 0x6a, 0xca, 0x00,
+	0x20, 0x65, 0xc8, 0x18,
+	0xff, 0x6c, 0x32, 0x09,
+	0xff, 0x6c, 0x32, 0x09,
+	0xff, 0x6c, 0x32, 0x09,
+	0xff, 0x6c, 0x32, 0x09,
+	0xff, 0x6c, 0x32, 0x09,
+	0xff, 0x6c, 0x32, 0x09,
+	0xff, 0x6c, 0x32, 0x09,
+	0xff, 0x6c, 0x32, 0x09,
+	0x00, 0x65, 0x26, 0x64,
+	0x0a, 0x93, 0x26, 0x01,
+	0x00, 0x65, 0x78, 0x44,
+	0xa0, 0x6a, 0xcc, 0x00,
+	0xe8, 0x6a, 0xc8, 0x00,
+	0x01, 0x94, 0x40, 0x6c,
+	0x10, 0x94, 0x42, 0x6c,
+	0x08, 0x94, 0x54, 0x6c,
+	0x08, 0x94, 0x54, 0x6c,
+	0x08, 0x94, 0x54, 0x6c,
+	0x00, 0x65, 0x68, 0x5c,
+	0x08, 0x64, 0xc8, 0x18,
+	0x00, 0x8c, 0xca, 0x18,
+	0x00, 0x65, 0x4a, 0x4c,
+	0x00, 0x65, 0x40, 0x44,
+	0xf7, 0x93, 0x26, 0x09,
+	0x08, 0x93, 0x56, 0x6c,
+	0x00, 0x65, 0x68, 0x5c,
+	0x08, 0x64, 0xc8, 0x18,
+	0x08, 0x64, 0x58, 0x64,
+	0xff, 0x6a, 0xd4, 0x0c,
+	0x00, 0x65, 0x78, 0x5c,
+	0x00, 0x65, 0x68, 0x5c,
+	0x00, 0x65, 0x68, 0x5c,
+	0x00, 0x65, 0x68, 0x5c,
+	0xff, 0x99, 0xda, 0x08,
+	0xff, 0x99, 0xda, 0x08,
+	0xff, 0x99, 0xda, 0x08,
+	0xff, 0x99, 0xda, 0x08,
+	0xff, 0x99, 0xda, 0x08,
+	0xff, 0x99, 0xda, 0x08,
+	0xff, 0x99, 0xda, 0x08,
+	0xff, 0x99, 0xda, 0x0c,
+	0x08, 0x94, 0x78, 0x7c,
+	0xf7, 0x93, 0x26, 0x09,
+	0x08, 0x93, 0x7c, 0x6c,
+	0xff, 0x6a, 0xd4, 0x0c,
+	0xff, 0x40, 0x74, 0x09,
+	0xff, 0x90, 0x80, 0x08,
+	0xff, 0x6a, 0x72, 0x05,
+	0xff, 0x40, 0x94, 0x64,
+	0xff, 0x3f, 0x8c, 0x64,
+	0xff, 0x6a, 0xca, 0x04,
+	0xff, 0x3f, 0x20, 0x09,
+	0x01, 0x6a, 0x6a, 0x00,
+	0x00, 0xb9, 0xe6, 0x5b,
+	0xff, 0xba, 0x7e, 0x0c,
+	0xff, 0x40, 0x20, 0x09,
+	0xff, 0xba, 0x80, 0x0c,
+	0xff, 0x3f, 0x74, 0x09,
+	0xff, 0x90, 0x7e, 0x0c,
+};
+
+static int aic7xxx_patch15_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch15_func(struct aic7xxx_host *p)
+{
+	return ((p->bugs & AHC_BUG_SCBCHAN_UPLOAD) != 0);
+}
+
+static int aic7xxx_patch14_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch14_func(struct aic7xxx_host *p)
+{
+	return ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0);
+}
+
+static int aic7xxx_patch13_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch13_func(struct aic7xxx_host *p)
+{
+	return ((p->features & AHC_WIDE) != 0);
+}
+
+static int aic7xxx_patch12_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch12_func(struct aic7xxx_host *p)
+{
+	return ((p->bugs & AHC_BUG_AUTOFLUSH) != 0);
+}
+
+static int aic7xxx_patch11_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch11_func(struct aic7xxx_host *p)
+{
+	return ((p->features & AHC_ULTRA2) == 0);
+}
+
+static int aic7xxx_patch10_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch10_func(struct aic7xxx_host *p)
+{
+	return ((p->features & AHC_CMD_CHAN) == 0);
+}
+
+static int aic7xxx_patch9_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch9_func(struct aic7xxx_host *p)
+{
+	return ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895);
+}
+
+static int aic7xxx_patch8_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch8_func(struct aic7xxx_host *p)
+{
+	return ((p->features & AHC_ULTRA) != 0);
+}
+
+static int aic7xxx_patch7_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch7_func(struct aic7xxx_host *p)
+{
+	return ((p->features & AHC_ULTRA2) != 0);
+}
+
+static int aic7xxx_patch6_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch6_func(struct aic7xxx_host *p)
+{
+	return ((p->flags & AHC_PAGESCBS) == 0);
+}
+
+static int aic7xxx_patch5_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch5_func(struct aic7xxx_host *p)
+{
+	return ((p->flags & AHC_PAGESCBS) != 0);
+}
+
+static int aic7xxx_patch4_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch4_func(struct aic7xxx_host *p)
+{
+	return ((p->features & AHC_QUEUE_REGS) != 0);
+}
+
+static int aic7xxx_patch3_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch3_func(struct aic7xxx_host *p)
+{
+	return ((p->features & AHC_TWIN) != 0);
+}
+
+static int aic7xxx_patch2_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch2_func(struct aic7xxx_host *p)
+{
+	return ((p->features & AHC_QUEUE_REGS) == 0);
+}
+
+static int aic7xxx_patch1_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch1_func(struct aic7xxx_host *p)
+{
+	return ((p->features & AHC_CMD_CHAN) != 0);
+}
+
+static int aic7xxx_patch0_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch0_func(struct aic7xxx_host *p)
+{
+	return (0);
+}
+
+struct sequencer_patch {
+	int		(*patch_func)(struct aic7xxx_host *);
+	unsigned int	begin	   :10,
+			skip_instr :10,
+			skip_patch :12;
+} sequencer_patches[] = {
+	{ aic7xxx_patch1_func, 3, 2, 1 },
+	{ aic7xxx_patch2_func, 7, 1, 1 },
+	{ aic7xxx_patch2_func, 8, 1, 1 },
+	{ aic7xxx_patch3_func, 11, 4, 1 },
+	{ aic7xxx_patch4_func, 16, 3, 2 },
+	{ aic7xxx_patch0_func, 19, 4, 1 },
+	{ aic7xxx_patch5_func, 23, 1, 1 },
+	{ aic7xxx_patch6_func, 26, 1, 1 },
+	{ aic7xxx_patch1_func, 29, 1, 2 },
+	{ aic7xxx_patch0_func, 30, 3, 1 },
+	{ aic7xxx_patch3_func, 39, 4, 1 },
+	{ aic7xxx_patch7_func, 43, 3, 2 },
+	{ aic7xxx_patch0_func, 46, 3, 1 },
+	{ aic7xxx_patch8_func, 52, 7, 1 },
+	{ aic7xxx_patch3_func, 60, 3, 1 },
+	{ aic7xxx_patch7_func, 63, 2, 1 },
+	{ aic7xxx_patch7_func, 102, 1, 2 },
+	{ aic7xxx_patch0_func, 103, 2, 1 },
+	{ aic7xxx_patch7_func, 107, 2, 1 },
+	{ aic7xxx_patch9_func, 109, 1, 1 },
+	{ aic7xxx_patch10_func, 110, 2, 1 },
+	{ aic7xxx_patch7_func, 113, 1, 2 },
+	{ aic7xxx_patch0_func, 114, 1, 1 },
+	{ aic7xxx_patch1_func, 118, 1, 1 },
+	{ aic7xxx_patch1_func, 121, 3, 3 },
+	{ aic7xxx_patch11_func, 123, 1, 1 },
+	{ aic7xxx_patch0_func, 124, 5, 1 },
+	{ aic7xxx_patch7_func, 132, 1, 1 },
+	{ aic7xxx_patch9_func, 133, 1, 1 },
+	{ aic7xxx_patch10_func, 134, 3, 1 },
+	{ aic7xxx_patch7_func, 137, 3, 2 },
+	{ aic7xxx_patch0_func, 140, 2, 1 },
+	{ aic7xxx_patch7_func, 142, 5, 2 },
+	{ aic7xxx_patch0_func, 147, 3, 1 },
+	{ aic7xxx_patch7_func, 150, 1, 2 },
+	{ aic7xxx_patch0_func, 151, 2, 1 },
+	{ aic7xxx_patch1_func, 153, 15, 4 },
+	{ aic7xxx_patch11_func, 166, 1, 2 },
+	{ aic7xxx_patch0_func, 167, 1, 1 },
+	{ aic7xxx_patch0_func, 168, 10, 1 },
+	{ aic7xxx_patch7_func, 181, 1, 2 },
+	{ aic7xxx_patch0_func, 182, 2, 1 },
+	{ aic7xxx_patch7_func, 184, 18, 1 },
+	{ aic7xxx_patch1_func, 202, 3, 3 },
+	{ aic7xxx_patch7_func, 204, 1, 1 },
+	{ aic7xxx_patch0_func, 205, 4, 1 },
+	{ aic7xxx_patch7_func, 210, 2, 1 },
+	{ aic7xxx_patch7_func, 215, 13, 3 },
+	{ aic7xxx_patch12_func, 218, 1, 1 },
+	{ aic7xxx_patch12_func, 219, 4, 1 },
+	{ aic7xxx_patch1_func, 229, 3, 3 },
+	{ aic7xxx_patch11_func, 231, 1, 1 },
+	{ aic7xxx_patch0_func, 232, 5, 1 },
+	{ aic7xxx_patch11_func, 237, 1, 2 },
+	{ aic7xxx_patch0_func, 238, 9, 1 },
+	{ aic7xxx_patch13_func, 254, 1, 2 },
+	{ aic7xxx_patch0_func, 255, 1, 1 },
+	{ aic7xxx_patch4_func, 316, 1, 2 },
+	{ aic7xxx_patch0_func, 317, 1, 1 },
+	{ aic7xxx_patch2_func, 320, 1, 1 },
+	{ aic7xxx_patch1_func, 330, 3, 2 },
+	{ aic7xxx_patch0_func, 333, 5, 1 },
+	{ aic7xxx_patch13_func, 341, 1, 2 },
+	{ aic7xxx_patch0_func, 342, 1, 1 },
+	{ aic7xxx_patch5_func, 347, 1, 1 },
+	{ aic7xxx_patch11_func, 389, 15, 2 },
+	{ aic7xxx_patch14_func, 402, 1, 1 },
+	{ aic7xxx_patch1_func, 441, 7, 2 },
+	{ aic7xxx_patch0_func, 448, 8, 1 },
+	{ aic7xxx_patch1_func, 457, 4, 2 },
+	{ aic7xxx_patch0_func, 461, 6, 1 },
+	{ aic7xxx_patch1_func, 467, 4, 2 },
+	{ aic7xxx_patch0_func, 471, 3, 1 },
+	{ aic7xxx_patch10_func, 481, 10, 1 },
+	{ aic7xxx_patch1_func, 500, 22, 5 },
+	{ aic7xxx_patch11_func, 508, 4, 1 },
+	{ aic7xxx_patch7_func, 512, 7, 3 },
+	{ aic7xxx_patch15_func, 512, 5, 2 },
+	{ aic7xxx_patch0_func, 517, 2, 1 },
+	{ aic7xxx_patch10_func, 522, 50, 3 },
+	{ aic7xxx_patch14_func, 543, 17, 2 },
+	{ aic7xxx_patch0_func, 560, 4, 1 },
+	{ aic7xxx_patch10_func, 572, 4, 1 },
+	{ aic7xxx_patch5_func, 576, 2, 1 },
+	{ aic7xxx_patch5_func, 579, 9, 1 },
+
+};
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx.c linux.19p18/drivers/scsi/aic7xxx.c
--- linux.vanilla/drivers/scsi/aic7xxx.c	Sat Sep  9 18:42:41 2000
+++ linux.19p18/drivers/scsi/aic7xxx.c	Mon Feb 12 14:57:23 2001
@@ -246,11 +246,11 @@
 #include "sd.h"
 #include "scsi.h"
 #include "hosts.h"
-#include "aic7xxx.h"
+#include "aic7xxx/aic7xxx.h"
 
 #include "aic7xxx/sequencer.h"
 #include "aic7xxx/scsi_message.h"
-#include "aic7xxx_reg.h"
+#include "aic7xxx/aic7xxx_reg.h"
 #include <scsi/scsicam.h>
 
 #include <linux/stat.h>
@@ -270,7 +270,7 @@
     0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-#define AIC7XXX_C_VERSION  "5.1.31"
+#define AIC7XXX_C_VERSION  "5.1.33"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
@@ -790,6 +790,7 @@
 
 typedef enum {
         SCB_FREE                = 0x0000,
+        SCB_DTR_SCB             = 0x0001,
         SCB_WAITINGQ            = 0x0002,
         SCB_ACTIVE              = 0x0004,
         SCB_SENSE               = 0x0008,
@@ -896,6 +897,17 @@
   AHC_AIC7899_FE       = AHC_AIC7890_FE|AHC_ULTRA3,
 } ahc_feature;
 
+typedef enum {
+  AHC_BUG_NONE            = 0x0000,
+  AHC_BUG_TMODE_WIDEODD   = 0x0001,
+  AHC_BUG_AUTOFLUSH       = 0x0002,
+  AHC_BUG_CACHETHEN       = 0x0004,
+  AHC_BUG_CACHETHEN_DIS   = 0x0008,
+  AHC_BUG_PCI_2_1_RETRY   = 0x0010,
+  AHC_BUG_PCI_MWI         = 0x0020,
+  AHC_BUG_SCBCHAN_UPLOAD  = 0x0040,
+} ahc_bugs;
+
 struct aic7xxx_scb {
         struct aic7xxx_hwscb  *hscb;          /* corresponding hardware scb */
         Scsi_Cmnd             *cmd;              /* Scsi_Cmnd for this scb */
@@ -1004,7 +1016,6 @@
   unsigned long            isr_count;        /* Interrupt count */
   unsigned long            spurious_int;
   scb_data_type           *scb_data;
-  volatile unsigned short  needdv;
   volatile unsigned short  needppr;
   volatile unsigned short  needsdtr;
   volatile unsigned short  needwdtr;
@@ -1032,10 +1043,9 @@
 #define  BUS_DEVICE_RESET_PENDING       0x02
 #define  DEVICE_RESET_DELAY             0x04
 #define  DEVICE_PRINT_DTR               0x08
-#define  DEVICE_PARITY_ERROR            0x10
-#define  DEVICE_WAS_BUSY                0x20
-#define  DEVICE_SCSI_3                  0x40
-#define  DEVICE_SCANNED                 0x80
+#define  DEVICE_WAS_BUSY                0x10
+#define  DEVICE_SCSI_3                  0x20
+#define  DEVICE_DTR_SCANNED             0x40
   volatile unsigned char   dev_flags[MAX_TARGETS];
   volatile unsigned char   dev_active_cmds[MAX_TARGETS];
   volatile unsigned char   dev_temp_queue_depth[MAX_TARGETS];
@@ -1051,10 +1061,6 @@
 #endif
 
 
-  Scsi_Cmnd               *dev_dtr_cmnd[MAX_TARGETS];
-
-  unsigned int             dev_checksum[MAX_TARGETS];
-  
   unsigned char            dev_last_queue_full[MAX_TARGETS];
   unsigned char            dev_last_queue_full_count[MAX_TARGETS];
   unsigned char            dev_max_queue_depth[MAX_TARGETS];
@@ -1111,6 +1117,7 @@
   int                      host_no;          /* SCSI host number */
   unsigned long            mbase;            /* I/O memory address */
   ahc_chip                 chip;             /* chip type */
+  ahc_bugs                 bugs;             /* hardware bugs this chip has */
 
   /*
    * Statistics Kept:
@@ -1712,7 +1719,7 @@
  * prototype, our code has to be ordered that way, it's a left-over from
  * the original driver days.....I should fix it some time DL).
  */
-#include "aic7xxx_seq.c"
+#include "aic7xxx/aic7xxx_seq.c"
 
 /*+F*************************************************************************
  * Function:
@@ -2876,138 +2883,98 @@
   {
     p->flags &= ~AHC_ABORT_PENDING;
   }
-  if (scb->flags & SCB_RESET)
+  if (scb->flags & (SCB_RESET|SCB_ABORT))
   {
-      cmd->result = (DID_RESET << 16) | (cmd->result & 0xffff);
+    cmd->result |= (DID_RESET << 16);
   }
-  else if (scb->flags & SCB_ABORT)
-  {
-      cmd->result = (DID_RESET << 16) | (cmd->result & 0xffff);
-  }
-  else if (!(p->dev_flags[tindex] & DEVICE_SCANNED))
+
+  if (!(p->dev_flags[tindex] & DEVICE_PRESENT))
   {
     if ( (cmd->cmnd[0] == INQUIRY) && (cmd->result == DID_OK) )
     {
-      char *buffer;
-      
+    
       p->dev_flags[tindex] |= DEVICE_PRESENT;
-      if(cmd->use_sg)
-      {
-        struct scatterlist *sg;
-
-        sg = (struct scatterlist *)cmd->request_buffer;
-        buffer = (char *)sg[0].address;
-      }
-      else
-      {
-        buffer = (char *)cmd->request_buffer;
-      }
 #define WIDE_INQUIRY_BITS 0x60
 #define SYNC_INQUIRY_BITS 0x10
 #define SCSI_VERSION_BITS 0x07
 #define SCSI_DT_BIT       0x04
-      if ( (buffer[7] & WIDE_INQUIRY_BITS) &&
-           (p->features & AHC_WIDE) )
-      {
-        p->needwdtr |= (1<<tindex);
-        p->needwdtr_copy |= (1<<tindex);
-        p->transinfo[tindex].goal_width = p->transinfo[tindex].user_width;
-      }
-      else
-      {
-        p->needwdtr &= ~(1<<tindex);
-        p->needwdtr_copy &= ~(1<<tindex);
-        pause_sequencer(p);
-        aic7xxx_set_width(p, cmd->target, cmd->channel, cmd->lun,
-                          MSG_EXT_WDTR_BUS_8_BIT, (AHC_TRANS_ACTIVE |
-                                                   AHC_TRANS_GOAL |
-                                                   AHC_TRANS_CUR) );
-        unpause_sequencer(p, FALSE);
-      }
-      if ( (buffer[7] & SYNC_INQUIRY_BITS) &&
-            p->transinfo[tindex].user_offset )
-      {
-        p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period;
-        p->transinfo[tindex].goal_options = p->transinfo[tindex].user_options;
-        if (p->features & AHC_ULTRA2)
-          p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
-        else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT)
-          p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+      if(!(p->dev_flags[tindex] & DEVICE_DTR_SCANNED)) {
+        char *buffer;
+
+        if(cmd->use_sg)
+        {
+          struct scatterlist *sg;
+
+          sg = (struct scatterlist *)cmd->request_buffer;
+          buffer = (char *)sg[0].address;
+        }
+        else
+        {
+          buffer = (char *)cmd->request_buffer;
+        }
+
+
+        if ( (buffer[7] & WIDE_INQUIRY_BITS) &&
+             (p->features & AHC_WIDE) )
+        {
+          p->needwdtr |= (1<<tindex);
+          p->needwdtr_copy |= (1<<tindex);
+          p->transinfo[tindex].goal_width = p->transinfo[tindex].user_width;
+        }
         else
-          p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
-        if ( (((buffer[2] & SCSI_VERSION_BITS) == 3) ||
-               (buffer[56] & SCSI_DT_BIT) ||
-	       (p->dev_flags[tindex] & DEVICE_SCSI_3) ) &&
-               (p->transinfo[tindex].user_period <= 9) &&
-               (p->transinfo[tindex].user_options) )
         {
-          p->needppr |= (1<<tindex);
-          p->needppr_copy |= (1<<tindex);
-          p->needsdtr &= ~(1<<tindex);
-          p->needsdtr_copy &= ~(1<<tindex);
           p->needwdtr &= ~(1<<tindex);
           p->needwdtr_copy &= ~(1<<tindex);
-          p->dev_flags[tindex] |= DEVICE_SCSI_3;
+          pause_sequencer(p);
+          aic7xxx_set_width(p, cmd->target, cmd->channel, cmd->lun,
+                            MSG_EXT_WDTR_BUS_8_BIT, (AHC_TRANS_ACTIVE |
+                                                     AHC_TRANS_GOAL |
+                                                     AHC_TRANS_CUR) );
+          unpause_sequencer(p, FALSE);
         }
-        else
+        if ( (buffer[7] & SYNC_INQUIRY_BITS) &&
+              p->transinfo[tindex].user_offset )
         {
-          p->needsdtr |= (1<<tindex);
-          p->needsdtr_copy |= (1<<tindex);
-          p->transinfo[tindex].goal_period = 
-            MAX(10, p->transinfo[tindex].goal_period);
-          p->transinfo[tindex].goal_options = 0;
+          p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period;
+          p->transinfo[tindex].goal_options = p->transinfo[tindex].user_options;
+          if (p->features & AHC_ULTRA2)
+            p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+          else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT)
+            p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+          else
+            p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+          if ( (((buffer[2] & SCSI_VERSION_BITS) >= 3) ||
+                 (buffer[56] & SCSI_DT_BIT) ||
+                 (p->dev_flags[tindex] & DEVICE_SCSI_3) ) &&
+                 (p->transinfo[tindex].user_period <= 9) &&
+                 (p->transinfo[tindex].user_options) )
+          {
+            p->needppr |= (1<<tindex);
+            p->needppr_copy |= (1<<tindex);
+            p->needsdtr &= ~(1<<tindex);
+            p->needsdtr_copy &= ~(1<<tindex);
+            p->needwdtr &= ~(1<<tindex);
+            p->needwdtr_copy &= ~(1<<tindex);
+            p->dev_flags[tindex] |= DEVICE_SCSI_3;
+          }
+          else
+          {
+            p->needsdtr |= (1<<tindex);
+            p->needsdtr_copy |= (1<<tindex);
+            p->transinfo[tindex].goal_period = 
+              MAX(10, p->transinfo[tindex].goal_period);
+            p->transinfo[tindex].goal_options = 0;
+          }
         }
-      }
-      else
-      {
-        p->needsdtr &= ~(1<<tindex);
-        p->needsdtr_copy &= ~(1<<tindex);
-        p->transinfo[tindex].goal_period = 255;
-        p->transinfo[tindex].goal_offset = 0;
-        p->transinfo[tindex].goal_options = 0;
-      }
-      /*
-       * This is needed to work around a sequencer bug for now.  Regardless
-       * of the controller in use, if we have a Quantum drive, we need to
-       * limit the speed to 80MByte/sec.  As soon as I get a fixed version
-       * of the sequencer, this code will get yanked.
-       */
-      if(!strncmp(buffer + 8, "QUANTUM", 7) &&
-         p->transinfo[tindex].goal_options )
-      {
-        p->transinfo[tindex].goal_period = 
-          MAX(p->transinfo[tindex].goal_period, 10);
-        p->transinfo[tindex].goal_options = 0;
-        p->needppr &= ~(1<<tindex);
-        p->needppr_copy &= ~(1<<tindex);
-        p->needsdtr |= (1<<tindex);
-        p->needsdtr_copy |= (1<<tindex);
-        p->needwdtr |= (1<<tindex);
-        p->needwdtr_copy |= (1<<tindex);
-      }
-      /*
-       * Get the INQUIRY checksum.  We use this on Ultra 160/m
-       * and older devices both.  It allows us to drop speed on any bus type
-       * while at the same time giving us the needed domain validation for
-       * Ultra 160/m
-       *
-       * Note: We only get the checksum and set the SCANNED bit if this is
-       * one of our dtr commands.  If we don't do this, then we end up
-       * getting bad checksum results on the mid-level SCSI code's INQUIRY
-       * commands.
-       */
-      if(p->dev_dtr_cmnd[tindex] == cmd) {
-        unsigned int checksum = 0;
-        int *ibuffer;
-        int i=0;
-
-        ibuffer = (int *)buffer;
-        for( i = 0; i < (cmd->request_bufflen >> 2); i++)
+        else
         {
-          checksum += ibuffer[i];
+          p->needsdtr &= ~(1<<tindex);
+          p->needsdtr_copy &= ~(1<<tindex);
+          p->transinfo[tindex].goal_period = 255;
+          p->transinfo[tindex].goal_offset = 0;
+          p->transinfo[tindex].goal_options = 0;
         }
-        p->dev_checksum[tindex] = checksum;
-        p->dev_flags[tindex] |= DEVICE_SCANNED;
+        p->dev_flags[tindex] |= DEVICE_DTR_SCANNED;
         p->dev_flags[tindex] |= DEVICE_PRINT_DTR;
       }
 #undef WIDE_INQUIRY_BITS
@@ -3016,7 +2983,8 @@
 #undef SCSI_DT_BIT
     }
   }
-  else if ((scb->flags & SCB_MSGOUT_BITS) != 0)
+
+  if ((scb->flags & SCB_MSGOUT_BITS) != 0)
   {
     unsigned short mask;
     int message_error = FALSE;
@@ -3036,7 +3004,6 @@
 
     if (scb->flags & SCB_MSGOUT_WDTR)
     {
-      p->dtr_pending &= ~mask;
       if (message_error)
       {
         if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
@@ -3055,7 +3022,6 @@
     }
     if (scb->flags & SCB_MSGOUT_SDTR)
     {
-      p->dtr_pending &= ~mask;
       if (message_error)
       {
         if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
@@ -3075,7 +3041,6 @@
     }
     if (scb->flags & SCB_MSGOUT_PPR)
     {
-      p->dtr_pending &= ~mask;
       if(message_error)
       {
         if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
@@ -3100,6 +3065,7 @@
       }
     }
   }
+
   queue_depth = p->dev_temp_queue_depth[tindex];
   if (queue_depth >= p->dev_active_cmds[tindex])
   {
@@ -3133,9 +3099,18 @@
       }
     }
   }
-  if ( !(scb->tag_action) && (p->tagenable & (1<<tindex)) )
+  if (!(scb->tag_action))
+  {
+    aic7xxx_index_busy_target(p, scb->hscb->target_channel_lun,
+                              /* unbusy */ TRUE);
+    if (p->tagenable & (1<<tindex))
+    {
+      p->dev_temp_queue_depth[tindex] = p->dev_max_queue_depth[tindex];
+    }
+  }
+  if(scb->flags & SCB_DTR_SCB)
   {
-    p->dev_temp_queue_depth[tindex] = p->dev_max_queue_depth[tindex];
+    p->dtr_pending &= ~(1 << tindex);
   }
   p->dev_active_cmds[tindex]--;
   p->activescbs--;
@@ -3244,6 +3219,14 @@
         printk(INFO_LEAD "Aborting scb %d\n",
              p->host_no, CTL_OF_SCB(scb), scb->hscb->tag);
       found++;
+      /*
+       * Clear any residual information since the normal aic7xxx_done() path
+       * doesn't touch the residuals.
+       */
+      scb->hscb->residual_SG_segment_count = 0;
+      scb->hscb->residual_data_count[0] = 0;
+      scb->hscb->residual_data_count[1] = 0;
+      scb->hscb->residual_data_count[2] = 0;
       aic7xxx_done(p, scb);
     }
   }
@@ -3456,8 +3439,22 @@
   active_scb = aic_inb(p, SCBPTR);
 
   if (aic7xxx_verbose & (VERBOSE_RESET_PROCESS | VERBOSE_ABORT_PROCESS))
+  {
     printk(INFO_LEAD "Reset device, active_scb %d\n",
          p->host_no, channel, target, lun, active_scb);
+    printk(INFO_LEAD "Current scb_tag %d, SEQADDR 0x%x, LASTPHASE "
+           "0x%x\n",
+         p->host_no, channel, target, lun, aic_inb(p, SCB_TAG),
+         aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+         aic_inb(p, LASTPHASE));
+    printk(INFO_LEAD "SG_CACHEPTR 0x%x, SG_COUNT %d, SCSISIGI 0x%x\n",
+         p->host_no, channel, target, lun,
+         (p->features & AHC_ULTRA2) ?  aic_inb(p, SG_CACHEPTR) : 0,
+         aic_inb(p, SG_COUNT), aic_inb(p, SCSISIGI));
+    printk(INFO_LEAD "SSTAT0 0x%x, SSTAT1 0x%x, SSTAT2 0x%x\n",
+         p->host_no, channel, target, lun, aic_inb(p, SSTAT0),
+         aic_inb(p, SSTAT1), aic_inb(p, SSTAT2));
+  }
   /*
    * Deal with the busy target and linked next issues.
    */
@@ -3501,11 +3498,11 @@
       if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
         printk(INFO_LEAD "Cleaning up status information "
           "and delayed_scbs.\n", p->host_no, channel, i, lun);
-      p->dev_flags[i] &= ~(BUS_DEVICE_RESET_PENDING | DEVICE_PARITY_ERROR);
+      p->dev_flags[i] &= ~BUS_DEVICE_RESET_PENDING;
       if ( tag == SCB_LIST_NULL )
       {
         p->dev_flags[i] |= DEVICE_PRINT_DTR | DEVICE_RESET_DELAY;
-        p->dev_expires[i] = jiffies + (4 * HZ);
+        p->dev_expires[i] = jiffies + (1 * HZ);
         p->dev_timer_active |= (0x01 << i);
         p->dev_last_queue_full_count[i] = 0;
         p->dev_last_queue_full[i] = 0;
@@ -3550,7 +3547,7 @@
           prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
         }
       }
-      if ( j > (p->scb_data->maxscbs + 1) )
+      if ( j > (p->scb_data->numscbs + 1) )
       {
         if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
           printk(WARN_LEAD "Yikes!! There's a loop in the "
@@ -3611,7 +3608,7 @@
         prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
       }
     }
-    if ( j > (p->scb_data->maxscbs + 1) )
+    if ( j > (p->scb_data->numscbs + 1) )
     {
       if (aic7xxx_verbose & (VERBOSE_ABORT | VERBOSE_RESET))
         printk(WARN_LEAD "Yikes!! There's a loop in the "
@@ -4375,11 +4372,25 @@
     if (actual < cmd->underflow)
     {
       if (aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+      {
         printk(INFO_LEAD "Underflow - Wanted %u, %s %u, residual SG "
           "count %d.\n", p->host_no, CTL_OF_SCB(scb), cmd->underflow,
           (cmd->request.cmd == WRITE) ? "wrote" : "read", actual,
           hscb->residual_SG_segment_count);
+        printk(INFO_LEAD "status 0x%x.\n", p->host_no, CTL_OF_SCB(scb),
+          hscb->target_status);
+      }
+      /*
+       * In 2.4, only send back the residual information, don't flag this
+       * as an error.  Before 2.4 we had to flag this as an error because
+       * the mid layer didn't check residual data counts to see if the
+       * command needs retried.
+       */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+      cmd->resid = scb->sg_length - actual;
+#else
       aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+#endif
       aic7xxx_status(cmd) = hscb->target_status;
     }
   }
@@ -4698,7 +4709,6 @@
            */
           p->needwdtr &= ~target_mask;
           p->needwdtr_copy &= ~target_mask;
-          p->dtr_pending &= ~target_mask;
           scb->flags &= ~SCB_MSGOUT_BITS;
           aic7xxx_set_width(p, target, channel, lun, MSG_EXT_WDTR_BUS_8_BIT,
             (AHC_TRANS_ACTIVE|AHC_TRANS_GOAL|AHC_TRANS_CUR));
@@ -4718,8 +4728,7 @@
           */
           p->needsdtr &= ~target_mask;
           p->needsdtr_copy &= ~target_mask;
-          p->dtr_pending &= ~target_mask;
-          scb->flags &= ~SCB_MSGOUT_SDTR;
+          scb->flags &= ~SCB_MSGOUT_BITS;
           aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
             (AHC_TRANS_CUR|AHC_TRANS_ACTIVE|AHC_TRANS_GOAL));
           if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
@@ -4852,6 +4861,8 @@
                 aic7xxx_error(cmd) = DID_OK;
                 break;
               }  /* first time sense, no errors */
+              printk(INFO_LEAD "CHECK_CONDITION on REQUEST_SENSE, returning "
+                     "an error.\n", p->host_no, CTL_OF_SCB(scb));
               aic7xxx_error(cmd) = DID_ERROR;
               scb->flags &= ~SCB_SENSE;
               break;
@@ -5214,12 +5225,21 @@
           printk(KERN_WARNING "  %s seen Data Phase. Length=%d, NumSGs=%d.\n",
             (aic_inb(p, SEQ_FLAGS) & DPHASE) ? "Have" : "Haven't",
             scb->sg_length, scb->sg_count);
-          for (i = 0; i < scb->sg_count; i++)
+          printk(KERN_WARNING "  Raw SCSI Command: 0x");
+          for (i = 0; i < scb->hscb->SCSI_cmd_length; i++)
+          {
+            printk("%02x ", scb->cmd->cmnd[i]);
+          }
+          printk("\n");
+          if(aic7xxx_verbose > 0xffff)
           {
-            printk(KERN_WARNING "     sg[%d] - Addr 0x%x : Length %d\n",
+            for (i = 0; i < scb->sg_count; i++)
+            {
+              printk(KERN_WARNING "     sg[%d] - Addr 0x%x : Length %d\n",
                  i, 
                  le32_to_cpu(scb->sg_list[i].address),
                  le32_to_cpu(scb->sg_list[i].length) );
+            }
           }
           aic7xxx_error(scb->cmd) = DID_ERROR;
         }
@@ -5234,7 +5254,7 @@
         unsigned char resid_sgcnt, index;
         unsigned char scb_index = aic_inb(p, SCB_TAG);
         unsigned int cur_addr, resid_dcnt;
-        unsigned int native_addr, native_length;
+        unsigned int native_addr, native_length, sg_addr;
         int i;
 
         if(scb_index > p->scb_data->numscbs)
@@ -5254,6 +5274,9 @@
                  scb->flags, (unsigned int)scb->cmd);
           break;
         }
+        if(aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+          printk(INFO_LEAD "Got WIDE_RESIDUE message, patching up data "
+                 "pointer.\n", p->host_no, CTL_OF_SCB(scb));
 
         /*
          * We have a valid scb to use on this WIDE_RESIDUE message, so
@@ -5266,132 +5289,87 @@
          */
         cur_addr = aic_inb(p, SHADDR) | (aic_inb(p, SHADDR + 1) << 8) |
           (aic_inb(p, SHADDR + 2) << 16) | (aic_inb(p, SHADDR + 3) << 24);
+        sg_addr = aic_inb(p, SG_COUNT + 1) | (aic_inb(p, SG_COUNT + 2) << 8) |
+          (aic_inb(p, SG_COUNT + 3) << 16) | (aic_inb(p, SG_COUNT + 4) << 24);
         resid_sgcnt = aic_inb(p, SCB_RESID_SGCNT);
         resid_dcnt = aic_inb(p, SCB_RESID_DCNT) |
           (aic_inb(p, SCB_RESID_DCNT + 1) << 8) |
           (aic_inb(p, SCB_RESID_DCNT + 2) << 16);
-        index = scb->sg_count - (resid_sgcnt + 1);
+        index = scb->sg_count - ((resid_sgcnt) ? resid_sgcnt : 1);
         native_addr = le32_to_cpu(scb->sg_list[index].address);
         native_length = le32_to_cpu(scb->sg_list[index].length);
         /*
-         * Make sure this is a valid sg_seg for the given pointer
+         * If resid_dcnt == native_length, then we just loaded this SG
+         * segment and we need to back it up one...
          */
-        if(cur_addr < native_addr ||
-           cur_addr > (native_addr + native_length + 1))
-        {
-          printk(WARN_LEAD "invalid cur_addr:0x%x during WIDE_RESIDUE\n",
-                 p->host_no, CTL_OF_SCB(scb), cur_addr);
-          if(index > 0)
-            printk(WARN_LEAD "  sg_address[-1]:0x%x sg_length[-1]:%d\n",
-                   p->host_no, CTL_OF_SCB(scb),
-                   le32_to_cpu(scb->sg_list[index - 1].address),
-                   le32_to_cpu(scb->sg_list[index - 1].length));
-          printk(WARN_LEAD "  sg_address:0x%x sg_length:%d\n",
-                 p->host_no, CTL_OF_SCB(scb),
-                 native_addr, native_length);
-          if(resid_sgcnt > 1)
-            printk(WARN_LEAD "  sg_address[1]:0x%x sg_length[1]:%d\n",
-                   p->host_no, CTL_OF_SCB(scb),
-                   le32_to_cpu(scb->sg_list[index + 1].address),
-                   le32_to_cpu(scb->sg_list[index + 1].length));
-          printk(WARN_LEAD "  cur_address:0x%x resid_dcnt:0x%06x\n",
-                 p->host_no, CTL_OF_SCB(scb),
-                 cur_addr, resid_dcnt);
-          break;
-        }
-
-        if( (resid_sgcnt == 0) &&
-            ((resid_dcnt == 0) || (resid_dcnt == 0xffffff)))
+        if(resid_dcnt == native_length)
         {
-          /*
-           * We are at the end of the transfer and this is about a byte
-           * we ignored already (because the sequencer knew this was
-           * the last segment and set the adapter to ignore any wide
-           * residue bytes that might come through, which is only done
-           * on the last scatter gather segment of transfers).
-           */
-          break;
-        }
-        else if(cur_addr == native_addr)
-        {
-          /*
-           * If our current address matches the sg_seg->address then we
-           * have to back up the sg array to the previous segment and set
-           * it up to have only one byte of transfer left to go.
-           */
           if(index == 0)
           {
-            printk(WARN_LEAD "bogus WIDE_RESIDUE message, no data has been "
-                   "transferred.\n", p->host_no, CTL_OF_SCB(scb));
+            /*
+             * Oops, this isn't right, we can't back up to before the
+             * beginning.  This must be a bogus message, ignore it.
+             */
             break;
           }
-          resid_sgcnt++;
-          index--;
-          cur_addr = le32_to_cpu(scb->sg_list[index].address) + 
-            le32_to_cpu(scb->sg_list[index].length) - 1;
-          native_addr = aic_inb(p, SG_NEXT) | (aic_inb(p, SG_NEXT + 1) << 8)
-            | (aic_inb(p, SG_NEXT + 2) << 16) | (aic_inb(p, SG_NEXT + 3) << 24);
-          native_addr -= SG_SIZEOF;
-          aic_outb(p, resid_sgcnt, SG_COUNT);
-          aic_outb(p, resid_sgcnt, SCB_RESID_SGCNT);
-          aic_outb(p, native_addr & 0xff, SG_NEXT);
-          aic_outb(p, (native_addr >> 8) & 0xff, SG_NEXT + 1);
-          aic_outb(p, (native_addr >> 16) & 0xff, SG_NEXT + 2);
-          aic_outb(p, (native_addr >> 24) & 0xff, SG_NEXT + 3);
-          aic_outb(p, 1, SCB_RESID_DCNT); 
-          aic_outb(p, 0, SCB_RESID_DCNT + 1); 
-          aic_outb(p, 0, SCB_RESID_DCNT + 2); 
-          aic_outb(p, 1, HCNT); 
-          aic_outb(p, 0, HCNT + 1); 
-          aic_outb(p, 0, HCNT + 2); 
-          aic_outb(p, cur_addr & 0xff, HADDR);
-          aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1);
-          aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2);
-          aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3);
+          resid_dcnt = 1;
+          resid_sgcnt += 1;
+          native_addr = le32_to_cpu(scb->sg_list[index - 1].address);
+          native_length = le32_to_cpu(scb->sg_list[index - 1].length);
+          cur_addr = native_addr + (native_length - 1);
+          sg_addr -= sizeof(struct hw_scatterlist);
         }
         else
         {
           /*
-           * Back the data pointer up by one and add one to the remaining
-           * byte count.  Then store that in the HCNT and HADDR registers.
+           * resid_dcnt != native_length, so we are in the middle of a SG
+           * element.  Back it up one byte and leave the rest alone.
            */
-          cur_addr--;
-          resid_dcnt++;
-          aic_outb(p, resid_dcnt & 0xff, SCB_RESID_DCNT); 
-          aic_outb(p, (resid_dcnt >> 8) & 0xff, SCB_RESID_DCNT + 1); 
-          aic_outb(p, (resid_dcnt >> 16) & 0xff, SCB_RESID_DCNT + 2); 
-          aic_outb(p, resid_dcnt & 0xff, HCNT); 
-          aic_outb(p, (resid_dcnt >> 8) & 0xff, HCNT + 1); 
-          aic_outb(p, (resid_dcnt >> 16) & 0xff, HCNT + 2); 
-          aic_outb(p, cur_addr & 0xff, HADDR);
-          aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1);
-          aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2);
-          aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3);
+          resid_dcnt += 1;
+          cur_addr -= 1;
         }
+        
+        /*
+         * Output the new addresses and counts to the right places on the
+         * card.
+         */
+        aic_outb(p, resid_sgcnt, SG_COUNT);
+        aic_outb(p, resid_sgcnt, SCB_RESID_SGCNT);
+        aic_outb(p, sg_addr & 0xff, SG_COUNT + 1);
+        aic_outb(p, (sg_addr >> 8) & 0xff, SG_COUNT + 2);
+        aic_outb(p, (sg_addr >> 16) & 0xff, SG_COUNT + 3);
+        aic_outb(p, (sg_addr >> 24) & 0xff, SG_COUNT + 4);
+        aic_outb(p, resid_dcnt & 0xff, SCB_RESID_DCNT);
+        aic_outb(p, (resid_dcnt >> 8) & 0xff, SCB_RESID_DCNT + 1);
+        aic_outb(p, (resid_dcnt >> 16) & 0xff, SCB_RESID_DCNT + 2);
+
         /*
-         * The sequencer actually wants to find the new address and byte
-         * count in the SHCNT and SHADDR register sets.  These registers
-         * are a shadow of the regular HCNT and HADDR registers.  On the
-         * Ultra2 controllers, these registers are read only and the way
-         * we have to set their values is to put the values we want into
-         * the HCNT and HADDR registers and then output PRELOADEN into
-         * the DFCNTRL register which causes the card to latch the current
-         * values in the HADDR and HCNT registers and drop it through to
-         * the shadow registers.  On older cards we copy them directly
-         * across by hand.
+         * The sequencer actually wants to find the new address
+         * in the SHADDR register set.  On the Ultra2 and later controllers
+         * this register set is readonly.  In order to get the right number
+         * into the register, you actually have to enter it in HADDR and then
+         * use the PRELOADEN bit of DFCNTRL to drop it through from the
+         * HADDR register to the SHADDR register.  On non-Ultra2 controllers,
+         * we simply write it direct.
          */
         if(p->features & AHC_ULTRA2)
         {
-          aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
-          i=0;
+          /*
+           * We might as well be accurate and drop both the resid_dcnt and
+           * cur_addr into HCNT and HADDR and have both of them drop
+           * through to the shadow layer together.
+           */
+          aic_outb(p, resid_dcnt & 0xff, HCNT);
+          aic_outb(p, (resid_dcnt >> 8) & 0xff, HCNT + 1);
+          aic_outb(p, (resid_dcnt >> 16) & 0xff, HCNT + 2);
+          aic_outb(p, cur_addr & 0xff, HADDR);
+          aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1);
+          aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2);
+          aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3);
+          aic_outb(p, aic_inb(p, DMAPARAMS) | PRELOADEN, DFCNTRL);
           udelay(1);
-          while(((aic_inb(p, SSTAT0) & SDONE) != 0) && (i++ < 1000))
-          {
-            udelay(1);
-          }
           aic_outb(p, aic_inb(p, DMAPARAMS) & ~(SCSIEN|HDMAEN), DFCNTRL);
           i=0;
-          udelay(1);
           while(((aic_inb(p, DFCNTRL) & (SCSIEN|HDMAEN)) != 0) && (i++ < 1000))
           {
             udelay(1);
@@ -5399,9 +5377,6 @@
         }
         else
         {
-          aic_outb(p, resid_dcnt & 0xff, STCNT); 
-          aic_outb(p, (resid_dcnt >> 8) & 0xff, STCNT + 1); 
-          aic_outb(p, (resid_dcnt >> 16) & 0xff, STCNT + 2); 
           aic_outb(p, cur_addr & 0xff, SHADDR);
           aic_outb(p, (cur_addr >> 8) & 0xff, SHADDR + 1);
           aic_outb(p, (cur_addr >> 16) & 0xff, SHADDR + 2);
@@ -5410,15 +5385,82 @@
       }
       break;
 
-        
-#if AIC7XXX_NOT_YET 
-    case TRACEPOINT:
+    case SEQ_SG_FIXUP:
+    {
+      unsigned char scb_index, tmp;
+      int sg_addr, sg_length;
+
+      scb_index = aic_inb(p, SCB_TAG);
+
+      if(scb_index > p->scb_data->numscbs)
       {
-        printk(INFO_LEAD "Tracepoint #1 reached.\n", p->host_no,
-               channel, target, lun);
+        printk(WARN_LEAD "invalid scb_index during SEQ_SG_FIXUP.\n",
+          p->host_no, -1, -1, -1);
+        printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 "
+           "0x%x\n", p->host_no, -1, -1, -1,
+           aic_inb(p, SCSISIGI),
+           aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+           aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
+        printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n",
+           p->host_no, -1, -1, -1, aic_inb(p, SG_CACHEPTR),
+           aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 |
+           aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT));
+        /*
+         * XXX: Add error handling here
+         */
+        break;
       }
-      break;
+      scb = p->scb_data->scb_array[scb_index];
+      if(!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
+      {
+        printk(WARN_LEAD "invalid scb during SEQ_SG_FIXUP flags:0x%x "
+               "scb->cmd:0x%x\n", p->host_no, CTL_OF_SCB(scb),
+               scb->flags, (unsigned int)scb->cmd);
+        printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 "
+           "0x%x\n", p->host_no, CTL_OF_SCB(scb),
+           aic_inb(p, SCSISIGI),
+           aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+           aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
+        printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n",
+           p->host_no, CTL_OF_SCB(scb), aic_inb(p, SG_CACHEPTR),
+           aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 |
+           aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT));
+        break;
+      }
+      if(aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+        printk(INFO_LEAD "Fixing up SG address for sequencer.\n", p->host_no,
+               CTL_OF_SCB(scb));
+      /*
+       * Advance the SG pointer to the next element in the list
+       */
+      tmp = aic_inb(p, SG_NEXT);
+      tmp += SG_SIZEOF;
+      aic_outb(p, tmp, SG_NEXT);
+      if( tmp < SG_SIZEOF )
+        aic_outb(p, aic_inb(p, SG_NEXT + 1) + 1, SG_NEXT + 1);
+      tmp = aic_inb(p, SG_COUNT) - 1;
+      aic_outb(p, tmp, SG_COUNT);
+      sg_addr = le32_to_cpu(scb->sg_list[scb->sg_count - tmp].address);
+      sg_length = le32_to_cpu(scb->sg_list[scb->sg_count - tmp].length);
+      /*
+       * Now stuff the element we just advanced past down onto the
+       * card so it can be stored in the residual area.
+       */
+      aic_outb(p, sg_addr & 0xff, HADDR);
+      aic_outb(p, (sg_addr >> 8) & 0xff, HADDR + 1);
+      aic_outb(p, (sg_addr >> 16) & 0xff, HADDR + 2);
+      aic_outb(p, (sg_addr >> 24) & 0xff, HADDR + 3);
+      aic_outb(p, sg_length & 0xff, HCNT);
+      aic_outb(p, (sg_length >> 8) & 0xff, HCNT + 1);
+      aic_outb(p, (sg_length >> 16) & 0xff, HCNT + 2);
+      aic_outb(p, (tmp << 2) | ((tmp == 1) ? LAST_SEG : 0), SG_CACHEPTR);
+      aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
+      while(aic_inb(p, SSTAT0) & SDONE) udelay(1);
+      while(aic_inb(p, DFCNTRL) & (HDMAEN|SCSIEN)) aic_outb(p, 0, DFCNTRL);
+    }
+    break;
 
+#if AIC7XXX_NOT_YET 
     case TRACEPOINT2:
       {
         printk(INFO_LEAD "Tracepoint #2 reached.\n", p->host_no,
@@ -5463,6 +5505,10 @@
   unsigned char target_scsirate, tindex;
   unsigned short target_mask;
   unsigned char target, channel, lun;
+  unsigned char bus_width, new_bus_width;
+  unsigned char trans_options, new_trans_options;
+  unsigned int period, new_period, offset, new_offset, maxsync;
+  struct aic7xxx_syncrate *syncrate;
 
   target = scb->cmd->target;
   channel = scb->cmd->channel;
@@ -5486,6 +5532,35 @@
   }
 
   /*
+   * Even if we are an Ultra3 card, don't allow Ultra3 sync rates when
+   * using the SDTR messages.  We need the PPR messages to enable the
+   * higher speeds that include things like Dual Edge clocking.
+   */
+  if (p->features & AHC_ULTRA2)
+  {
+    if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
+         !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
+    {
+      if (p->features & AHC_ULTRA3)
+        maxsync = AHC_SYNCRATE_ULTRA3;
+      else
+        maxsync = AHC_SYNCRATE_ULTRA2;
+    }
+    else
+    {
+      maxsync = AHC_SYNCRATE_ULTRA;
+    }
+  }
+  else if (p->features & AHC_ULTRA)
+  {
+    maxsync = AHC_SYNCRATE_ULTRA;
+  }
+  else
+  {
+    maxsync = AHC_SYNCRATE_FAST;
+  }
+
+  /*
    * Just accept the length byte outright and perform
    * more checking once we know the message type.
    */
@@ -5496,9 +5571,6 @@
     {
       case MSG_EXT_SDTR:
       {
-        unsigned int period, offset;
-        unsigned char maxsync, saved_offset, options;
-        struct aic7xxx_syncrate *syncrate;
         
         if (p->msg_buf[1] != MSG_EXT_SDTR_LEN)
         {
@@ -5511,35 +5583,18 @@
           break;
         }
 
-        period = p->msg_buf[3];
-        saved_offset = offset = p->msg_buf[4];
-        options = 0;
+        period = new_period = p->msg_buf[3];
+        offset = new_offset = p->msg_buf[4];
+        trans_options = new_trans_options = 0;
+        bus_width = new_bus_width = target_scsirate & WIDEXFER;
 
         /*
-         * Even if we are an Ultra3 card, don't allow Ultra3 sync rates when
-         * using the SDTR messages.  We need the PPR messages to enable the
-         * higher speeds that include things like Dual Edge clocking.
+         * If our current max syncrate is in the Ultra3 range, bump it back
+         * down to Ultra2 since we can't negotiate DT transfers using SDTR
          */
-        if (p->features & AHC_ULTRA2)
-        {
-          if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
-               !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
-          {
-            maxsync = AHC_SYNCRATE_ULTRA2;
-          }
-          else
-          {
-            maxsync = AHC_SYNCRATE_ULTRA;
-          }
-        }
-        else if (p->features & AHC_ULTRA)
-        {
-          maxsync = AHC_SYNCRATE_ULTRA;
-        }
-        else
-        {
-          maxsync = AHC_SYNCRATE_FAST;
-        }
+        if(maxsync == AHC_SYNCRATE_ULTRA3)
+          maxsync = AHC_SYNCRATE_ULTRA2;
+
         /*
          * We might have a device that is starting negotiation with us
          * before we can start up negotiation with it....be prepared to
@@ -5549,88 +5604,116 @@
         if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
              (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) )
         {
-          if (!(p->dev_flags[tindex] & DEVICE_SCANNED) &&
-              !(p->needsdtr_copy & target_mask) &&
-               (p->transinfo[tindex].user_offset) )
+          if (!(p->dev_flags[tindex] & DEVICE_DTR_SCANNED))
           {
             /*
-             * Not only is the device starting this up, but it also hasn't
-             * been scanned yet, so this would likely be our TUR or our
-             * INQUIRY command at scan time, so we need to use the
-             * settings from the SEEPROM if they existed.  Of course, even
-             * if we didn't find a SEEPROM, we stuffed default values into
-             * the user settings anyway, so use those in all cases.
+             * We shouldn't get here unless this is a narrow drive, wide
+             * devices should trigger this same section of code in the WDTR
+             * handler first instead.
              */
-            p->transinfo[tindex].goal_period =
-              p->transinfo[tindex].user_period;
-            if(p->features & AHC_ULTRA2)
-            {
-              p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
-            }
-            else if (p->transinfo[tindex].cur_width)
+            p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_8_BIT;
+            p->transinfo[tindex].goal_options = 0;
+            if(p->transinfo[tindex].user_offset)
             {
-              p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+              p->needsdtr_copy |= target_mask;
+              p->transinfo[tindex].goal_period =
+                MAX(10,p->transinfo[tindex].user_period);
+              if(p->features & AHC_ULTRA2)
+              {
+                p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+              }
+              else
+              {
+                p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+              }
             }
             else
             {
-              p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+              p->needsdtr_copy &= ~target_mask;
+              p->transinfo[tindex].goal_period = 255;
+              p->transinfo[tindex].goal_offset = 0;
             }
-            p->needsdtr_copy |= target_mask;
+            p->dev_flags[tindex] |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR;
+          }
+          else if ((p->needsdtr_copy & target_mask) == 0)
+          {
+            /*
+             * This is a preemptive message from the target, we've already
+             * scanned this target and set our options for it, and we
+             * don't need a WDTR with this target (for whatever reason),
+             * so reject this incoming WDTR
+             */
+            reject = TRUE;
+            break;
           }
+
+          /* The device is sending this message first and we have to reply */
+          reply = TRUE;
+          
           if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
           {
             printk(INFO_LEAD "Received pre-emptive SDTR message from "
                    "target.\n", p->host_no, CTL_OF_SCB(scb));
           }
-          if ( !p->transinfo[tindex].goal_offset )
-            period = 255;
-          if ( p->transinfo[tindex].goal_period > period )
-            period = p->transinfo[tindex].goal_period;
+          /*
+           * Validate the values the device passed to us against our SEEPROM
+           * settings.  We don't have to do this if we aren't replying since
+           * the device isn't allowed to send values greater than the ones
+           * we first sent to it.
+           */
+          new_period = MAX(period, p->transinfo[tindex].goal_period);
+          new_offset = MIN(offset, p->transinfo[tindex].goal_offset);
         }
-  
-        syncrate = aic7xxx_find_syncrate(p, &period, maxsync, &options);
-        aic7xxx_validate_offset(p, syncrate, &offset,
-                                target_scsirate & WIDEXFER);
-        aic7xxx_set_syncrate(p, syncrate, target, channel, period,
-                             offset, options, AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+ 
+        /*
+         * Use our new_period, new_offset, bus_width, and card options
+         * to determine the actual syncrate settings
+         */
+        syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync,
+                                         &trans_options);
+        aic7xxx_validate_offset(p, syncrate, &new_offset, bus_width);
 
         /*
-         * Did we drop to async?  Or are we sending a reply?  If we are,
-         * then we have to make sure that the reply value reflects the proper
-         * settings so we need to set the goal values according to what
-         * we need to send.
+         * Did we drop to async?  If so, send a reply regardless of whether
+         * or not we initiated this negotiation.
          */
-        if ( (offset != saved_offset) ||
-             ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
-              (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) ) )
+        if ((new_offset == 0) && (new_offset != offset))
         {
-          aic7xxx_set_syncrate(p, syncrate, target, channel, period, offset,
-                               options, AHC_TRANS_GOAL|AHC_TRANS_QUITE);
+          p->needsdtr_copy &= ~target_mask;
+          reply = TRUE;
         }
         
         /*
-         * Did we start this, if not, or if we went to low and had to
+         * Did we start this, if not, or if we went too low and had to
          * go async, then send an SDTR back to the target
          */
-        p->needsdtr &= ~target_mask;
-        p->dtr_pending &= ~target_mask;
-        if ( ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
-              (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) ||
-             (offset != saved_offset) )
+        if(reply)
         {
-          reply = TRUE;
-          p->dtr_pending |= target_mask;
+          /* when sending a reply, make sure that the goal settings are
+           * updated along with current and active since the code that
+           * will actually build the message for the sequencer uses the
+           * goal settings as its guidelines.
+           */
+          aic7xxx_set_syncrate(p, syncrate, target, channel, new_period,
+                               new_offset, trans_options,
+                               AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
           scb->flags &= ~SCB_MSGOUT_BITS;
           scb->flags |= SCB_MSGOUT_SDTR;
           aic_outb(p, HOST_MSG, MSG_OUT);
           aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
         }
+        else
+        {
+          aic7xxx_set_syncrate(p, syncrate, target, channel, new_period,
+                               new_offset, trans_options,
+                               AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+          p->needsdtr &= ~target_mask;
+        }
         done = TRUE;
         break;
       }
       case MSG_EXT_WDTR:
       {
-        unsigned char bus_width;
           
         if (p->msg_buf[1] != MSG_EXT_WDTR_LEN)
         {
@@ -5643,7 +5726,8 @@
           break;
         }
 
-        bus_width = p->msg_buf[3];
+        bus_width = new_bus_width = p->msg_buf[3];
+
         if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_WDTR)) ==
              (SCB_MSGOUT_SENT|SCB_MSGOUT_WDTR) )
         {
@@ -5662,7 +5746,7 @@
             } /* We fall through on purpose */
             case MSG_EXT_WDTR_BUS_8_BIT:
             {
-              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+              p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_8_BIT;
               p->needwdtr_copy &= ~target_mask;
               break;
             }
@@ -5671,29 +5755,40 @@
               break;
             }
           }
-          p->dtr_pending &= ~target_mask;
           p->needwdtr &= ~target_mask;
+          aic7xxx_set_width(p, target, channel, lun, new_bus_width,
+                            AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
         }
         else
         {
-          if ( !(p->dev_flags[tindex] & DEVICE_SCANNED) )
+          if ( !(p->dev_flags[tindex] & DEVICE_DTR_SCANNED) )
           {
             /* 
              * Well, we now know the WDTR and SYNC caps of this device since
              * it contacted us first, mark it as such and copy the user stuff
              * over to the goal stuff.
              */
-            p->transinfo[tindex].goal_period =
-              p->transinfo[tindex].user_period;
+            if( (p->features & AHC_WIDE) && p->transinfo[tindex].user_width )
+            {
+              p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_16_BIT;
+              p->needwdtr_copy |= target_mask;
+            }
+            
+            /*
+             * Devices that support DT transfers don't start WDTR requests
+             */
+            p->transinfo[tindex].goal_options = 0;
+
             if(p->transinfo[tindex].user_offset)
             {
+              p->needsdtr_copy |= target_mask;
+              p->transinfo[tindex].goal_period =
+                MAX(10,p->transinfo[tindex].user_period);
               if(p->features & AHC_ULTRA2)
               {
                 p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
               }
-              else if( p->transinfo[tindex].user_width &&
-                       (bus_width == MSG_EXT_WDTR_BUS_16_BIT) &&
-                       p->features & AHC_WIDE )
+              else if( p->transinfo[tindex].goal_width )
               {
                 p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
               }
@@ -5701,48 +5796,76 @@
               {
                 p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
               }
+            } else {
+              p->needsdtr_copy &= ~target_mask;
+              p->transinfo[tindex].goal_period = 255;
+              p->transinfo[tindex].goal_offset = 0;
             }
-            p->transinfo[tindex].goal_width =
-              p->transinfo[tindex].user_width;
-            p->needwdtr_copy |= target_mask;
-            p->needsdtr_copy |= target_mask;
+            
+            p->dev_flags[tindex] |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR;
           }
-          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          else if ((p->needwdtr_copy & target_mask) == 0)
           {
-            printk(INFO_LEAD "Received pre-emptive WDTR message from "
-                   "target.\n", p->host_no, CTL_OF_SCB(scb));
-          }
+            /*
+             * This is a preemptive message from the target, we've already
+             * scanned this target and set our options for it, and we
+             * don't need a WDTR with this target (for whatever reason),
+             * so reject this incoming WDTR
+             */
+            reject = TRUE;
+            break;
+          }
+
+          /* The device is sending this message first and we have to reply */
+          reply = TRUE;
+
+          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
+            printk(INFO_LEAD "Received pre-emptive WDTR message from "
+                   "target.\n", p->host_no, CTL_OF_SCB(scb));
+          }
           switch(bus_width)
           {
-            default:
+            case MSG_EXT_WDTR_BUS_16_BIT:
             {
               if ( (p->features & AHC_WIDE) &&
                    (p->transinfo[tindex].goal_width ==
                     MSG_EXT_WDTR_BUS_16_BIT) )
               {
-                bus_width = MSG_EXT_WDTR_BUS_16_BIT;
+                new_bus_width = MSG_EXT_WDTR_BUS_16_BIT;
                 break;
               }
             } /* Fall through if we aren't a wide card */
+            default:
             case MSG_EXT_WDTR_BUS_8_BIT:
             {
               p->needwdtr_copy &= ~target_mask;
-              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
-              aic7xxx_set_width(p, target, channel, lun, bus_width,
-                                AHC_TRANS_GOAL|AHC_TRANS_QUITE);
+              new_bus_width = MSG_EXT_WDTR_BUS_8_BIT;
               break;
             }
           }
-          reply = TRUE;
           scb->flags &= ~SCB_MSGOUT_BITS;
           scb->flags |= SCB_MSGOUT_WDTR;
           p->needwdtr &= ~target_mask;
-          p->dtr_pending |= target_mask;
+          if((p->dtr_pending & target_mask) == 0)
+          {
+            /* there is no other command with SCB_DTR_SCB already set that will
+             * trigger the release of the dtr_pending bit.  Both set the bit
+             * and set scb->flags |= SCB_DTR_SCB
+             */
+            p->dtr_pending |= target_mask;
+            scb->flags |= SCB_DTR_SCB;
+          }
           aic_outb(p, HOST_MSG, MSG_OUT);
           aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+          /* when sending a reply, make sure that the goal settings are
+           * updated along with current and active since the code that
+           * will actually build the message for the sequencer uses the
+           * goal settings as its guidelines.
+           */
+          aic7xxx_set_width(p, target, channel, lun, new_bus_width,
+                          AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
         }
-        aic7xxx_set_width(p, target, channel, lun, bus_width,
-                          AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
         
         /*
          * By virtue of the SCSI spec, a WDTR message negates any existing
@@ -5759,10 +5882,6 @@
       }
       case MSG_EXT_PPR:
       {
-        unsigned char bus_width, trans_options, new_trans_options;
-        unsigned int period, offset;
-        unsigned char maxsync, saved_offset;
-        struct aic7xxx_syncrate *syncrate;
         
         if (p->msg_buf[1] != MSG_EXT_PPR_LEN)
         {
@@ -5775,9 +5894,9 @@
           break;
         }
 
-        period = p->msg_buf[3];
-        offset = saved_offset = p->msg_buf[5];
-        bus_width = p->msg_buf[6];
+        period = new_period = p->msg_buf[3];
+        offset = new_offset = p->msg_buf[5];
+        bus_width = new_bus_width = p->msg_buf[6];
         trans_options = new_trans_options = p->msg_buf[7] & 0xf;
 
         if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
@@ -5787,22 +5906,6 @@
                  trans_options);
         }
 
-        if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
-            !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
-        {
-          if(p->features & AHC_ULTRA3)
-          {
-            maxsync = AHC_SYNCRATE_ULTRA3;
-          }
-          else
-          {
-            maxsync = AHC_SYNCRATE_ULTRA2;
-          }
-        }
-        else
-        {
-          maxsync = AHC_SYNCRATE_ULTRA;
-        }
         /*
          * We might have a device that is starting negotiation with us
          * before we can start up negotiation with it....be prepared to
@@ -5811,13 +5914,22 @@
          */
         if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR)) !=
              (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR) )
-        {
-          reply = TRUE;
-          scb->flags &= ~SCB_MSGOUT_BITS;
-          scb->flags |= SCB_MSGOUT_PPR;
-	  p->dev_flags[tindex] |= DEVICE_SCSI_3;
-          if (!(p->dev_flags[tindex] & DEVICE_SCANNED))
-          {
+        { 
+          /* Have we scanned the device yet? */
+          if (!(p->dev_flags[tindex] & DEVICE_DTR_SCANNED))
+          {
+            /* The device is electing to use PPR messages, so we will too until
+             * we know better */
+            p->needppr |= target_mask;
+            p->needppr_copy |= target_mask;
+            p->needsdtr &= ~target_mask;
+            p->needsdtr_copy &= ~target_mask;
+            p->needwdtr &= ~target_mask;
+            p->needwdtr_copy &= ~target_mask;
+          
+            /* We know the device is SCSI-3 compliant due to PPR */
+            p->dev_flags[tindex] |= DEVICE_SCSI_3;
+          
             /*
              * Not only is the device starting this up, but it also hasn't
              * been scanned yet, so this would likely be our TUR or our
@@ -5826,15 +5938,19 @@
              * if we didn't find a SEEPROM, we stuffed default values into
              * the user settings anyway, so use those in all cases.
              */
-            p->transinfo[tindex].goal_period =
-              p->transinfo[tindex].user_period;
+            p->transinfo[tindex].goal_width =
+              p->transinfo[tindex].user_width;
             if(p->transinfo[tindex].user_offset)
             {
+              p->transinfo[tindex].goal_period =
+                p->transinfo[tindex].user_period;
+              p->transinfo[tindex].goal_options =
+                p->transinfo[tindex].user_options;
               if(p->features & AHC_ULTRA2)
               {
                 p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
               }
-              else if( p->transinfo[tindex].user_width &&
+              else if( p->transinfo[tindex].goal_width &&
                        (bus_width == MSG_EXT_WDTR_BUS_16_BIT) &&
                        p->features & AHC_WIDE )
               {
@@ -5845,117 +5961,142 @@
                 p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
               }
             }
-            p->transinfo[tindex].goal_width =
-              p->transinfo[tindex].user_width;
-            p->transinfo[tindex].goal_options =
-              p->transinfo[tindex].user_options;
+            else
+            {
+              p->transinfo[tindex].goal_period = 255;
+              p->transinfo[tindex].goal_offset = 0;
+              p->transinfo[tindex].goal_options = 0;
+            }
+            p->dev_flags[tindex] |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR;
+          }
+          else if ((p->needppr_copy & target_mask) == 0)
+          {
+            /*
+             * This is a preemptive message from the target, we've already
+             * scanned this target and set our options for it, and we
+             * don't need a PPR with this target (for whatever reason),
+             * so reject this incoming PPR
+             */
+            reject = TRUE;
+            break;
           }
+
+          /* The device is sending this message first and we have to reply */
+          reply = TRUE;
+          
           if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
           {
             printk(INFO_LEAD "Received pre-emptive PPR message from "
                    "target.\n", p->host_no, CTL_OF_SCB(scb));
           }
-          if ( !p->transinfo[tindex].goal_offset )
-            period = 255;
-          if ( p->transinfo[tindex].goal_period > period )
-            period = p->transinfo[tindex].goal_period;
-          if ( p->transinfo[tindex].goal_options == 0 )
-            new_trans_options = 0;
-          switch(bus_width)
+
+        }
+
+        switch(bus_width)
+        {
+          case MSG_EXT_WDTR_BUS_16_BIT:
           {
-            default:
-            {
-              if ( (p->features & AHC_WIDE) &&
-                   (p->transinfo[tindex].goal_width ==
-                    MSG_EXT_WDTR_BUS_16_BIT) )
-              {
-                bus_width = MSG_EXT_WDTR_BUS_16_BIT;
-                break;
-              }
-            } /* Fall through if we aren't a wide card */
-            case MSG_EXT_WDTR_BUS_8_BIT:
+            if ( (p->transinfo[tindex].goal_width ==
+                  MSG_EXT_WDTR_BUS_16_BIT) && p->features & AHC_WIDE)
             {
-              p->needwdtr_copy &= ~target_mask;
-              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
-              aic7xxx_set_width(p, target, channel, lun, bus_width,
-                                AHC_TRANS_GOAL|AHC_TRANS_QUITE);
               break;
             }
           }
-          if ( (p->transinfo[tindex].goal_period > 9) ||
-               (p->transinfo[tindex].goal_options == 0) )
+          default:
           {
-            scb->flags &= ~SCB_MSGOUT_BITS;
-            reject = TRUE;
-            reply = FALSE;
-            p->needppr &= ~(1 << tindex);
-            p->needppr_copy &= ~(1 << tindex);
-            if ( p->transinfo[tindex].goal_offset )
-            {
-              p->needsdtr |= (1 << tindex);
-              p->needsdtr_copy |= (1 << tindex);
-            }
-            if ( p->transinfo[tindex].goal_width )
-            {
-              p->needwdtr |= (1 << tindex);
-              p->needwdtr_copy |= (1 << tindex);
+            if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
+                 ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) ||
+                  (aic7xxx_verbose > 0xffff)) )
+            {
+              reply = TRUE;
+              printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n",
+                p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width));
             }
+          } /* We fall through on purpose */
+          case MSG_EXT_WDTR_BUS_8_BIT:
+          {
+            /*
+             * According to the spec, if we aren't wide, we also can't be
+             * Dual Edge so clear the options byte
+             */
+            new_trans_options = 0;
+            new_bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+            break;
           }
         }
+
+        if(reply)
+        {
+          /* when sending a reply, make sure that the goal settings are
+           * updated along with current and active since the code that
+           * will actually build the message for the sequencer uses the
+           * goal settings as its guidelines.
+           */
+          aic7xxx_set_width(p, target, channel, lun, new_bus_width,
+                            AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+          syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync,
+                                           &new_trans_options);
+          aic7xxx_validate_offset(p, syncrate, &new_offset, new_bus_width);
+          aic7xxx_set_syncrate(p, syncrate, target, channel, new_period,
+                               new_offset, new_trans_options,
+                               AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+        }
         else
         {
-          switch(bus_width)
+          aic7xxx_set_width(p, target, channel, lun, new_bus_width,
+                            AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+          syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync,
+                                           &new_trans_options);
+          aic7xxx_validate_offset(p, syncrate, &new_offset, new_bus_width);
+          aic7xxx_set_syncrate(p, syncrate, target, channel, new_period,
+                               new_offset, new_trans_options,
+                               AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+        }
+
+        /*
+         * As it turns out, if we don't *have* to have PPR messages, then
+         * configure ourselves not to use them since that makes some
+         * external drive chassis work (those chassis can't parse PPR
+         * messages and they mangle the SCSI bus until you send a WDTR
+         * and SDTR that they can understand).
+         */
+        if(new_trans_options == 0)
+        {
+          p->needppr &= ~target_mask;
+          p->needppr_copy &= ~target_mask;
+          if(new_offset)
           {
-            default:
-            {
-              reject = TRUE;
-              if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
-                   ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) ||
-                    (aic7xxx_verbose > 0xffff)) )
-              {
-                printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n",
-                  p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width));
-              }
-            } /* We fall through on purpose */
-            case MSG_EXT_WDTR_BUS_8_BIT:
-            {
-              /*
-               * According to the spec, if we aren't wide, we also can't be
-               * Dual Edge so clear the options byte
-               */
-              new_trans_options = 0;
-              bus_width = MSG_EXT_WDTR_BUS_8_BIT;
-              break;
-            }
-            case MSG_EXT_WDTR_BUS_16_BIT:
-            {
-              break;
-            }
+            p->needsdtr |= target_mask;
+            p->needsdtr_copy |= target_mask;
+          }
+          if (new_bus_width)
+          {
+            p->needwdtr |= target_mask;
+            p->needwdtr_copy |= target_mask;
           }
         }
 
-        if ( !reject )
+        if((new_offset == 0) && (offset != 0))
         {
-          aic7xxx_set_width(p, target, channel, lun, bus_width,
-                            AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
-          syncrate = aic7xxx_find_syncrate(p, &period, maxsync,
-                                           &new_trans_options);
-          aic7xxx_validate_offset(p, syncrate, &offset, bus_width);
-          aic7xxx_set_syncrate(p, syncrate, target, channel, period,
-                               offset, new_trans_options,
-                               AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+          /*
+           * Oops, the syncrate went to low for this card and we fell off
+           * to async (should never happen with a device that uses PPR
+           * messages, but have to be complete)
+           */
+          reply = TRUE;
         }
 
-        p->dtr_pending &= ~target_mask;
-        p->needppr &= ~target_mask;
         if(reply)
         {
-          p->dtr_pending |= target_mask;
           scb->flags &= ~SCB_MSGOUT_BITS;
           scb->flags |= SCB_MSGOUT_PPR;
           aic_outb(p, HOST_MSG, MSG_OUT);
           aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
         }
+        else
+        {
+          p->needppr &= ~target_mask;
+        }
         done = TRUE;
         break;
       }
@@ -6193,16 +6334,14 @@
         printerror = 0;
       }
     }
-    if ( (scb != NULL) &&
-         (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)]) )
+    if ( (scb != NULL) && (scb->flags & SCB_DTR_SCB) ) 
     {
       /*
-       * This might be a SCSI-3 device that is dropping the bus due to
-       * errors and signalling that we should reduce the transfer speed.
-       * All we have to do is complete this command (since it's a negotiation
-       * command already) and the checksum routine should flag an error and
-       * reduce the speed setting and renegotiate.  We call the reset routing
-       * just to clean out the hardware from this scb.
+       * Hmmm...error during a negotiation command.  Either we have a
+       * borken bus, or the device doesn't like our negotiation message.
+       * Since we check the INQUIRY data of a device before sending it
+       * negotiation messages, assume the bus is borken for whatever
+       * reason.  Complete the command.
        */
       printerror = 0;
       aic7xxx_reset_device(p, target, channel, ALL_LUNS, scb->hscb->tag);
@@ -6334,19 +6473,6 @@
         cmd->result = 0;
         scb = NULL;
       }
-      else if (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)])
-      {
-        /*
-         * Turn off the needsdtr, needwdtr, and needppr bits since this device
-         * doesn't seem to exist.
-         */
-        p->needppr &= ~(0x01 << TARGET_INDEX(scb->cmd));
-        p->needppr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd));
-        p->needsdtr &= ~(0x01 << TARGET_INDEX(scb->cmd));
-        p->needsdtr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd));
-        p->needwdtr &= ~(0x01 << TARGET_INDEX(scb->cmd));
-        p->needwdtr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd));
-      }
     }
     /*
      * Keep the sequencer from trying to restart any selections
@@ -6469,7 +6595,6 @@
       }
     }
     else if( (lastphase == P_MESGOUT) &&
-             (cmd == p->dev_dtr_cmnd[tindex]) &&
              (scb->flags & SCB_MSGOUT_PPR) )
     {
       /*
@@ -6488,7 +6613,6 @@
       aic7xxx_set_syncrate(p, NULL, scb->cmd->target, scb->cmd->channel, 0, 0,
                            0, AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
       p->transinfo[tindex].goal_options = 0;
-      p->dtr_pending &= ~(1 << tindex);
       scb->flags &= ~SCB_MSGOUT_BITS;
       if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
       {
@@ -6511,87 +6635,6 @@
       }
       scb = NULL;
     }
-    else if(p->dev_flags[tindex] & DEVICE_PARITY_ERROR)
-    {
-      struct aic7xxx_syncrate *syncrate;
-      unsigned int period = p->transinfo[tindex].cur_period;
-      unsigned char options = p->transinfo[tindex].cur_options;
-      /*
-       * oops, we had a failure, lower the transfer rate and try again.  It's
-       * worth noting here that it might be wise to also check for typical
-       * wide setting on narrow cable type problems and try disabling wide
-       * instead of slowing down if those exist.  That's hard to do with simple
-       * checksums though.
-       */
-      printk(WARN_LEAD "Parity error during %s phase.\n",
-             p->host_no, CTL_OF_SCB(scb), phase);
-      if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL)
-      {
-        syncrate++;
-        if( (syncrate->rate[0] != NULL) &&
-            (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) )
-        {
-          p->transinfo[tindex].goal_period = syncrate->period;
-          if( p->transinfo[tindex].goal_period > 9 )
-          {
-            p->transinfo[tindex].goal_options = 0;
-            p->needppr &= ~(1<<tindex);
-            p->needsdtr |= (1<<tindex);
-            p->needppr_copy &= ~(1<<tindex);
-            p->needsdtr_copy |= (1<<tindex);
-            if (p->transinfo[tindex].goal_width)
-            {
-              p->needwdtr |= (1<<tindex);
-              p->needwdtr_copy |= (1<<tindex);
-            }
-          }
-        }
-        else if (p->transinfo[tindex].goal_width)
-        {
-          p->transinfo[tindex].goal_width = 0;
-          p->needwdtr &= ~(1<<tindex);
-          p->needwdtr_copy &= ~(1<<tindex);
-          p->transinfo[tindex].goal_offset =
-            p->transinfo[tindex].user_offset;
-          p->transinfo[tindex].goal_period =
-            p->transinfo[tindex].user_period;
-          p->transinfo[tindex].goal_options =
-            p->transinfo[tindex].user_options;
-          if( p->transinfo[tindex].goal_period <= 9 )
-          {
-            p->needppr |= (1<<tindex);
-            p->needsdtr &= ~(1<<tindex);
-            p->needppr_copy |= (1<<tindex);
-            p->needsdtr_copy &= ~(1<<tindex);
-          }
-          else
-          {
-            p->needppr &= ~(1<<tindex);
-            p->needsdtr |= (1<<tindex);
-            p->needppr_copy &= ~(1<<tindex);
-            p->needsdtr_copy |= (1<<tindex);
-          }
-        }
-        else
-        {
-          p->transinfo[tindex].goal_offset = 0;
-          p->transinfo[tindex].goal_period = 255;
-          p->transinfo[tindex].goal_options = 0;
-          p->transinfo[tindex].goal_width = 0;
-          p->needppr &= ~(1<<tindex);
-          p->needsdtr &= ~(1<<tindex);
-          p->needwdtr &= ~(1<<tindex);
-          p->needppr_copy &= ~(1<<tindex);
-          p->needsdtr_copy &= ~(1<<tindex);
-          p->needwdtr_copy &= ~(1<<tindex);
-        }
-      }
-      p->dev_flags[tindex] &= ~DEVICE_PARITY_ERROR;
-    }
-    else
-    {
-      p->dev_flags[tindex] |= DEVICE_PARITY_ERROR;
-    }
 
     /*
      * We've set the hardware to assert ATN if we get a parity
@@ -6860,34 +6903,11 @@
     else if (scb->flags & SCB_SENSE)
     {
       char *buffer = &scb->cmd->sense_buffer[0];
-      if (scb->cmd == p->dev_dtr_cmnd[tindex])
-      {
-        struct aic7xxx_scb *old_scb;
-        /*
-         * We have valid sense data, send it back immediately.
-         */
-        old_scb = p->scb_data->scb_array[scb->cmd->next->tag];
-        *old_scb->cmd->sense_buffer = *scb->cmd->sense_buffer;
-        old_scb->hscb->target_status = scb->hscb->target_status;
-        old_scb->cmd->result = scb->hscb->target_status;
-        old_scb->cmd->result |= (DID_ERROR << 16);
-        aic7xxx_status(old_scb->cmd) = scb->hscb->target_status;
-        scbq_remove(&p->waiting_scbs, old_scb);
-        scbq_remove(&p->delayed_scbs[tindex], old_scb);
-        scb->cmd->next = NULL;
-	aic7xxx_done(p, scb);
-        aic7xxx_done(p, old_scb);
-	continue;
-      } 
-      else if (buffer[12] == 0x47 || buffer[12] == 0x54)
+
+      if (buffer[12] == 0x47 || buffer[12] == 0x54)
       {
         /*
-         * SCSI errors, run domain validation and re-run negotiation
-         */
-        p->needdv |= (1<<tindex);
-        /*
-         * Signal that we need to re-negotiate things, this also gets us our
-         * INQUIRY command to re-checksum off of.
+         * Signal that we need to re-negotiate things.
          */
         p->needppr |= (p->needppr_copy & (1<<tindex));
         p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
@@ -6900,7 +6920,18 @@
       case BUSY:
         scb->hscb->target_status = 0;
         scb->cmd->result = 0;
+        scb->hscb->residual_SG_segment_count = 0;
+        scb->hscb->residual_data_count[0] = 0;
+        scb->hscb->residual_data_count[1] = 0;
+        scb->hscb->residual_data_count[2] = 0;
         aic7xxx_error(scb->cmd) = DID_OK;
+        aic7xxx_status(scb->cmd) = 0;
+        /*
+         * The QUEUE_FULL/BUSY handler in aic7xxx_seqint takes care of putting
+         * this command on a timer and allowing us to retry it.  Here, we
+         * just 0 out a few values so that they don't carry through to when
+         * the command finally does complete.
+         */
         break;
       default:
         cmd = scb->cmd;
@@ -7065,33 +7096,27 @@
   if(!p)
     return;
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,95)
-  if(test_and_set_bit(AHC_IN_ISR_BIT, &p->flags))
-  {
-    return;
-  }
   spin_lock_irqsave(&io_request_lock, cpu_flags);
+  p->flags |= AHC_IN_ISR;
   do
   {
     aic7xxx_isr(irq, dev_id, regs);
   } while ( (aic_inb(p, INTSTAT) & INT_PEND) );
   aic7xxx_done_cmds_complete(p);
   aic7xxx_run_waiting_queues(p);
-  clear_bit(AHC_IN_ISR_BIT, &p->flags);
+  p->flags &= ~AHC_IN_ISR;
   spin_unlock_irqrestore(&io_request_lock, cpu_flags);
 #else
-  if(set_bit(AHC_IN_ISR_BIT, (int *)&p->flags))
-  {
-    return;
-  }
   DRIVER_LOCK
+  p->flags |= AHC_IN_ISR;
   do
   {
     aic7xxx_isr(irq, dev_id, regs);
   } while ( (aic_inb(p, INTSTAT) & INT_PEND) );
+  p->flags &= ~AHC_IN_ISR;
   DRIVER_UNLOCK
   aic7xxx_done_cmds_complete(p);
   aic7xxx_run_waiting_queues(p);
-  clear_bit(AHC_IN_ISR_BIT, (int *)&p->flags);
 #endif
 }
 
@@ -9012,22 +9037,6 @@
     kfree(p->scb_data);
   }
 
-  /*
-   * Free any alloced Scsi_Cmnd structures that might be around for
-   * negotiation purposes....
-   */
-  for (i = 0; i < MAX_TARGETS; i++)
-  {
-    if(p->dev_dtr_cmnd[i])
-    {
-      if(p->dev_dtr_cmnd[i]->request_buffer)
-      {
-        kfree(p->dev_dtr_cmnd[i]->request_buffer);
-      }
-      kfree(p->dev_dtr_cmnd[i]);
-    }
-  }
-
 }
 
 /*+F*************************************************************************
@@ -9413,7 +9422,7 @@
   }
   aic_outb(p, ~(p->discenable & 0xFF), DISC_DSB);
   aic_outb(p, ~((p->discenable >> 8) & 0xFF), DISC_DSB + 1);
-  p->needppr = p->needppr_copy = p->needdv = 0;
+  p->needppr = p->needppr_copy = 0;
   p->needwdtr = p->needwdtr_copy;
   p->needsdtr = p->needsdtr_copy;
   p->dtr_pending = 0;
@@ -9471,53 +9480,165 @@
 
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_detect
+ *   aic7xxx_configure_bugs
  *
  * Description:
- *   Try to detect and register an Adaptec 7770 or 7870 SCSI controller.
- *
- * XXX - This should really be called aic7xxx_probe().  A sequence of
- *       probe(), attach()/detach(), and init() makes more sense than
- *       one do-it-all function.  This may be useful when (and if) the
- *       mid-level SCSI code is overhauled.
+ *   Take the card passed in and set the appropriate bug flags based upon
+ *   the card model.  Also make any changes needed to device registers or
+ *   PCI registers while we are here.
  *-F*************************************************************************/
-int
-aic7xxx_detect(Scsi_Host_Template *template)
+static void
+aic7xxx_configure_bugs(struct aic7xxx_host *p)
 {
-  struct aic7xxx_host *temp_p = NULL;
-  struct aic7xxx_host *current_p = NULL;
-  struct aic7xxx_host *list_p = NULL;
-  int found = 0;
-#if defined(__i386__) || defined(__alpha__)
-  ahc_flag_type flags = 0;
-  int type;
-#endif
-  unsigned char sxfrctl1;
-#if defined(__i386__) || defined(__alpha__)
-  unsigned char hcntrl, hostconf;
-  unsigned int slot, base;
-#endif
-
-#ifdef MODULE
-  /*
-   * If we are called as a module, the aic7xxx pointer may not be null
-   * and it would point to our bootup string, just like on the lilo
-   * command line.  IF not NULL, then process this config string with
-   * aic7xxx_setup
-   */
-  if(aic7xxx)
-    aic7xxx_setup(aic7xxx, NULL);
-  if(dummy_buffer[0] != 'P')
-    printk(KERN_WARNING "aic7xxx: Please read the file /usr/src/linux/drivers"
-      "/scsi/README.aic7xxx\n"
-      "aic7xxx: to see the proper way to specify options to the aic7xxx "
-      "module\n"
-      "aic7xxx: Specifically, don't use any commas when passing arguments to\n"
-      "aic7xxx: insmod or else it might trash certain memory areas.\n");
+  unsigned char pci_rev;
+  unsigned short tmp_word;
+ 
+  if((p->chip & ~AHC_CHIPID_MASK) == AHC_PCI)
+  {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,92)
+      pcibios_read_config_byte(p->pci_bus, p->pci_device_fn,
+            PCI_REVISION_ID, &pci_rev);
+#else
+      pci_read_config_byte(p->pdev, PCI_REVISION_ID, &pci_rev);
 #endif
+  }
 
-  template->proc_dir = &proc_scsi_aic7xxx;
-  template->sg_tablesize = AIC7XXX_MAX_SG;
+  switch(p->chip & AHC_CHIPID_MASK)
+  {
+    case AHC_AIC7860:
+      if(pci_rev >= 1)
+      {
+        p->bugs |= AHC_BUG_PCI_2_1_RETRY;
+      }
+      /* fall through */
+    case AHC_AIC7850:
+    case AHC_AIC7870:
+      p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI;
+      break;
+    case AHC_AIC7880:
+      p->bugs |= AHC_BUG_TMODE_WIDEODD;
+      if(pci_rev >= 1)
+      {
+        p->bugs |= AHC_BUG_PCI_2_1_RETRY;
+      }
+      else
+      {
+        p->bugs |= AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI;
+      }
+      break;
+    case AHC_AIC7890:
+      if(pci_rev == 0)
+      {
+        p->bugs |= AHC_BUG_AUTOFLUSH | AHC_BUG_CACHETHEN;
+      }
+      break;
+    case AHC_AIC7892:
+      p->bugs |= AHC_BUG_SCBCHAN_UPLOAD;
+      break;
+    case AHC_AIC7895:
+      p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_PCI_2_1_RETRY |
+                 AHC_BUG_CACHETHEN;
+      if(pci_rev <= 3)
+      {
+        p->bugs |= AHC_BUG_PCI_MWI;
+      }
+      break;
+    case AHC_AIC7896:
+      p->bugs |= AHC_BUG_CACHETHEN_DIS;
+      break;
+    case AHC_AIC7899:
+      p->bugs |= AHC_BUG_SCBCHAN_UPLOAD;
+      break;
+    default:
+      /* Nothing to do */
+      break;
+  }
+
+  /*
+   * Now handle the bugs that require PCI register or card register tweaks
+   */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,92)
+  pcibios_read_config_word(p->pci_bus, p->pci_device_fn,
+            PCI_COMMAND, &tmp_word);
+#else
+  pci_read_config_word(p->pdev, PCI_COMMAND, &tmp_word);
+#endif
+  if(p->bugs & AHC_BUG_PCI_MWI)
+  {
+    tmp_word &= ~PCI_COMMAND_INVALIDATE;
+  }
+  else
+  {
+    tmp_word |= PCI_COMMAND_INVALIDATE;
+  }
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,92)
+  pcibios_write_config_word(p->pci_bus, p->pci_device_fn,
+            PCI_COMMAND, tmp_word);
+#else
+  pci_write_config_word(p->pdev, PCI_COMMAND, tmp_word);
+#endif
+
+  if(p->bugs & AHC_BUG_CACHETHEN)
+  {
+    aic_outb(p, aic_inb(p, DSCOMMAND0) & ~CACHETHEN, DSCOMMAND0);
+  }
+  else if (p->bugs & AHC_BUG_CACHETHEN_DIS)
+  {
+    aic_outb(p, aic_inb(p, DSCOMMAND0) | CACHETHEN, DSCOMMAND0);
+  }
+
+  return;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_detect
+ *
+ * Description:
+ *   Try to detect and register an Adaptec 7770 or 7870 SCSI controller.
+ *
+ * XXX - This should really be called aic7xxx_probe().  A sequence of
+ *       probe(), attach()/detach(), and init() makes more sense than
+ *       one do-it-all function.  This may be useful when (and if) the
+ *       mid-level SCSI code is overhauled.
+ *-F*************************************************************************/
+int
+aic7xxx_detect(Scsi_Host_Template *template)
+{
+  struct aic7xxx_host *temp_p = NULL;
+  struct aic7xxx_host *current_p = NULL;
+  struct aic7xxx_host *list_p = NULL;
+  int found = 0;
+#if defined(__i386__) || defined(__alpha__)
+  ahc_flag_type flags = 0;
+  int type;
+#endif
+  unsigned char sxfrctl1;
+#if defined(__i386__) || defined(__alpha__)
+  unsigned char hcntrl, hostconf;
+  unsigned int slot, base;
+#endif
+
+#ifdef MODULE
+  /*
+   * If we are called as a module, the aic7xxx pointer may not be null
+   * and it would point to our bootup string, just like on the lilo
+   * command line.  IF not NULL, then process this config string with
+   * aic7xxx_setup
+   */
+  if(aic7xxx)
+    aic7xxx_setup(aic7xxx, NULL);
+  if(dummy_buffer[0] != 'P')
+    printk(KERN_WARNING "aic7xxx: Please read the file /usr/src/linux/drivers"
+      "/scsi/README.aic7xxx\n"
+      "aic7xxx: to see the proper way to specify options to the aic7xxx "
+      "module\n"
+      "aic7xxx: Specifically, don't use any commas when passing arguments to\n"
+      "aic7xxx: insmod or else it might trash certain memory areas.\n");
+#endif
+
+  template->proc_dir = &proc_scsi_aic7xxx;
+  template->sg_tablesize = AIC7XXX_MAX_SG;
 
 
 #ifdef CONFIG_PCI
@@ -10290,6 +10411,14 @@
             aic_outb(temp_p, DFTHRSH_100, DSPCISTATUS);
           }
 
+          /*
+           * Call our function to fixup any bugs that exist on this chipset.
+           * This may muck with PCI settings and other device settings, so
+           * make sure it's after all the other PCI and device register
+           * tweaks so it can back out bad settings on specific broken cards.
+           */
+          aic7xxx_configure_bugs(temp_p);
+
           if ( list_p == NULL )
           {
             list_p = current_p = temp_p;
@@ -10533,6 +10662,11 @@
     }
 
     /*
+     * All the 7770 based chipsets have this bug
+     */
+    temp_p->bugs |= AHC_BUG_TMODE_WIDEODD;
+
+    /*
      * Set the FIFO threshold and the bus off time.
      */
     hostconf = aic_inb(temp_p, HOSTCONF);
@@ -10751,297 +10885,6 @@
   return (found);
 }
 
-static void aic7xxx_build_negotiation_cmnd(struct aic7xxx_host *p,
-                                           Scsi_Cmnd *old_cmd, int tindex);
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_allocate_negotiation_command
- *
- * Description:
- *   allocate the actual command struct and fill in the gaps...
- *-F*************************************************************************/
-static Scsi_Cmnd *
-aic7xxx_allocate_negotiation_command(struct aic7xxx_host *p,
-                                     Scsi_Cmnd *old_cmd, int tindex)
-{
-  Scsi_Cmnd *cmd;
-  char *buffer;
-
-  if (!(p->dev_dtr_cmnd[tindex] = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC)) )
-  {
-    return(NULL);
-  }
-  if (!(buffer = kmalloc(256, GFP_ATOMIC)))
-  {
-    kfree(p->dev_dtr_cmnd[tindex]);
-    p->dev_dtr_cmnd[tindex] = NULL;
-    return(NULL);
-  }
-  cmd = p->dev_dtr_cmnd[tindex];
-  memset(cmd, 0, sizeof(Scsi_Cmnd));
-  memcpy(cmd, old_cmd, sizeof(Scsi_Cmnd));
-  memset(&cmd->cmnd[0], 0, sizeof(cmd->cmnd));
-  memset(&cmd->data_cmnd[0], 0, sizeof(cmd->data_cmnd));
-  cmd->lun = 0;
-  cmd->request_bufflen = 255;
-  cmd->request_buffer = buffer;
-  cmd->use_sg = cmd->old_use_sg = cmd->sglist_len = 0;
-  cmd->bufflen = 0;
-  cmd->buffer = NULL;
-  cmd->underflow = 0;
-  cmd->cmd_len = 6;
-  cmd->cmnd[0] = cmd->data_cmnd[0] = INQUIRY;
-  cmd->cmnd[1] = cmd->data_cmnd[1] = 0;
-  cmd->cmnd[2] = cmd->data_cmnd[2] = 0;
-  cmd->cmnd[3] = cmd->data_cmnd[3] = 0;
-  cmd->cmnd[4] = cmd->data_cmnd[4] = 255; /* match what scsi.c does here */
-  cmd->cmnd[5] = cmd->data_cmnd[5] = 0;
-  return(cmd);
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_negotiation_complete
- *
- * Description:
- *   Handle completion events for our Negotiation commands.  Clear out the
- *   struct and get it ready for its next use.
- *-F*************************************************************************/
-static void
-aic7xxx_negotiation_complete(Scsi_Cmnd *cmd)
-{
-  unsigned int checksum;
-  int i;
-  int *ibuffer;
-  struct aic7xxx_host *p = (struct aic7xxx_host *)cmd->host->hostdata;
-  int tindex = TARGET_INDEX(cmd);
-  struct aic7xxx_syncrate *syncrate;
-
-  /*
-   * perform our minimalistic domain validation
-   */
-  if(p->dev_flags[tindex] & DEVICE_SCANNED)
-  {
-    ibuffer = (int *)cmd->request_buffer;
-    checksum = 0;
-    for(i = 0; i < (cmd->request_bufflen >> 2); i++)
-    {
-      checksum += ibuffer[i];
-    }
-    if( (checksum != p->dev_checksum[tindex]) &&
-        (p->transinfo[tindex].cur_offset != 0) )
-    {
-      unsigned int period = p->transinfo[tindex].cur_period;
-      unsigned char options = p->transinfo[tindex].cur_options;
-
-      if (p->needdv & (1<<tindex))
-      {
-        /*
-         * oops, we had a failure, lower the transfer rate and try again.  It's
-         * worth noting here that it might be wise to also check for typical
-         * wide setting on narrow cable type problems and try disabling wide
-         * instead of slowing down if those exist.  That's hard to do with simple
-         * checksums though.
-         */
-        if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) 
-        {
-          printk(INFO_LEAD "reducing SCSI transfer speed due to Domain "
-                 "validation failure.\n", p->host_no, CTL_OF_CMD(cmd));
-        }
-        if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL)
-        {
-          syncrate++;
-          if( (syncrate->rate[0] != NULL) &&
-              (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) )
-          {
-            p->transinfo[tindex].goal_period = syncrate->period;
-            if( p->transinfo[tindex].goal_period > 9 )
-            {
-              p->transinfo[tindex].goal_options = 0;
-              p->needppr &= ~(1<<tindex);
-              p->needsdtr |= (1<<tindex);
-              p->needppr_copy &= ~(1<<tindex);
-              p->needsdtr_copy |= (1<<tindex);
-              if (p->transinfo[tindex].goal_width)
-              {
-                p->needwdtr |= (1<<tindex);
-                p->needwdtr_copy |= (1<<tindex);
-              }
-            }
-          }
-          else if (p->transinfo[tindex].goal_width)
-          {
-            p->transinfo[tindex].goal_width = 0;
-            p->needwdtr &= ~(1<<tindex);
-            p->needwdtr_copy &= ~(1<<tindex);
-            p->transinfo[tindex].goal_offset =
-              p->transinfo[tindex].user_offset;
-            p->transinfo[tindex].goal_period =
-              p->transinfo[tindex].user_period;
-            p->transinfo[tindex].goal_options =
-              p->transinfo[tindex].user_options;
-            if( p->transinfo[tindex].goal_period <= 9 )
-            {
-              p->needppr |= (1<<tindex);
-              p->needsdtr &= ~(1<<tindex);
-              p->needppr_copy |= (1<<tindex);
-              p->needsdtr_copy &= ~(1<<tindex);
-            }
-            else
-            {
-              p->needppr &= ~(1<<tindex);
-              p->needsdtr |= (1<<tindex);
-              p->needppr_copy &= ~(1<<tindex);
-              p->needsdtr_copy |= (1<<tindex);
-            }
-          }
-          else
-          {
-            p->transinfo[tindex].goal_offset = 0;
-            p->transinfo[tindex].goal_period = 255;
-            p->transinfo[tindex].goal_options = 0;
-            p->transinfo[tindex].goal_width = 0;
-            p->needppr &= ~(1<<tindex);
-            p->needsdtr &= ~(1<<tindex);
-            p->needwdtr &= ~(1<<tindex);
-            p->needppr_copy &= ~(1<<tindex);
-            p->needsdtr_copy &= ~(1<<tindex);
-            p->needwdtr_copy &= ~(1<<tindex);
-          }
-        }
-        p->needdv &= ~(1<<tindex);
-      }
-      else
-      {
-        if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) 
-        {
-          printk(INFO_LEAD "Performing Domain validation.\n",
-                 p->host_no, CTL_OF_CMD(cmd));
-        }
-        /*
-         * Update the checksum in case the INQUIRY data has changed, maybe
-         * in relation to a change in the mode pages, or whatever.
-         */
-        p->dev_checksum[tindex] = checksum;
-        /*
-         * Signal that we are trying out the domain validation
-         */
-        p->needdv |= (1<<tindex);
-        /*
-         * Signal that we need to re-negotiate things, this also gets us our
-         * INQUIRY command to re-checksum off of.
-         */
-        p->needppr |= (p->needppr_copy & (1<<tindex));
-        p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
-        p->needwdtr |= (p->needwdtr_copy & (1<<tindex));
-      }
-    } 
-    else
-    {
-      if( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
-          (p->needdv & (1<<tindex)) )
-      {
-        printk(INFO_LEAD "Successfully completed Domain validation.\n",
-               p->host_no, CTL_OF_CMD(cmd));
-      }
-      /*
-       * We successfully did our checksum, so don't leave the needdv flag set
-       * in case we might have set it last time through.
-       */
-      p->needdv &= ~(1<<tindex);
-    }
-  }
-
-  p->dtr_pending &= ~(0x01 << tindex);
-  /*
-   * This looks recursive in the extreme, but if this was a WDTR negotiation
-   * and we didn't follow up with SDTR yet, then this will get it started.
-   * For all other cases, this should work out to be a no-op, unless we are
-   * doing domain validation and happen to need a new negotiation command.
-   *
-   * In case we don't want this to go any further, the cmdcmplt interrupt
-   * handler will NULL out the cmd->next entry so that the real SCSI command
-   * can be sent back to the mid layer code with SENSE data intact.  We'll
-   * finish things up when the cmd gets sent back down to us, so no worries.
-   */
-  if(cmd->next)
-  {
-    aic7xxx_build_negotiation_cmnd(p, cmd->next, tindex);
-  }
-  return;
-}
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_build_negotiation_command
- *
- * Description:
- *   Build a Scsi_Cmnd structure to perform negotiation with or else send
- *   a pre-built command specifically for this purpose.
- *-F*************************************************************************/
-static void
-aic7xxx_build_negotiation_cmnd(struct aic7xxx_host *p, Scsi_Cmnd *old_cmd,
-  int tindex)
-{
-
-  if ( !(p->dtr_pending & (1<<tindex)) &&
-       ( (p->needppr & (1<<tindex)) ||
-         (p->needwdtr & (1<<tindex)) ||
-         (p->needsdtr & (1<<tindex)) ) )
-  {
-    if ( (p->dev_dtr_cmnd[tindex] == NULL) &&
-         (aic7xxx_allocate_negotiation_command(p, old_cmd, tindex) == NULL) )
-    {
-      return;
-    }
-    /*
-     * Before sending this thing out, we also make the cmd->next pointer
-     * point to the real command so we can stuff any possible SENSE data
-     * into the real command instead of this fake command.  This has to be
-     * done each time the command is built, not just the first time, hence
-     * it's outside of the above if()...
-     */
-    p->dev_dtr_cmnd[tindex]->next = old_cmd;
-    /*
-     * Clear the buffer so checksums come out right....
-     */
-    memset(p->dev_dtr_cmnd[tindex]->request_buffer, 0,
-           p->dev_dtr_cmnd[tindex]->request_bufflen);
-    /*
-     * Remove any commands for this particular device that might be on the
-     * waiting_scbs queue or qinfifo so that this command goes out first.
-     * This is vital for our implementation of domain validation.
-     */
-    pause_sequencer(p);
-    aic7xxx_search_qinfifo(p, old_cmd->target, old_cmd->channel, ALL_LUNS,
-                SCB_LIST_NULL, 0, TRUE, &p->delayed_scbs[tindex]);
-    unpause_sequencer(p, FALSE);
-    {
-      struct aic7xxx_scb *scb, *next;
-
-      scb = p->waiting_scbs.head;
-      while(scb != NULL)
-      {
-        if( aic7xxx_match_scb(p, scb, old_cmd->target, old_cmd->channel,
-                              ALL_LUNS, SCB_LIST_NULL) )
-        {
-          next = scb->q_next;
-          scbq_remove(&p->waiting_scbs, scb);
-          scbq_insert_tail(&p->delayed_scbs[tindex], scb);
-          scb = next;
-        }
-        else
-        {
-          scb = scb->q_next;
-        }
-      }
-    }
-    aic7xxx_queue(p->dev_dtr_cmnd[tindex], 
-                  aic7xxx_negotiation_complete);
-  }
-}
-
 #ifdef AIC7XXX_VERBOSE_DEBUGGING
 /*+F*************************************************************************
  * Function:
@@ -11090,7 +10933,7 @@
    */
   hscb->control = 0;
   scb->tag_action = 0;
-  cmd->tag = hscb->tag;
+
   if (p->discenable & mask)
   {
     hscb->control |= DISCENB;
@@ -11119,34 +10962,29 @@
       }
     }
   }
-  if ( cmd == p->dev_dtr_cmnd[tindex] )
+  if ( !(p->dtr_pending & mask) &&
+        ( (p->needppr & mask) ||
+          (p->needwdtr & mask) ||
+          (p->needsdtr & mask) ) &&
+        (p->dev_flags[tindex] & DEVICE_DTR_SCANNED) )
   {
     p->dtr_pending |= mask;
     scb->tag_action = 0;
-    if (p->dev_flags[tindex] & DEVICE_SCANNED)
+    hscb->control &= DISCENB;
+    hscb->control |= MK_MESSAGE;
+    if(p->needppr & mask)
     {
-      hscb->control &= DISCENB;
-      hscb->control |= MK_MESSAGE;
-      if(p->needppr & mask)
-      {
-        scb->flags |= SCB_MSGOUT_PPR;
-      }
-      else if(p->needwdtr & mask)
-      {
-        scb->flags |= SCB_MSGOUT_WDTR;
-      }
-      else if(p->needsdtr & mask)
-      {
-        scb->flags |= SCB_MSGOUT_SDTR;
-      }
+      scb->flags |= SCB_MSGOUT_PPR;
     }
-  }
-  if ( !(p->dtr_pending & mask) &&
-        ( (p->needppr & mask) ||
-          (p->needwdtr & mask) ||
-          (p->needsdtr & mask) ) )
-  {
-    aic7xxx_build_negotiation_cmnd(p, cmd, tindex);
+    else if(p->needwdtr & mask)
+    {
+      scb->flags |= SCB_MSGOUT_WDTR;
+    }
+    else if(p->needsdtr & mask)
+    {
+      scb->flags |= SCB_MSGOUT_SDTR;
+    }
+    scb->flags |= SCB_DTR_SCB;
   }
   hscb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
         ((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
@@ -11285,50 +11123,58 @@
     aic7xxx_allocate_scb(p);
     DRIVER_UNLOCK
     scb = scbq_remove_head(&p->scb_data->free_scbs);
-  }
-  if (scb == NULL)
-  {
-    printk(WARN_LEAD "Couldn't get a free SCB.\n", p->host_no,
-           CTL_OF_CMD(cmd));
-    cmd->result = (DID_BUS_BUSY << 16);
+    if(scb == NULL)
+      printk(WARN_LEAD "Couldn't get a free SCB.\n", p->host_no,
+             CTL_OF_CMD(cmd));
+  }
+  while (scb == NULL)
+  {
+    /*
+     * Well, all SCBs are currently active on the bus.  So, we spin here
+     * running the interrupt handler until one completes and becomes free.
+     * We can do this safely because we either A) hold the driver lock (in
+     * 2.0 kernels) or we have the io_request_lock held (in 2.2 and later
+     * kernels) and so either way, we won't take any other interrupts and
+     * the queue path will block until we release it.  Also, we would worry
+     * about running the completion queues, but obviously there are plenty
+     * of commands outstanding to trigger a later interrupt that will do
+     * that for us, so skip it here.
+     */
     DRIVER_LOCK
-    aic7xxx_queue_cmd_complete(p, cmd);
+    aic7xxx_isr(p->irq, p, NULL);
     DRIVER_UNLOCK
-    return 0;
+    scb = scbq_remove_head(&p->scb_data->free_scbs);
   }
-  else
-  {
-    scb->cmd = cmd;
-    aic7xxx_position(cmd) = scb->hscb->tag;
+  scb->cmd = cmd;
+  aic7xxx_position(cmd) = scb->hscb->tag;
 
-    /*
-     * Construct the SCB beforehand, so the sequencer is
-     * paused a minimal amount of time.
-     */
-    aic7xxx_buildscb(p, cmd, scb);
+  /*
+   * Make sure the Scsi_Cmnd pointer is saved, the struct it points to
+   * is set up properly, and the parity error flag is reset, then send
+   * the SCB to the sequencer and watch the fun begin.
+   */
+  cmd->scsi_done = fn;
+  cmd->result = DID_OK;
+  memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+  aic7xxx_error(cmd) = DID_OK;
+  aic7xxx_status(cmd) = 0;
+  cmd->host_scribble = NULL;
 
-    /*
-     * Make sure the Scsi_Cmnd pointer is saved, the struct it points to
-     * is set up properly, and the parity error flag is reset, then send
-     * the SCB to the sequencer and watch the fun begin.
-     */
-    cmd->scsi_done = fn;
-    cmd->result = DID_OK;
-    memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
-    aic7xxx_error(cmd) = DID_OK;
-    aic7xxx_status(cmd) = 0;
-    cmd->host_scribble = NULL;
+  /*
+   * Construct the SCB beforehand, so the sequencer is
+   * paused a minimal amount of time.
+   */
+  aic7xxx_buildscb(p, cmd, scb);
 
-    scb->flags |= SCB_ACTIVE | SCB_WAITINGQ;
+  scb->flags |= SCB_ACTIVE | SCB_WAITINGQ;
 
-    DRIVER_LOCK
-    scbq_insert_tail(&p->waiting_scbs, scb);
-    if ( (p->flags & (AHC_IN_ISR | AHC_IN_ABORT | AHC_IN_RESET)) == 0)
-    {
-      aic7xxx_run_waiting_queues(p);
-    }
-    DRIVER_UNLOCK
+  DRIVER_LOCK
+  scbq_insert_tail(&p->waiting_scbs, scb);
+  if ( (p->flags & (AHC_IN_ISR | AHC_IN_ABORT | AHC_IN_RESET)) == 0)
+  {
+    aic7xxx_run_waiting_queues(p);
   }
+  DRIVER_UNLOCK
   return (0);
 }
 
@@ -11394,6 +11240,12 @@
          aic_inb(p, SCSISIGI),
          aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
          aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
+    printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n", p->host_no,
+         CTL_OF_SCB(scb),
+         (p->features & AHC_ULTRA2) ? aic_inb(p, SG_CACHEPTR) : 0,
+         aic_inb(p, SSTAT2),
+         aic_inb(p, STCNT + 2) << 16 | aic_inb(p, STCNT + 1) << 8 |
+         aic_inb(p, STCNT));
   }
 
   channel = cmd->channel;
@@ -11687,7 +11539,6 @@
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
   unsigned long cpu_flags = 0;
 #endif
-  Scsi_Cmnd *cmd_next, *cmd_prev;
 
   p = (struct aic7xxx_host *) cmd->host->hostdata;
   scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
@@ -11718,13 +11569,11 @@
   {
     aic7xxx_isr(p->irq, p, (void *)NULL);
     pause_sequencer(p);
-    aic7xxx_done_cmds_complete(p);
   }
+  aic7xxx_done_cmds_complete(p);
 
-  if ((scb == NULL) || (cmd->serial_number != cmd->serial_number_at_timeout))
-                      /*  Totally bogus cmd since it points beyond our  */
-  {                   /*  valid SCB range or doesn't even match it's own*/
-                      /*  timeout serial number.                        */
+  if (scb == NULL)
+  {
     if (aic7xxx_verbose & VERBOSE_ABORT_MID)
       printk(INFO_LEAD "Abort called with bogus Scsi_Cmnd "
         "pointer.\n", p->host_no, CTL_OF_CMD(cmd));
@@ -11743,28 +11592,6 @@
                         /*  finish successfully, or to indicate that we     */
                         /*  don't have this cmd any more and the mid level  */
                         /*  code needs to find it.                          */
-    cmd_next = p->completeq.head;
-    cmd_prev = NULL;
-    while (cmd_next != NULL) 
-    {
-      if (cmd_next == cmd) 
-      {
-        if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
-          printk(INFO_LEAD "Abort called for command "
-          "on completeq, completing.\n", p->host_no, CTL_OF_CMD(cmd));
-        if ( cmd_prev == NULL )
-          p->completeq.head = (Scsi_Cmnd *)cmd_next->host_scribble;
-        else
-          cmd_prev->host_scribble = cmd_next->host_scribble;
-        cmd_next->scsi_done(cmd_next);
-        unpause_sequencer(p, FALSE);
-        DRIVER_UNLOCK
-        return(SCSI_ABORT_NOT_RUNNING); /* It's already back as a successful
-                                         * completion */
-      }                                  
-      cmd_prev = cmd_next;
-      cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble;
-    }
     if (aic7xxx_verbose & VERBOSE_ABORT_MID)
       printk(INFO_LEAD "Abort called for already completed"
         " command.\n", p->host_no, CTL_OF_CMD(cmd));
@@ -11822,8 +11649,20 @@
   found = 0;
   p->flags |= AHC_IN_ABORT;
   if (aic7xxx_verbose & VERBOSE_ABORT)
-    printk(INFO_LEAD "Aborting scb %d, flags 0x%x\n",
-         p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags);
+  {
+    printk(INFO_LEAD "Aborting scb %d, flags 0x%x, SEQADDR 0x%x, LASTPHASE "
+           "0x%x\n",
+         p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags,
+         aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+         aic_inb(p, LASTPHASE));
+    printk(INFO_LEAD "SG_CACHEPTR 0x%x, SG_COUNT %d, SCSISIGI 0x%x\n",
+         p->host_no, CTL_OF_SCB(scb), (p->features & AHC_ULTRA2) ?
+         aic_inb(p, SG_CACHEPTR) : 0, aic_inb(p, SG_COUNT),
+         aic_inb(p, SCSISIGI));
+    printk(INFO_LEAD "SSTAT0 0x%x, SSTAT1 0x%x, SSTAT2 0x%x\n",
+         p->host_no, CTL_OF_SCB(scb), aic_inb(p, SSTAT0),
+         aic_inb(p, SSTAT1), aic_inb(p, SSTAT2));
+  }
 
 /*
  *   First, let's check to see if the currently running command is our target
@@ -11851,6 +11690,16 @@
         if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
           printk(INFO_LEAD "SCB is currently active.  "
                 "Waiting on completion.\n", p->host_no, CTL_OF_SCB(scb));
+        printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 "
+           "0x%x\n", p->host_no, CTL_OF_SCB(scb),
+           aic_inb(p, SCSISIGI),
+           aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+           aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
+        printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n",
+           p->host_no, CTL_OF_SCB(scb),
+           (p->features & AHC_ULTRA2) ? aic_inb(p, SG_CACHEPTR) : 0,
+           aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 |
+           aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT));
         unpause_sequencer(p, FALSE);
         p->flags &= ~AHC_IN_ABORT;
         scb->flags |= SCB_RECOVERY_SCB; /*  Note the fact that we've been  */
@@ -11866,35 +11715,7 @@
   if ((found == 0) && (scb->flags & SCB_WAITINGQ))
   {
     int tindex = TARGET_INDEX(cmd);
-    unsigned short mask;
-
-    mask = (1 << tindex);
 
-    if (p->dtr_pending & mask)
-    {
-      if (p->dev_dtr_cmnd[tindex]->next != cmd)
-        found = 1;
-      else
-        found = 0;
-    }
-    else
-    {
-      found = 1;
-    }
-    if (found == 0)
-    {
-      /*
-       * OK..this means the command we are currently getting an abort
-       * for has an outstanding negotiation command in front of it.
-       * We don't really have a way to tie back into the negotiation
-       * commands, so we just send this back as pending, then it
-       * will get reset in 2 seconds.
-       */
-      unpause_sequencer(p, TRUE);
-      scb->flags |= SCB_ABORT;
-      DRIVER_UNLOCK
-      return(SCSI_ABORT_PENDING);
-    }
     if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) 
       printk(INFO_LEAD "SCB found on waiting list and "
           "aborted.\n", p->host_no, CTL_OF_SCB(scb));
@@ -12051,10 +11872,8 @@
 #define DEVICE_RESET 0x01
 #define BUS_RESET    0x02
 #define HOST_RESET   0x04
-#define FAIL         0x08
-#define RESET_DELAY  0x10
+#define RESET_DELAY  0x08
   int        action;
-  Scsi_Cmnd *cmd_prev, *cmd_next;
 
 
   if ( cmd == NULL )
@@ -12082,86 +11901,32 @@
   DRIVER_LOCK
 
   pause_sequencer(p);
-  while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
-  {
-    aic7xxx_isr(p->irq, p, (void *)NULL );
-    pause_sequencer(p);
-    aic7xxx_done_cmds_complete(p);
-  }
 
-  if (scb == NULL)
+  if(flags & SCSI_RESET_SYNCHRONOUS)
   {
     if (aic7xxx_verbose & VERBOSE_RESET_MID)
-      printk(INFO_LEAD "Reset called with bogus Scsi_Cmnd"
-           "->SCB mapping, improvising.\n", p->host_no, CTL_OF_CMD(cmd));
-    if ( flags & SCSI_RESET_SUGGEST_HOST_RESET )
-    {
-      action = HOST_RESET;
-    }
-    else
-    {
-      action = BUS_RESET;
-    }
+      printk(INFO_LEAD "Reset called for a SYNCHRONOUS reset, flags 0x%x, "
+           "cmd->result 0x%x.\n", p->host_no, CTL_OF_CMD(cmd), flags,
+           cmd->result);
+    scb = NULL;
+    action = HOST_RESET;
   }
-  else if (scb->cmd != cmd) 
+  else if ((scb == NULL) || (scb->cmd != cmd))
   {
     if (aic7xxx_verbose & VERBOSE_RESET_MID)
-    printk(INFO_LEAD "Reset called with recycled SCB "
-        "for cmd.\n", p->host_no, CTL_OF_CMD(cmd));
-    cmd_prev = NULL;
-    cmd_next = p->completeq.head;
-    while ( cmd_next != NULL )
-    {
-      if (cmd_next == cmd)
-      {
-        if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
-          printk(INFO_LEAD "Reset, found cmd on completeq"
-          ", completing.\n", p->host_no, CTL_OF_CMD(cmd));
-        unpause_sequencer(p, FALSE);
-        DRIVER_UNLOCK
-        return(SCSI_RESET_NOT_RUNNING);
-      }
-      cmd_prev = cmd_next;
-      cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble;
-    }
-    if ( !(flags & SCSI_RESET_SYNCHRONOUS) )
-    {
-      if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
-        printk(INFO_LEAD "Reset, cmd not found,"
-          " failing.\n", p->host_no, CTL_OF_CMD(cmd));
-      unpause_sequencer(p, FALSE);
-      DRIVER_UNLOCK
-      return(SCSI_RESET_NOT_RUNNING);
-    }
-    else
-    {
-      if (aic7xxx_verbose & VERBOSE_RESET_MID)
-        printk(INFO_LEAD "Reset called, no scb, "
-          "flags 0x%x\n", p->host_no, CTL_OF_CMD(cmd), flags);
-      scb = NULL;
-      action = HOST_RESET;
-    }
+      printk(INFO_LEAD "Reset called with bogus Scsi_Cmnd"
+           "->SCB mapping, failing.\n", p->host_no, CTL_OF_CMD(cmd));
+    aic7xxx_done_cmds_complete(p);
+    aic7xxx_run_waiting_queues(p);
+    unpause_sequencer(p, FALSE);
+    DRIVER_UNLOCK
+    return(SCSI_RESET_NOT_RUNNING);
   }
   else
   {
     if (aic7xxx_verbose & VERBOSE_RESET_MID)
       printk(INFO_LEAD "Reset called, scb %d, flags "
         "0x%x\n", p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags);
-    if ( aic7xxx_scb_on_qoutfifo(p, scb) )
-    {
-      if(aic7xxx_verbose & VERBOSE_RESET_RETURN)
-        printk(INFO_LEAD "SCB on qoutfifo, completing.\n", p->host_no,
-          CTL_OF_SCB(scb));
-      if ((aic_inb(p,INTSTAT) & CMDCMPLT) == 0)
-        printk(INFO_LEAD "missed CMDCMPLT interrupt!\n", p->host_no,
-          CTL_OF_SCB(scb));
-      aic7xxx_handle_command_completion_intr(p);
-      aic7xxx_done_cmds_complete(p);
-      aic7xxx_run_waiting_queues(p);
-      unpause_sequencer(p, FALSE);
-      DRIVER_UNLOCK
-      return(SCSI_RESET_SUCCESS);
-    }
     if ( flags & SCSI_RESET_SUGGEST_HOST_RESET )
     {
       action = HOST_RESET;
@@ -12175,6 +11940,26 @@
       action = DEVICE_RESET;
     }
   }
+
+  while((aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
+  {
+    aic7xxx_isr(p->irq, p, (void *)NULL );
+    pause_sequencer(p);
+  }
+  aic7xxx_done_cmds_complete(p);
+
+  if(scb && (scb->cmd == NULL))
+  {
+    /*
+     * We just completed the command when we ran the isr stuff, so we no
+     * longer have it.
+     */
+    aic7xxx_run_waiting_queues(p);
+    unpause_sequencer(p, FALSE);
+    DRIVER_UNLOCK
+    return(SCSI_RESET_SUCCESS);
+  }
+    
   if ( (action & DEVICE_RESET) && 
         (p->dev_flags[tindex] & BUS_DEVICE_RESET_PENDING) )
   {
@@ -12234,14 +12019,13 @@
   switch (action)
   {
     case RESET_DELAY:
+      aic7xxx_run_waiting_queues(p);
       unpause_sequencer(p, FALSE);
       DRIVER_UNLOCK
-      return(SCSI_RESET_PENDING);
-      break;
-    case FAIL:
-      unpause_sequencer(p, FALSE);
-      DRIVER_UNLOCK
-      return(SCSI_RESET_ERROR);
+      if(scb == NULL)
+        return(SCSI_RESET_PUNT);
+      else
+        return(SCSI_RESET_PENDING);
       break;
     case DEVICE_RESET:
       p->flags |= AHC_IN_RESET;
@@ -12259,7 +12043,7 @@
     case HOST_RESET:
     default:
       p->flags |= AHC_IN_RESET | AHC_RESET_DELAY;
-      p->dev_expires[p->scsi_id] = jiffies + (3 * HZ);
+      p->dev_expires[p->scsi_id] = jiffies + (1 * HZ);
       p->dev_timer_active |= (0x01 << p->scsi_id);
       if ( !(p->dev_timer_active & (0x01 << MAX_TARGETS)) ||
             time_after_eq(p->dev_timer.expires, p->dev_expires[p->scsi_id]) )
@@ -12288,21 +12072,14 @@
         p->msg_index = 0;
         p->msg_len = 0;
       }
-      aic7xxx_run_done_queue(p, TRUE);
-      /*
-       * If this a SCSI_RESET_SYNCHRONOUS then the command we were given is
-       * in need of being re-started, so send it on through to aic7xxx_queue
-       * and let it set until the delay is over.  This keeps it from dying
-       * entirely and avoids getting a bogus dead command back through the
-       * mid-level code due to too many retries.
-       */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,132)
-      if ( flags & SCSI_RESET_SYNCHRONOUS )
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+      if(flags & SCSI_RESET_SYNCHRONOUS)
       {
-        cmd->result = DID_BUS_BUSY << 16;
+        cmd->result = DID_RESET << 16;
         cmd->done(cmd);
       }
 #endif
+      aic7xxx_run_done_queue(p, TRUE);
       p->flags &= ~AHC_IN_RESET;
       /*
        * We can't rely on run_waiting_queues to unpause the sequencer for
@@ -12313,7 +12090,10 @@
       aic7xxx_run_waiting_queues(p);
       unpause_sequencer(p, FALSE);
       DRIVER_UNLOCK
-      return(result);
+      if(scb == NULL)
+        return(SCSI_RESET_SUCCESS|SCSI_RESET_HOST_RESET);
+      else
+        return(result);
       break;
   }
 }
@@ -12623,7 +12403,7 @@
 }
 
 
-#include "aic7xxx_proc.c"
+#include "aic7xxx/aic7xxx_proc.c"
 
 #ifdef MODULE
 /* Eventually this will go into an include file, but this will be later */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx.h linux.19p18/drivers/scsi/aic7xxx.h
--- linux.vanilla/drivers/scsi/aic7xxx.h	Wed May  3 22:31:20 2000
+++ linux.19p18/drivers/scsi/aic7xxx.h	Thu Jan  1 01:00:00 1970
@@ -1,114 +0,0 @@
-/*+M*************************************************************************
- * Adaptec AIC7xxx device driver for Linux.
- *
- * Copyright (c) 1994 John Aycock
- *   The University of Calgary Department of Computer Science.
- *
- * 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, 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; see the file COPYING.  If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- * 
- * $Id: aic7xxx.h,v 3.2 1996/07/23 03:37:26 deang Exp $
- *-M*************************************************************************/
-#ifndef _aic7xxx_h
-#define _aic7xxx_h
-
-#define AIC7XXX_H_VERSION  "3.2.4"
-
-#ifndef LINUX_VERSION_CODE
-#include <linux/version.h>
-#endif
-
-#ifndef KERNEL_VERSION
-#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
-#endif
-
-#if defined(__i386__)
-#  define AIC7XXX_BIOSPARAM aic7xxx_biosparam
-#else
-#  define AIC7XXX_BIOSPARAM NULL
-#endif
-
-/*
- * Scsi_Host_Template (see hosts.h) for AIC-7xxx - some fields
- * to do with card config are filled in after the card is detected.
- */
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,65)
-#define AIC7XXX	{						\
-	next: NULL,						\
-	module: NULL,						\
-	proc_dir: NULL,						\
-	proc_info: aic7xxx_proc_info,				\
-	name: NULL,						\
-	detect: aic7xxx_detect,					\
-	release: aic7xxx_release,				\
-	info: aic7xxx_info,					\
-	command: NULL,						\
-	queuecommand: aic7xxx_queue,				\
-	eh_strategy_handler: NULL,				\
-	eh_abort_handler: NULL,					\
-	eh_device_reset_handler: NULL,				\
-	eh_bus_reset_handler: NULL,				\
-	eh_host_reset_handler: NULL,				\
-	abort: aic7xxx_abort,					\
-	reset: aic7xxx_reset,					\
-	slave_attach: NULL,					\
-	bios_param: AIC7XXX_BIOSPARAM,				\
-	can_queue: 255,		/* max simultaneous cmds      */\
-	this_id: -1,		/* scsi id of host adapter    */\
-	sg_tablesize: 0,	/* max scatter-gather cmds    */\
-	cmd_per_lun: 3,		/* cmds per lun (linked cmds) */\
-	present: 0,		/* number of 7xxx's present   */\
-	unchecked_isa_dma: 0,	/* no memory DMA restrictions */\
-	use_clustering: ENABLE_CLUSTERING,			\
-	use_new_eh_code: 0					\
-}
-#else
-#define AIC7XXX	{						\
-	next: NULL,						\
-	usage_count: NULL,					\
-	proc_dir: NULL, 					\
-	proc_info: aic7xxx_proc_info,				\
-	name: NULL,						\
-	detect: aic7xxx_detect,					\
-	release: aic7xxx_release,				\
-	info: aic7xxx_info,					\
-	command: NULL,						\
-	queuecommand: aic7xxx_queue,				\
-	abort: aic7xxx_abort,					\
-	reset: aic7xxx_reset,					\
-	slave_attach: NULL,					\
-	bios_param: AIC7XXX_BIOSPARAM,				\
-	can_queue: 255,		/* max simultaneous cmds      */\
-	this_id: -1,		/* scsi id of host adapter    */\
-	sg_tablesize: 0,	/* max scatter-gather cmds    */\
-	cmd_per_lun: 3,		/* cmds per lun (linked cmds) */\
-	present: 0,		/* number of 7xxx's present   */\
-	unchecked_isa_dma: 0,	/* no memory DMA restrictions */\
-	use_clustering: ENABLE_CLUSTERING			\
-}
-#endif
-
-extern int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
-extern int aic7xxx_biosparam(Disk *, kdev_t, int[]);
-extern int aic7xxx_detect(Scsi_Host_Template *);
-extern int aic7xxx_command(Scsi_Cmnd *);
-extern int aic7xxx_reset(Scsi_Cmnd *, unsigned int);
-extern int aic7xxx_abort(Scsi_Cmnd *);
-extern int aic7xxx_release(struct Scsi_Host *);
-
-extern const char *aic7xxx_info(struct Scsi_Host *);
-
-extern int aic7xxx_proc_info(char *, char **, off_t, int, int, int);
-
-#endif /* _aic7xxx_h */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx_proc.c linux.19p18/drivers/scsi/aic7xxx_proc.c
--- linux.vanilla/drivers/scsi/aic7xxx_proc.c	Fri Apr 21 12:46:27 2000
+++ linux.19p18/drivers/scsi/aic7xxx_proc.c	Thu Jan  1 01:00:00 1970
@@ -1,414 +0,0 @@
-/*+M*************************************************************************
- * Adaptec AIC7xxx device driver proc support for Linux.
- *
- * Copyright (c) 1995, 1996 Dean W. Gehnert
- *
- * 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, 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; see the file COPYING.  If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * ----------------------------------------------------------------
- *  o Modified from the EATA-DMA /proc support.
- *  o Additional support for device block statistics provided by
- *    Matthew Jacob.
- *  o Correction of overflow by Heinz Mauelshagen
- *  o Adittional corrections by Doug Ledford
- *
- *  Dean W. Gehnert, deang@teleport.com, 05/01/96
- *
- *  $Id: aic7xxx_proc.c,v 4.1 1997/06/97 08:23:42 deang Exp $
- *-M*************************************************************************/
-
-#include <linux/config.h>
-
-#define	BLS	(&aic7xxx_buffer[size])
-#define HDRB \
-"             < 2K      2K+     4K+     8K+    16K+    32K+    64K+   128K+"
-
-#ifdef PROC_DEBUG
-extern int vsprintf(char *, const char *, va_list);
-
-static void
-proc_debug(const char *fmt, ...)
-{
-  va_list ap;
-  char buf[256];
-
-  va_start(ap, fmt);
-  vsprintf(buf, fmt, ap);
-  printk(buf);
-  va_end(ap);
-}
-#else /* PROC_DEBUG */
-#  define proc_debug(fmt, args...)
-#endif /* PROC_DEBUG */
-
-static int aic7xxx_buffer_size = 0;
-static char *aic7xxx_buffer = NULL;
-
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_set_info
- *
- * Description:
- *   Set parameters for the driver from the /proc filesystem.
- *-F*************************************************************************/
-int
-aic7xxx_set_info(char *buffer, int length, struct Scsi_Host *HBAptr)
-{
-  proc_debug("aic7xxx_set_info(): %s\n", buffer);
-  return (-ENOSYS);  /* Currently this is a no-op */
-}
-
-
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_proc_info
- *
- * Description:
- *   Return information to handle /proc support for the driver.
- *-F*************************************************************************/
-int
-aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length, 
-                    int hostno, int inout)
-{
-  struct Scsi_Host *HBAptr;
-  struct aic7xxx_host *p;
-  int    size = 0;
-  unsigned char i;
-  struct aic7xxx_xferstats *sp;
-  unsigned char target;
-
-  HBAptr = NULL;
-
-  for(p=first_aic7xxx; p->host->host_no != hostno; p=p->next)
-    ;
-
-  if (!p)
-  {
-    size += sprintf(buffer, "Can't find adapter for host number %d\n", hostno);
-    if (size > length)
-    {
-      return (size);
-    }
-    else
-    {
-      return (length);
-    }
-  }
-
-  HBAptr = p->host;
-
-  if (inout == TRUE) /* Has data been written to the file? */ 
-  {
-    return (aic7xxx_set_info(buffer, length, HBAptr));
-  }
-
-  p = (struct aic7xxx_host *) HBAptr->hostdata;
-
-  /*
-   * It takes roughly 1K of space to hold all relevant card info, not
-   * counting any proc stats, so we start out with a 1.5k buffer size and
-   * if proc_stats is defined, then we sweep the stats structure to see
-   * how many drives we will be printing out for and add 384 bytes per
-   * device with active stats.
-   *
-   * Hmmmm...that 1.5k seems to keep growing as items get added so they
-   * can be easily viewed for debugging purposes.  So, we bumped that
-   * 1.5k to 4k so we can quit having to bump it all the time.
-   */
-
-  size = 4096;
-  for (target = 0; target < MAX_TARGETS; target++)
-  {
-    if (p->dev_flags[target] & DEVICE_PRESENT)
-#ifdef AIC7XXX_PROC_STATS
-      size += 512;
-#else
-      size += 256;
-#endif
-  }
-  if (aic7xxx_buffer_size != size)
-  {
-    if (aic7xxx_buffer != NULL) 
-    {
-      kfree(aic7xxx_buffer);
-      aic7xxx_buffer_size = 0;
-    }
-    aic7xxx_buffer = kmalloc(size, GFP_KERNEL);
-  }
-  if (aic7xxx_buffer == NULL)
-  {
-    size = sprintf(buffer, "AIC7xxx - kmalloc error at line %d\n",
-        __LINE__);
-    return size;
-  }
-  aic7xxx_buffer_size = size;
-
-  size = 0;
-  size += sprintf(BLS, "Adaptec AIC7xxx driver version: ");
-  size += sprintf(BLS, "%s/", AIC7XXX_C_VERSION);
-  size += sprintf(BLS, "%s", AIC7XXX_H_VERSION);
-  size += sprintf(BLS, "\n");
-  size += sprintf(BLS, "Compile Options:\n");
-#ifdef CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
-  size += sprintf(BLS, "  TCQ Enabled By Default : Enabled\n");
-#else
-  size += sprintf(BLS, "  TCQ Enabled By Default : Disabled\n");
-#endif
-#ifdef AIC7XXX_PROC_STATS
-  size += sprintf(BLS, "  AIC7XXX_PROC_STATS     : Enabled\n");
-#else
-  size += sprintf(BLS, "  AIC7XXX_PROC_STATS     : Disabled\n");
-#endif
-  size += sprintf(BLS, "  AIC7XXX_RESET_DELAY    : %d\n", AIC7XXX_RESET_DELAY);
-  size += sprintf(BLS, "\n");
-  size += sprintf(BLS, "Adapter Configuration:\n");
-  size += sprintf(BLS, "           SCSI Adapter: %s\n",
-      board_names[p->board_name_index]);
-  if (p->flags & AHC_TWIN)
-    size += sprintf(BLS, "                         Twin Channel Controller ");
-  else
-  {
-    char *channel = "";
-    char *ultra = "";
-    char *wide = "Narrow ";
-    if (p->flags & AHC_MULTI_CHANNEL)
-    {
-      channel = " Channel A";
-      if (p->flags & (AHC_CHNLB|AHC_CHNLC))
-        channel = (p->flags & AHC_CHNLB) ? " Channel B" : " Channel C";
-    }
-    if (p->features & AHC_WIDE)
-      wide = "Wide ";
-    if (p->features & AHC_ULTRA3)
-    {
-      switch(p->chip & AHC_CHIPID_MASK)
-      {
-        case AHC_AIC7892:
-        case AHC_AIC7899:
-          ultra = "Ultra-160/m LVD/SE ";
-          break;
-        default:
-          ultra = "Ultra-3 LVD/SE ";
-          break;
-      }
-    }
-    else if (p->features & AHC_ULTRA2)
-      ultra = "Ultra-2 LVD/SE ";
-    else if (p->features & AHC_ULTRA)
-      ultra = "Ultra ";
-    size += sprintf(BLS, "                           %s%sController%s ",
-      ultra, wide, channel);
-  }
-  switch(p->chip & ~AHC_CHIPID_MASK)
-  {
-    case AHC_VL:
-      size += sprintf(BLS, "at VLB slot %d\n", p->pci_device_fn);
-      break;
-    case AHC_EISA:
-      size += sprintf(BLS, "at EISA slot %d\n", p->pci_device_fn);
-      break;
-    default:
-      size += sprintf(BLS, "at PCI %d/%d/%d\n", p->pci_bus,
-        PCI_SLOT(p->pci_device_fn), PCI_FUNC(p->pci_device_fn));
-      break;
-  }
-  if( !(p->maddr) )
-  {
-    size += sprintf(BLS, "    Programmed I/O Base: %lx\n", p->base);
-  }
-  else
-  {
-    size += sprintf(BLS, "    PCI MMAPed I/O Base: 0x%lx\n", p->mbase);
-  }
-  if( (p->chip & (AHC_VL | AHC_EISA)) )
-  {
-    size += sprintf(BLS, "    BIOS Memory Address: 0x%08x\n", p->bios_address);
-  }
-  size += sprintf(BLS, " Adapter SEEPROM Config: %s\n",
-          (p->flags & AHC_SEEPROM_FOUND) ? "SEEPROM found and used." :
-         ((p->flags & AHC_USEDEFAULTS) ? "SEEPROM not found, using defaults." :
-           "SEEPROM not found, using leftover BIOS values.") );
-  size += sprintf(BLS, "      Adaptec SCSI BIOS: %s\n",
-          (p->flags & AHC_BIOS_ENABLED) ? "Enabled" : "Disabled");
-  size += sprintf(BLS, "                    IRQ: %d\n", HBAptr->irq);
-  size += sprintf(BLS, "                   SCBs: Active %d, Max Active %d,\n",
-            p->activescbs, p->max_activescbs);
-  size += sprintf(BLS, "                         Allocated %d, HW %d, "
-            "Page %d\n", p->scb_data->numscbs, p->scb_data->maxhscbs,
-            p->scb_data->maxscbs);
-  if (p->flags & AHC_EXTERNAL_SRAM)
-    size += sprintf(BLS, "                         Using External SCB SRAM\n");
-  size += sprintf(BLS, "             Interrupts: %ld", p->isr_count);
-  if (p->chip & AHC_EISA)
-  {
-    size += sprintf(BLS, " %s\n",
-        (p->pause & IRQMS) ? "(Level Sensitive)" : "(Edge Triggered)");
-  }
-  else
-  {
-    size += sprintf(BLS, "\n");
-  }
-  size += sprintf(BLS, "      BIOS Control Word: 0x%04x\n",
-            p->bios_control);
-  size += sprintf(BLS, "   Adapter Control Word: 0x%04x\n",
-            p->adapter_control);
-  size += sprintf(BLS, "   Extended Translation: %sabled\n",
-      (p->flags & AHC_EXTEND_TRANS_A) ? "En" : "Dis");
-  size += sprintf(BLS, "Disconnect Enable Flags: 0x%04x\n", p->discenable);
-  if (p->features & (AHC_ULTRA | AHC_ULTRA2))
-  {
-    size += sprintf(BLS, "     Ultra Enable Flags: 0x%04x\n", p->ultraenb);
-  }
-  size += sprintf(BLS, " Tag Queue Enable Flags: 0x%04x\n", p->tagenable);
-  size += sprintf(BLS, "Ordered Queue Tag Flags: 0x%04x\n", p->orderedtag);
-  size += sprintf(BLS, "Default Tag Queue Depth: %d\n", AIC7XXX_CMDS_PER_DEVICE);
-  size += sprintf(BLS, "    Tagged Queue By Device array for aic7xxx host "
-                       "instance %d:\n", p->instance);
-  size += sprintf(BLS, "      {");
-  for(i=0; i < (MAX_TARGETS - 1); i++)
-    size += sprintf(BLS, "%d,",aic7xxx_tag_info[p->instance].tag_commands[i]);
-  size += sprintf(BLS, "%d}\n",aic7xxx_tag_info[p->instance].tag_commands[i]);
-  size += sprintf(BLS, "    Actual queue depth per device for aic7xxx host "
-                       "instance %d:\n", p->instance);
-  size += sprintf(BLS, "      {");
-  for(i=0; i < (MAX_TARGETS - 1); i++)
-    size += sprintf(BLS, "%d,", p->dev_max_queue_depth[i]);
-  size += sprintf(BLS, "%d}\n", p->dev_max_queue_depth[i]);
-
-  size += sprintf(BLS, "\n");
-  size += sprintf(BLS, "Statistics:\n\n");
-  for (target = 0; target < MAX_TARGETS; target++)
-  {
-    sp = &p->stats[target];
-    if ((p->dev_flags[target] & DEVICE_PRESENT) == 0)
-    {
-      continue;
-    }
-    if (p->features & AHC_TWIN)
-    {
-      size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
-          p->host_no, (target >> 3), (target & 0x7), 0);
-    }
-    else
-    {
-      size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
-          p->host_no, 0, target, 0);
-    }
-    size += sprintf(BLS, "  Device using %s/%s",
-          (p->transinfo[target].cur_width == MSG_EXT_WDTR_BUS_16_BIT) ?
-          "Wide" : "Narrow",
-          (p->transinfo[target].cur_offset != 0) ?
-          "Sync transfers at " : "Async transfers.\n" );
-    if (p->transinfo[target].cur_offset != 0)
-    {
-      struct aic7xxx_syncrate *sync_rate;
-      unsigned char options = p->transinfo[target].cur_options;
-      int period = p->transinfo[target].cur_period;
-      int rate = (p->transinfo[target].cur_width ==
-                  MSG_EXT_WDTR_BUS_16_BIT) ? 1 : 0;
-
-      sync_rate = aic7xxx_find_syncrate(p, &period, 0, &options);
-      if (sync_rate != NULL)
-      {
-        size += sprintf(BLS, "%s MByte/sec, offset %d\n",
-                        sync_rate->rate[rate],
-                        p->transinfo[target].cur_offset );
-      }
-      else
-      {
-        size += sprintf(BLS, "3.3 MByte/sec, offset %d\n",
-                        p->transinfo[target].cur_offset );
-      }
-    }
-    size += sprintf(BLS, "  Transinfo settings: ");
-    size += sprintf(BLS, "current(%d/%d/%d/%d), ",
-                    p->transinfo[target].cur_period,
-                    p->transinfo[target].cur_offset,
-                    p->transinfo[target].cur_width,
-                    p->transinfo[target].cur_options);
-    size += sprintf(BLS, "goal(%d/%d/%d/%d), ",
-                    p->transinfo[target].goal_period,
-                    p->transinfo[target].goal_offset,
-                    p->transinfo[target].goal_width,
-                    p->transinfo[target].goal_options);
-    size += sprintf(BLS, "user(%d/%d/%d/%d)\n",
-                    p->transinfo[target].user_period,
-                    p->transinfo[target].user_offset,
-                    p->transinfo[target].user_width,
-                    p->transinfo[target].user_options);
-#ifdef AIC7XXX_PROC_STATS
-    size += sprintf(BLS, "  Total transfers %ld (%ld reads and %ld writes)\n",
-        sp->r_total + sp->w_total, sp->r_total, sp->w_total);
-    size += sprintf(BLS, "%s\n", HDRB);
-    size += sprintf(BLS, "   Reads:");
-    for (i = 0; i < NUMBER(sp->r_bins); i++)
-    {
-      size += sprintf(BLS, " %7ld", sp->r_bins[i]);
-    }
-    size += sprintf(BLS, "\n");
-    size += sprintf(BLS, "  Writes:");
-    for (i = 0; i < NUMBER(sp->w_bins); i++)
-    {
-      size += sprintf(BLS, " %7ld", sp->w_bins[i]);
-    }
-    size += sprintf(BLS, "\n");
-#else
-    size += sprintf(BLS, "  Total transfers %ld (%ld reads and %ld writes)\n",
-        sp->r_total + sp->w_total, sp->r_total, sp->w_total);
-#endif /* AIC7XXX_PROC_STATS */
-    size += sprintf(BLS, "\n\n");
-  }
-
-  if (size >= aic7xxx_buffer_size)
-  {
-    printk(KERN_WARNING "aic7xxx: Overflow in aic7xxx_proc.c\n");
-  }
-
-  if (offset > size - 1)
-  {
-    kfree(aic7xxx_buffer);
-    aic7xxx_buffer = NULL;
-    aic7xxx_buffer_size = length = 0;
-    *start = NULL;
-  }
-  else
-  {
-    *start = buffer;
-    length = MIN(length, size - offset);
-    memcpy(buffer, &aic7xxx_buffer[offset], length);
-  }
-
-  return (length);
-}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 2
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -2
- * c-argdecl-indent: 2
- * c-label-offset: -2
- * c-continued-statement-offset: 2
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx_reg.h linux.19p18/drivers/scsi/aic7xxx_reg.h
--- linux.vanilla/drivers/scsi/aic7xxx_reg.h	Fri Apr 21 12:46:27 2000
+++ linux.19p18/drivers/scsi/aic7xxx_reg.h	Thu Jan  1 01:00:00 1970
@@ -1,629 +0,0 @@
-/*
-  * DO NOT EDIT - This file is automatically generated.
-  */
-
-#define	SCSISEQ         		0x00
-#define		TEMODE          	0x80
-#define		ENSELO          	0x40
-#define		ENSELI          	0x20
-#define		ENRSELI         	0x10
-#define		ENAUTOATNO      	0x08
-#define		ENAUTOATNI      	0x04
-#define		ENAUTOATNP      	0x02
-#define		SCSIRSTO        	0x01
-
-#define	SXFRCTL0        		0x01
-#define		DFON            	0x80
-#define		DFPEXP          	0x40
-#define		FAST20          	0x20
-#define		CLRSTCNT        	0x10
-#define		SPIOEN          	0x08
-#define		SCAMEN          	0x04
-#define		CLRCHN          	0x02
-
-#define	SXFRCTL1        		0x02
-#define		BITBUCKET       	0x80
-#define		SWRAPEN         	0x40
-#define		ENSPCHK         	0x20
-#define		STIMESEL        	0x18
-#define		ENSTIMER        	0x04
-#define		ACTNEGEN        	0x02
-#define		STPWEN          	0x01
-
-#define	SCSISIGO        		0x03
-#define		CDO             	0x80
-#define		IOO             	0x40
-#define		MSGO            	0x20
-#define		ATNO            	0x10
-#define		SELO            	0x08
-#define		BSYO            	0x04
-#define		REQO            	0x02
-#define		ACKO            	0x01
-
-#define	SCSISIGI        		0x03
-#define		ATNI            	0x10
-#define		SELI            	0x08
-#define		BSYI            	0x04
-#define		REQI            	0x02
-#define		ACKI            	0x01
-
-#define	SCSIRATE        		0x04
-#define		WIDEXFER        	0x80
-#define		SXFR_ULTRA2     	0x7f
-#define		SXFR            	0x70
-#define		SOFS            	0x0f
-
-#define	SCSIID          		0x05
-#define	SCSIOFFSET      		0x05
-#define		SOFS_ULTRA2     	0x7f
-
-#define	SCSIDATL        		0x06
-
-#define	SCSIDATH        		0x07
-
-#define	STCNT           		0x08
-
-#define	OPTIONMODE      		0x08
-#define		AUTORATEEN      	0x80
-#define		AUTOACKEN       	0x40
-#define		ATNMGMNTEN      	0x20
-#define		BUSFREEREV      	0x10
-#define		EXPPHASEDIS     	0x08
-#define		SCSIDATL_IMGEN  	0x04
-#define		AUTO_MSGOUT_DE  	0x02
-#define		DIS_MSGIN_DUALEDGE	0x01
-
-#define	CLRSINT0        		0x0b
-#define		CLRSELDO        	0x40
-#define		CLRSELDI        	0x20
-#define		CLRSELINGO      	0x10
-#define		CLRSWRAP        	0x08
-#define		CLRSPIORDY      	0x02
-
-#define	SSTAT0          		0x0b
-#define		TARGET          	0x80
-#define		SELDO           	0x40
-#define		SELDI           	0x20
-#define		SELINGO         	0x10
-#define		IOERR           	0x08
-#define		SWRAP           	0x08
-#define		SDONE           	0x04
-#define		SPIORDY         	0x02
-#define		DMADONE         	0x01
-
-#define	CLRSINT1        		0x0c
-#define		CLRSELTIMEO     	0x80
-#define		CLRATNO         	0x40
-#define		CLRSCSIRSTI     	0x20
-#define		CLRBUSFREE      	0x08
-#define		CLRSCSIPERR     	0x04
-#define		CLRPHASECHG     	0x02
-#define		CLRREQINIT      	0x01
-
-#define	SSTAT1          		0x0c
-#define		SELTO           	0x80
-#define		ATNTARG         	0x40
-#define		SCSIRSTI        	0x20
-#define		PHASEMIS        	0x10
-#define		BUSFREE         	0x08
-#define		SCSIPERR        	0x04
-#define		PHASECHG        	0x02
-#define		REQINIT         	0x01
-
-#define	SSTAT2          		0x0d
-#define		OVERRUN         	0x80
-#define		SHVALID         	0x40
-#define		WIDE_RES        	0x20
-#define		SFCNT           	0x1f
-#define		EXP_ACTIVE      	0x10
-#define		CRCVALERR       	0x08
-#define		CRCENDERR       	0x04
-#define		CRCREQERR       	0x02
-#define		DUAL_EDGE_ERROR 	0x01
-
-#define	SSTAT3          		0x0e
-#define		SCSICNT         	0xf0
-#define		OFFCNT          	0x0f
-
-#define	SCSIID_ULTRA2   		0x0f
-#define		OID             	0x0f
-
-#define	SIMODE0         		0x10
-#define		ENSELDO         	0x40
-#define		ENSELDI         	0x20
-#define		ENSELINGO       	0x10
-#define		ENIOERR         	0x08
-#define		ENSWRAP         	0x08
-#define		ENSDONE         	0x04
-#define		ENSPIORDY       	0x02
-#define		ENDMADONE       	0x01
-
-#define	SIMODE1         		0x11
-#define		ENSELTIMO       	0x80
-#define		ENATNTARG       	0x40
-#define		ENSCSIRST       	0x20
-#define		ENPHASEMIS      	0x10
-#define		ENBUSFREE       	0x08
-#define		ENSCSIPERR      	0x04
-#define		ENPHASECHG      	0x02
-#define		ENREQINIT       	0x01
-
-#define	SCSIBUSL        		0x12
-
-#define	SCSIBUSH        		0x13
-
-#define	SHADDR          		0x14
-
-#define	SELTIMER        		0x18
-#define		STAGE6          	0x20
-#define		STAGE5          	0x10
-#define		STAGE4          	0x08
-#define		STAGE3          	0x04
-#define		STAGE2          	0x02
-#define		STAGE1          	0x01
-
-#define	SELID           		0x19
-#define		SELID_MASK      	0xf0
-#define		ONEBIT          	0x08
-
-#define	SPIOCAP         		0x1b
-#define		SOFT1           	0x80
-#define		SOFT0           	0x40
-#define		SOFTCMDEN       	0x20
-#define		HAS_BRDCTL      	0x10
-#define		SEEPROM         	0x08
-#define		EEPROM          	0x04
-#define		ROM             	0x02
-#define		SSPIOCPS        	0x01
-
-#define	BRDCTL          		0x1d
-#define		BRDDAT7         	0x80
-#define		BRDDAT6         	0x40
-#define		BRDDAT5         	0x20
-#define		BRDDAT4         	0x10
-#define		BRDSTB          	0x10
-#define		BRDCS           	0x08
-#define		BRDDAT3         	0x08
-#define		BRDDAT2         	0x04
-#define		BRDRW           	0x04
-#define		BRDRW_ULTRA2    	0x02
-#define		BRDCTL1         	0x02
-#define		BRDCTL0         	0x01
-#define		BRDSTB_ULTRA2   	0x01
-
-#define	SEECTL          		0x1e
-#define		EXTARBACK       	0x80
-#define		EXTARBREQ       	0x40
-#define		SEEMS           	0x20
-#define		SEERDY          	0x10
-#define		SEECS           	0x08
-#define		SEECK           	0x04
-#define		SEEDO           	0x02
-#define		SEEDI           	0x01
-
-#define	SBLKCTL         		0x1f
-#define		DIAGLEDEN       	0x80
-#define		DIAGLEDON       	0x40
-#define		AUTOFLUSHDIS    	0x20
-#define		ENAB40          	0x08
-#define		ENAB20          	0x04
-#define		SELWIDE         	0x02
-#define		XCVR            	0x01
-
-#define	SRAM_BASE       		0x20
-
-#define	TARG_SCSIRATE   		0x20
-
-#define	ULTRA_ENB       		0x30
-
-#define	DISC_DSB        		0x32
-
-#define	MSG_OUT         		0x34
-
-#define	DMAPARAMS       		0x35
-#define		PRELOADEN       	0x80
-#define		WIDEODD         	0x40
-#define		SCSIEN          	0x20
-#define		SDMAENACK       	0x10
-#define		SDMAEN          	0x10
-#define		HDMAEN          	0x08
-#define		HDMAENACK       	0x08
-#define		DIRECTION       	0x04
-#define		FIFOFLUSH       	0x02
-#define		FIFORESET       	0x01
-
-#define	SEQ_FLAGS       		0x36
-#define		IDENTIFY_SEEN   	0x80
-#define		SCBPTR_VALID    	0x20
-#define		DPHASE          	0x10
-#define		AMTARGET        	0x08
-#define		WIDE_BUS        	0x02
-#define		TWIN_BUS        	0x01
-
-#define	SAVED_TCL       		0x37
-
-#define	SG_COUNT        		0x38
-
-#define	SG_NEXT         		0x39
-
-#define	LASTPHASE       		0x3d
-#define		P_MESGIN        	0xe0
-#define		PHASE_MASK      	0xe0
-#define		P_STATUS        	0xc0
-#define		P_MESGOUT       	0xa0
-#define		P_COMMAND       	0x80
-#define		CDI             	0x80
-#define		IOI             	0x40
-#define		P_DATAIN        	0x40
-#define		MSGI            	0x20
-#define		P_BUSFREE       	0x01
-#define		P_DATAOUT       	0x00
-
-#define	WAITING_SCBH    		0x3e
-
-#define	DISCONNECTED_SCBH		0x3f
-
-#define	FREE_SCBH       		0x40
-
-#define	HSCB_ADDR       		0x41
-
-#define	SCBID_ADDR      		0x45
-
-#define	TMODE_CMDADDR   		0x49
-
-#define	KERNEL_QINPOS   		0x4d
-
-#define	QINPOS          		0x4e
-
-#define	QOUTPOS         		0x4f
-
-#define	TMODE_CMDADDR_NEXT		0x50
-
-#define	ARG_1           		0x51
-#define	RETURN_1        		0x51
-#define		SEND_MSG        	0x80
-#define		SEND_SENSE      	0x40
-#define		SEND_REJ        	0x20
-#define		MSGOUT_PHASEMIS 	0x10
-
-#define	ARG_2           		0x52
-#define	RETURN_2        		0x52
-
-#define	LAST_MSG        		0x53
-
-#define	PREFETCH_CNT    		0x54
-
-#define	SCSICONF        		0x5a
-#define		TERM_ENB        	0x80
-#define		RESET_SCSI      	0x40
-#define		HWSCSIID        	0x0f
-#define		HSCSIID         	0x07
-
-#define	HOSTCONF        		0x5d
-
-#define	HA_274_BIOSCTRL 		0x5f
-#define		BIOSMODE        	0x30
-#define		BIOSDISABLED    	0x30
-#define		CHANNEL_B_PRIMARY	0x08
-
-#define	SEQCTL          		0x60
-#define		PERRORDIS       	0x80
-#define		PAUSEDIS        	0x40
-#define		FAILDIS         	0x20
-#define		FASTMODE        	0x10
-#define		BRKADRINTEN     	0x08
-#define		STEP            	0x04
-#define		SEQRESET        	0x02
-#define		LOADRAM         	0x01
-
-#define	SEQRAM          		0x61
-
-#define	SEQADDR0        		0x62
-
-#define	SEQADDR1        		0x63
-#define		SEQADDR1_MASK   	0x01
-
-#define	ACCUM           		0x64
-
-#define	SINDEX          		0x65
-
-#define	DINDEX          		0x66
-
-#define	ALLONES         		0x69
-
-#define	ALLZEROS        		0x6a
-
-#define	NONE            		0x6a
-
-#define	FLAGS           		0x6b
-#define		ZERO            	0x02
-#define		CARRY           	0x01
-
-#define	SINDIR          		0x6c
-
-#define	DINDIR          		0x6d
-
-#define	FUNCTION1       		0x6e
-
-#define	STACK           		0x6f
-
-#define	TARG_OFFSET     		0x70
-
-#define	BCTL            		0x84
-#define		ACE             	0x08
-#define		ENABLE          	0x01
-
-#define	DSCOMMAND0      		0x84
-#define		INTSCBRAMSEL    	0x08
-#define		RAMPS           	0x04
-#define		USCBSIZE32      	0x02
-#define		CIOPARCKEN      	0x01
-
-#define	DSCOMMAND       		0x84
-#define		CACHETHEN       	0x80
-#define		DPARCKEN        	0x40
-#define		MPARCKEN        	0x20
-#define		EXTREQLCK       	0x10
-
-#define	BUSTIME         		0x85
-#define		BOFF            	0xf0
-#define		BON             	0x0f
-
-#define	BUSSPD          		0x86
-#define		DFTHRSH         	0xc0
-#define		STBOFF          	0x38
-#define		STBON           	0x07
-
-#define	DSPCISTATUS     		0x86
-#define		DFTHRSH_100     	0xc0
-
-#define	HCNTRL          		0x87
-#define		POWRDN          	0x40
-#define		SWINT           	0x10
-#define		IRQMS           	0x08
-#define		PAUSE           	0x04
-#define		INTEN           	0x02
-#define		CHIPRST         	0x01
-#define		CHIPRSTACK      	0x01
-
-#define	HADDR           		0x88
-
-#define	HCNT            		0x8c
-
-#define	SCBPTR          		0x90
-
-#define	INTSTAT         		0x91
-#define		SEQINT_MASK     	0xf1
-#define		DATA_OVERRUN    	0xe1
-#define		MSGIN_PHASEMIS  	0xd1
-#define		TRACEPOINT2     	0xc1
-#define		TRACEPOINT      	0xb1
-#define		AWAITING_MSG    	0xa1
-#define		RESIDUAL        	0x81
-#define		BAD_STATUS      	0x71
-#define		REJECT_MSG      	0x61
-#define		WIDE_RESIDUE    	0x51
-#define		EXTENDED_MSG    	0x41
-#define		NO_MATCH        	0x31
-#define		NO_IDENT        	0x21
-#define		SEND_REJECT     	0x11
-#define		INT_PEND        	0x0f
-#define		BRKADRINT       	0x08
-#define		SCSIINT         	0x04
-#define		CMDCMPLT        	0x02
-#define		BAD_PHASE       	0x01
-#define		SEQINT          	0x01
-
-#define	CLRINT          		0x92
-#define		CLRPARERR       	0x10
-#define		CLRBRKADRINT    	0x08
-#define		CLRSCSIINT      	0x04
-#define		CLRCMDINT       	0x02
-#define		CLRSEQINT       	0x01
-
-#define	ERROR           		0x92
-#define		CIOPARERR       	0x80
-#define		PCIERRSTAT      	0x40
-#define		MPARERR         	0x20
-#define		DPARERR         	0x10
-#define		SQPARERR        	0x08
-#define		ILLOPCODE       	0x04
-#define		DSCTMOUT        	0x02
-#define		ILLSADDR        	0x02
-#define		ILLHADDR        	0x01
-
-#define	DFCNTRL         		0x93
-
-#define	DFSTATUS        		0x94
-#define		PRELOAD_AVAIL   	0x80
-#define		DWORDEMP        	0x20
-#define		MREQPEND        	0x10
-#define		HDONE           	0x08
-#define		DFTHRESH        	0x04
-#define		FIFOFULL        	0x02
-#define		FIFOEMP         	0x01
-
-#define	DFDAT           		0x99
-
-#define	SCBCNT          		0x9a
-#define		SCBAUTO         	0x80
-#define		SCBCNT_MASK     	0x1f
-
-#define	QINFIFO         		0x9b
-
-#define	QINCNT          		0x9c
-
-#define	SCSIDATL_IMG    		0x9c
-
-#define	QOUTFIFO        		0x9d
-
-#define	CRCCONTROL1     		0x9d
-#define		CRCONSEEN       	0x80
-#define		CRCVALCHKEN     	0x40
-#define		CRCENDCHKEN     	0x20
-#define		CRCREQCHKEN     	0x10
-#define		TARGCRCENDEN    	0x08
-#define		TARGCRCCNTEN    	0x04
-
-#define	QOUTCNT         		0x9e
-
-#define	SCSIPHASE       		0x9e
-#define		SP_STATUS       	0x20
-#define		SP_COMMAND      	0x10
-#define		SP_MSG_IN       	0x08
-#define		SP_MSG_OUT      	0x04
-#define		SP_DATA_IN      	0x02
-#define		SP_DATA_OUT     	0x01
-
-#define	SFUNCT          		0x9f
-#define		ALT_MODE        	0x80
-
-#define	SCB_CONTROL     		0xa0
-#define		MK_MESSAGE      	0x80
-#define		DISCENB         	0x40
-#define		TAG_ENB         	0x20
-#define		DISCONNECTED    	0x04
-#define		SCB_TAG_TYPE    	0x03
-
-#define	SCB_BASE        		0xa0
-
-#define	SCB_TCL         		0xa1
-#define		TID             	0xf0
-#define		SELBUSB         	0x08
-#define		LID             	0x07
-
-#define	SCB_TARGET_STATUS		0xa2
-
-#define	SCB_SGCOUNT     		0xa3
-
-#define	SCB_SGPTR       		0xa4
-
-#define	SCB_RESID_SGCNT 		0xa8
-
-#define	SCB_RESID_DCNT  		0xa9
-
-#define	SCB_DATAPTR     		0xac
-
-#define	SCB_DATACNT     		0xb0
-
-#define	SCB_CMDPTR      		0xb4
-
-#define	SCB_CMDLEN      		0xb8
-
-#define	SCB_TAG         		0xb9
-
-#define	SCB_NEXT        		0xba
-
-#define	SCB_PREV        		0xbb
-
-#define	SCB_BUSYTARGETS 		0xbc
-
-#define	SEECTL_2840     		0xc0
-#define		CS_2840         	0x04
-#define		CK_2840         	0x02
-#define		DO_2840         	0x01
-
-#define	STATUS_2840     		0xc1
-#define		EEPROM_TF       	0x80
-#define		BIOS_SEL        	0x60
-#define		ADSEL           	0x1e
-#define		DI_2840         	0x01
-
-#define	CCHADDR         		0xe0
-
-#define	CCHCNT          		0xe8
-
-#define	CCSGRAM         		0xe9
-
-#define	CCSGADDR        		0xea
-
-#define	CCSGCTL         		0xeb
-#define		CCSGDONE        	0x80
-#define		CCSGEN          	0x08
-#define		FLAG            	0x02
-#define		CCSGRESET       	0x01
-
-#define	CCSCBRAM        		0xec
-
-#define	CCSCBADDR       		0xed
-
-#define	CCSCBCTL        		0xee
-#define		CCSCBDONE       	0x80
-#define		ARRDONE         	0x40
-#define		CCARREN         	0x10
-#define		CCSCBEN         	0x08
-#define		CCSCBDIR        	0x04
-#define		CCSCBRESET      	0x01
-
-#define	CCSCBCNT        		0xef
-
-#define	CCSCBPTR        		0xf1
-
-#define	HNSCB_QOFF      		0xf4
-
-#define	HESCB_QOFF      		0xf5
-
-#define	SNSCB_QOFF      		0xf6
-
-#define	SESCB_QOFF      		0xf7
-
-#define	SDSCB_QOFF      		0xf8
-
-#define	QOFF_CTLSTA     		0xfa
-#define		ESTABLISH_SCB_AVAIL	0x80
-#define		SCB_AVAIL       	0x40
-#define		SNSCB_ROLLOVER  	0x20
-#define		SDSCB_ROLLOVER  	0x10
-#define		SESCB_ROLLOVER  	0x08
-#define		SCB_QSIZE       	0x07
-#define		SCB_QSIZE_256   	0x06
-
-#define	DFF_THRSH       		0xfb
-#define		WR_DFTHRSH      	0x70
-#define		WR_DFTHRSH_MAX  	0x70
-#define		WR_DFTHRSH_90   	0x60
-#define		WR_DFTHRSH_85   	0x50
-#define		WR_DFTHRSH_75   	0x40
-#define		WR_DFTHRSH_63   	0x30
-#define		WR_DFTHRSH_50   	0x20
-#define		WR_DFTHRSH_25   	0x10
-#define		RD_DFTHRSH_MAX  	0x07
-#define		RD_DFTHRSH      	0x07
-#define		RD_DFTHRSH_90   	0x06
-#define		RD_DFTHRSH_85   	0x05
-#define		RD_DFTHRSH_75   	0x04
-#define		RD_DFTHRSH_63   	0x03
-#define		RD_DFTHRSH_50   	0x02
-#define		RD_DFTHRSH_25   	0x01
-#define		RD_DFTHRSH_MIN  	0x00
-#define		WR_DFTHRSH_MIN  	0x00
-
-#define	SG_CACHEPTR     		0xfc
-#define		SG_USER_DATA    	0xfc
-#define		LAST_SEG        	0x02
-#define		LAST_SEG_DONE   	0x01
-
-
-#define	CMD_GROUP_CODE_SHIFT	0x05
-#define	BUS_8_BIT	0x00
-#define	QOUTFIFO_OFFSET	0x01
-#define	CCSGRAM_MAXSEGS	0x10
-#define	CMD_GROUP2_BYTE_DELTA	0xfa
-#define	MAX_OFFSET_8BIT	0x0f
-#define	BUS_16_BIT	0x01
-#define	QINFIFO_OFFSET	0x02
-#define	CMD_GROUP5_BYTE_DELTA	0x0b
-#define	MAX_OFFSET_ULTRA2	0x7f
-#define	MAX_OFFSET_16BIT	0x08
-#define	UNTAGGEDSCB_OFFSET	0x00
-#define	SCB_LIST_NULL	0xff
-#define	SG_SIZEOF	0x08
-#define	CMD_GROUP4_BYTE_DELTA	0x04
-#define	CMD_GROUP0_BYTE_DELTA	0xfc
-#define	HOST_MSG	0xff
-#define	BUS_32_BIT	0x02
-#define	CCSGADDR_MAX	0x80
-
-
-/* Downloaded Constant Definitions */
-#define	TMODE_NUMCMDS	0x00
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/aic7xxx_seq.c linux.19p18/drivers/scsi/aic7xxx_seq.c
--- linux.vanilla/drivers/scsi/aic7xxx_seq.c	Sat Sep  9 18:42:41 2000
+++ linux.19p18/drivers/scsi/aic7xxx_seq.c	Thu Jan  1 01:00:00 1970
@@ -1,745 +0,0 @@
-/*
-  * DO NOT EDIT - This file is automatically generated.
-  */
-static unsigned char seqprog[] = {
-	0xff, 0x6a, 0x06, 0x08,
-	0x7f, 0x02, 0x04, 0x08,
-	0x12, 0x6a, 0x00, 0x00,
-	0xff, 0x6a, 0xd6, 0x09,
-	0xff, 0x6a, 0xdc, 0x09,
-	0x00, 0x65, 0xca, 0x58,
-	0xf7, 0x01, 0x02, 0x08,
-	0xff, 0x4e, 0xc8, 0x08,
-	0xbf, 0x60, 0xc0, 0x08,
-	0x60, 0x0b, 0x86, 0x68,
-	0x40, 0x00, 0x0c, 0x68,
-	0x08, 0x1f, 0x3e, 0x10,
-	0x60, 0x0b, 0x86, 0x68,
-	0x40, 0x00, 0x0c, 0x68,
-	0x08, 0x1f, 0x3e, 0x10,
-	0xff, 0x3e, 0x48, 0x60,
-	0x40, 0xfa, 0x10, 0x78,
-	0xff, 0xf6, 0xd4, 0x08,
-	0x01, 0x4e, 0x9c, 0x18,
-	0x40, 0x60, 0xc0, 0x00,
-	0x00, 0x4d, 0x10, 0x70,
-	0x01, 0x4e, 0x9c, 0x18,
-	0xbf, 0x60, 0xc0, 0x08,
-	0x00, 0x6a, 0x3e, 0x5c,
-	0xff, 0x4e, 0xc8, 0x18,
-	0x02, 0x6a, 0x54, 0x5b,
-	0xff, 0x52, 0x20, 0x09,
-	0x0d, 0x6a, 0x6a, 0x00,
-	0x00, 0x52, 0xca, 0x5b,
-	0x03, 0xb0, 0x52, 0x31,
-	0xff, 0xb0, 0x52, 0x09,
-	0xff, 0xb1, 0x54, 0x09,
-	0xff, 0xb2, 0x56, 0x09,
-	0xff, 0xa3, 0x50, 0x09,
-	0xff, 0x3e, 0x74, 0x09,
-	0xff, 0x90, 0x7c, 0x08,
-	0xff, 0x3e, 0x20, 0x09,
-	0x00, 0x65, 0x4e, 0x58,
-	0x00, 0x65, 0x0c, 0x40,
-	0xf7, 0x1f, 0xca, 0x08,
-	0x08, 0xa1, 0xc8, 0x08,
-	0x00, 0x65, 0xca, 0x00,
-	0xff, 0x65, 0x3e, 0x08,
-	0xf0, 0xa1, 0xc8, 0x08,
-	0x0f, 0x0f, 0x1e, 0x08,
-	0x00, 0x0f, 0x1e, 0x00,
-	0xf0, 0xa1, 0xc8, 0x08,
-	0x0f, 0x05, 0x0a, 0x08,
-	0x00, 0x05, 0x0a, 0x00,
-	0xff, 0x6a, 0x0c, 0x08,
-	0x5a, 0x6a, 0x00, 0x04,
-	0x12, 0x65, 0x02, 0x00,
-	0x31, 0x6a, 0xca, 0x00,
-	0x80, 0x37, 0x6e, 0x68,
-	0xff, 0x65, 0xca, 0x18,
-	0xff, 0x37, 0xdc, 0x08,
-	0xff, 0x6e, 0xc8, 0x08,
-	0x00, 0x6c, 0x76, 0x78,
-	0x20, 0x01, 0x02, 0x00,
-	0x4c, 0x37, 0xc8, 0x28,
-	0x08, 0x1f, 0x7e, 0x78,
-	0x08, 0x37, 0x6e, 0x00,
-	0x08, 0x64, 0xc8, 0x00,
-	0x70, 0x64, 0xca, 0x18,
-	0xff, 0x6c, 0x0a, 0x08,
-	0x20, 0x64, 0xca, 0x18,
-	0xff, 0x6c, 0x08, 0x0c,
-	0x40, 0x0b, 0x96, 0x68,
-	0x20, 0x6a, 0x16, 0x00,
-	0xf0, 0x19, 0x6e, 0x08,
-	0x08, 0x6a, 0x18, 0x00,
-	0x08, 0x11, 0x22, 0x00,
-	0x08, 0x6a, 0x66, 0x58,
-	0x08, 0x6a, 0x68, 0x00,
-	0x00, 0x65, 0xaa, 0x40,
-	0x12, 0x6a, 0x00, 0x00,
-	0x40, 0x6a, 0x16, 0x00,
-	0xff, 0x3e, 0x20, 0x09,
-	0xff, 0xba, 0x7c, 0x08,
-	0xff, 0xa1, 0x6e, 0x08,
-	0x08, 0x6a, 0x18, 0x00,
-	0x08, 0x11, 0x22, 0x00,
-	0x08, 0x6a, 0x66, 0x58,
-	0x80, 0x6a, 0x68, 0x00,
-	0x80, 0x36, 0x6c, 0x00,
-	0x00, 0x65, 0x9e, 0x5b,
-	0xff, 0x3d, 0xc8, 0x08,
-	0xbf, 0x64, 0xe2, 0x78,
-	0x80, 0x64, 0xac, 0x71,
-	0xa0, 0x64, 0xdc, 0x71,
-	0xc0, 0x64, 0xd4, 0x71,
-	0xe0, 0x64, 0x1c, 0x72,
-	0x01, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0xaa, 0x40,
-	0xf7, 0x11, 0x22, 0x08,
-	0x00, 0x65, 0xca, 0x58,
-	0xff, 0x06, 0xd4, 0x08,
-	0xf7, 0x01, 0x02, 0x08,
-	0x09, 0x0c, 0xc4, 0x78,
-	0x08, 0x0c, 0x0c, 0x68,
-	0x01, 0x6a, 0x22, 0x01,
-	0xff, 0x6a, 0x26, 0x09,
-	0x02, 0x6a, 0x08, 0x30,
-	0xff, 0x6a, 0x08, 0x08,
-	0xdf, 0x01, 0x02, 0x08,
-	0x01, 0x6a, 0x7a, 0x00,
-	0xff, 0x6a, 0x6c, 0x0c,
-	0x04, 0x14, 0x10, 0x31,
-	0x03, 0xa9, 0x18, 0x31,
-	0x03, 0xa9, 0x10, 0x30,
-	0x08, 0x6a, 0xcc, 0x00,
-	0xa9, 0x6a, 0xb4, 0x5b,
-	0x00, 0x65, 0x02, 0x41,
-	0xa8, 0x6a, 0x6a, 0x00,
-	0x79, 0x6a, 0x6a, 0x00,
-	0x40, 0x3d, 0xea, 0x68,
-	0x04, 0x35, 0x6a, 0x00,
-	0x00, 0x65, 0x0e, 0x5b,
-	0x80, 0x6a, 0xd4, 0x01,
-	0x10, 0x36, 0xd6, 0x68,
-	0x10, 0x36, 0x6c, 0x00,
-	0x07, 0xac, 0x10, 0x31,
-	0x03, 0x8c, 0x10, 0x30,
-	0x05, 0xa3, 0x70, 0x30,
-	0x88, 0x6a, 0xcc, 0x00,
-	0xac, 0x6a, 0xac, 0x5b,
-	0x00, 0x65, 0xa6, 0x5b,
-	0x38, 0x6a, 0xcc, 0x00,
-	0xa3, 0x6a, 0xb0, 0x5b,
-	0xff, 0x38, 0x12, 0x69,
-	0x80, 0x02, 0x04, 0x00,
-	0xe7, 0x35, 0x6a, 0x08,
-	0x03, 0x69, 0x18, 0x31,
-	0x03, 0x69, 0x10, 0x30,
-	0xff, 0x6a, 0x10, 0x00,
-	0xff, 0x6a, 0x12, 0x00,
-	0xff, 0x6a, 0x14, 0x00,
-	0x01, 0x38, 0x18, 0x61,
-	0xbf, 0x35, 0x6a, 0x08,
-	0x02, 0x6a, 0xf8, 0x01,
-	0xff, 0x69, 0xca, 0x08,
-	0xff, 0x35, 0x26, 0x09,
-	0x04, 0x0b, 0x1c, 0x69,
-	0x04, 0x0b, 0x28, 0x69,
-	0x10, 0x0c, 0x1e, 0x79,
-	0x04, 0x0b, 0x28, 0x69,
-	0xff, 0x6a, 0xca, 0x08,
-	0x00, 0x35, 0xee, 0x5a,
-	0x80, 0x02, 0x7c, 0x69,
-	0xff, 0x65, 0x6c, 0x79,
-	0xff, 0x38, 0x70, 0x18,
-	0xff, 0x38, 0x6c, 0x79,
-	0x80, 0xea, 0x48, 0x61,
-	0xef, 0x38, 0xc8, 0x18,
-	0x80, 0x6a, 0xc8, 0x00,
-	0x00, 0x65, 0x3a, 0x49,
-	0x33, 0x38, 0xc8, 0x28,
-	0xff, 0x64, 0xd0, 0x09,
-	0x04, 0x39, 0xc0, 0x31,
-	0x09, 0x6a, 0xd6, 0x01,
-	0x80, 0xeb, 0x40, 0x79,
-	0xf7, 0xeb, 0xd6, 0x09,
-	0x08, 0xeb, 0x44, 0x69,
-	0x01, 0x6a, 0xd6, 0x01,
-	0x08, 0xe9, 0x10, 0x31,
-	0x03, 0x8c, 0x10, 0x30,
-	0x88, 0x6a, 0xcc, 0x00,
-	0x39, 0x6a, 0xb2, 0x5b,
-	0x08, 0x6a, 0x18, 0x01,
-	0xff, 0x6a, 0x1a, 0x09,
-	0xff, 0x6a, 0x1c, 0x09,
-	0x0d, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0x30, 0x5c,
-	0x88, 0x6a, 0x20, 0x5c,
-	0x00, 0x65, 0xa6, 0x5b,
-	0xff, 0x6a, 0xc8, 0x08,
-	0x08, 0x39, 0x72, 0x18,
-	0x00, 0x3a, 0x74, 0x20,
-	0x01, 0x0c, 0x64, 0x79,
-	0x10, 0x0c, 0x02, 0x79,
-	0xff, 0x35, 0x26, 0x09,
-	0x04, 0x0b, 0x6a, 0x69,
-	0x00, 0x65, 0x84, 0x59,
-	0x03, 0x08, 0x52, 0x31,
-	0xff, 0x38, 0x50, 0x09,
-	0xff, 0x08, 0x52, 0x09,
-	0xff, 0x09, 0x54, 0x09,
-	0xff, 0x0a, 0x56, 0x09,
-	0xff, 0x38, 0x50, 0x09,
-	0x00, 0x65, 0xaa, 0x40,
-	0x00, 0x65, 0x84, 0x59,
-	0x7f, 0x02, 0x04, 0x08,
-	0xe1, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0xaa, 0x40,
-	0x04, 0x93, 0x9a, 0x69,
-	0xdf, 0x93, 0x26, 0x09,
-	0x20, 0x93, 0x88, 0x69,
-	0x02, 0x93, 0x26, 0x01,
-	0x01, 0x94, 0x8a, 0x79,
-	0x01, 0x94, 0x8a, 0x79,
-	0x01, 0x94, 0x8a, 0x79,
-	0x01, 0x94, 0x8a, 0x79,
-	0x01, 0x94, 0x8a, 0x79,
-	0x01, 0x94, 0x8a, 0x79,
-	0x10, 0x94, 0x98, 0x69,
-	0x7f, 0x05, 0xa0, 0x69,
-	0x02, 0x03, 0xa0, 0x79,
-	0x11, 0x0c, 0x9c, 0x79,
-	0xd7, 0x93, 0x26, 0x09,
-	0x28, 0x93, 0xa2, 0x69,
-	0x03, 0x08, 0x52, 0x31,
-	0xff, 0x38, 0x50, 0x09,
-	0x12, 0x01, 0x02, 0x00,
-	0xff, 0x6a, 0xd4, 0x0c,
-	0x00, 0x65, 0x0e, 0x5b,
-	0x05, 0xb4, 0x10, 0x31,
-	0x02, 0x6a, 0x1a, 0x31,
-	0x03, 0x8c, 0x10, 0x30,
-	0x88, 0x6a, 0xcc, 0x00,
-	0xb4, 0x6a, 0xb0, 0x5b,
-	0xff, 0x6a, 0x1a, 0x09,
-	0xff, 0x6a, 0x1c, 0x09,
-	0x00, 0x65, 0xa6, 0x5b,
-	0x3d, 0x6a, 0xee, 0x5a,
-	0xac, 0x6a, 0x26, 0x01,
-	0x04, 0x0b, 0xc2, 0x69,
-	0x04, 0x0b, 0xc8, 0x69,
-	0x10, 0x0c, 0xc4, 0x79,
-	0x02, 0x03, 0xcc, 0x79,
-	0x11, 0x0c, 0xc8, 0x79,
-	0xd7, 0x93, 0x26, 0x09,
-	0x28, 0x93, 0xce, 0x69,
-	0x12, 0x01, 0x02, 0x00,
-	0x00, 0x65, 0xaa, 0x40,
-	0x00, 0x65, 0x0e, 0x5b,
-	0xff, 0x06, 0x44, 0x09,
-	0x00, 0x65, 0xaa, 0x40,
-	0x10, 0x3d, 0x06, 0x00,
-	0xff, 0x34, 0xca, 0x08,
-	0x80, 0x65, 0x00, 0x62,
-	0x0f, 0xa1, 0xca, 0x08,
-	0x07, 0xa1, 0xca, 0x08,
-	0x40, 0xa0, 0xc8, 0x08,
-	0x00, 0x65, 0xca, 0x00,
-	0x80, 0x65, 0xca, 0x00,
-	0x80, 0xa0, 0xf0, 0x79,
-	0xff, 0x65, 0x0c, 0x08,
-	0x00, 0x65, 0x02, 0x42,
-	0x20, 0xa0, 0x08, 0x7a,
-	0xff, 0x65, 0x0c, 0x08,
-	0x00, 0x65, 0x9e, 0x5b,
-	0xa0, 0x3d, 0x10, 0x62,
-	0x23, 0xa0, 0x0c, 0x08,
-	0x00, 0x65, 0x9e, 0x5b,
-	0xa0, 0x3d, 0x10, 0x62,
-	0x00, 0xb9, 0x08, 0x42,
-	0xff, 0x65, 0x08, 0x62,
-	0xa1, 0x6a, 0x22, 0x01,
-	0xff, 0x6a, 0xd4, 0x08,
-	0x10, 0x51, 0x10, 0x72,
-	0x40, 0x6a, 0x18, 0x00,
-	0xff, 0x65, 0x0c, 0x08,
-	0x00, 0x65, 0x9e, 0x5b,
-	0xa0, 0x3d, 0xda, 0x71,
-	0x40, 0x6a, 0x18, 0x00,
-	0xff, 0x34, 0xa6, 0x08,
-	0x80, 0x34, 0x18, 0x62,
-	0x7f, 0xa0, 0x40, 0x09,
-	0x08, 0x6a, 0x68, 0x00,
-	0x00, 0x65, 0xaa, 0x40,
-	0x64, 0x6a, 0xe4, 0x5a,
-	0x80, 0x64, 0x8e, 0x6a,
-	0x04, 0x64, 0x70, 0x72,
-	0x02, 0x64, 0x76, 0x72,
-	0x00, 0x6a, 0x38, 0x72,
-	0x03, 0x64, 0x8a, 0x72,
-	0x01, 0x64, 0x6c, 0x72,
-	0x07, 0x64, 0xcc, 0x72,
-	0x08, 0x64, 0x34, 0x72,
-	0x23, 0x64, 0xd0, 0x72,
-	0x11, 0x6a, 0x22, 0x01,
-	0x07, 0x6a, 0xd6, 0x5a,
-	0xff, 0x06, 0xd4, 0x08,
-	0x00, 0x65, 0xaa, 0x40,
-	0xff, 0xa8, 0x3c, 0x6a,
-	0xff, 0xa2, 0x54, 0x7a,
-	0x01, 0x6a, 0x6a, 0x00,
-	0x00, 0xb9, 0xca, 0x5b,
-	0xff, 0xa2, 0x54, 0x7a,
-	0x71, 0x6a, 0x22, 0x01,
-	0xff, 0x6a, 0xd4, 0x08,
-	0x40, 0x51, 0x54, 0x62,
-	0x0d, 0x6a, 0x6a, 0x00,
-	0x00, 0xb9, 0xca, 0x5b,
-	0xff, 0x3e, 0x74, 0x09,
-	0xff, 0x90, 0x7c, 0x08,
-	0x00, 0x65, 0x4e, 0x58,
-	0x00, 0x65, 0xbc, 0x40,
-	0x20, 0xa0, 0x5c, 0x6a,
-	0xff, 0x37, 0xc8, 0x08,
-	0x00, 0x6a, 0x74, 0x5b,
-	0xff, 0x6a, 0x8a, 0x5b,
-	0xff, 0xf8, 0xc8, 0x08,
-	0xff, 0x4f, 0xc8, 0x08,
-	0x01, 0x6a, 0x74, 0x5b,
-	0x00, 0xb9, 0x8a, 0x5b,
-	0x01, 0x4f, 0x9e, 0x18,
-	0x02, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0x38, 0x5c,
-	0x00, 0x65, 0xbc, 0x40,
-	0x41, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0xaa, 0x40,
-	0x04, 0xa0, 0x40, 0x01,
-	0x00, 0x65, 0x50, 0x5c,
-	0x00, 0x65, 0xbc, 0x40,
-	0x10, 0x36, 0x34, 0x7a,
-	0x05, 0x38, 0x46, 0x31,
-	0x04, 0x14, 0x58, 0x31,
-	0x03, 0xa9, 0x60, 0x31,
-	0xa3, 0x6a, 0xcc, 0x00,
-	0x38, 0x6a, 0xb0, 0x5b,
-	0xac, 0x6a, 0xcc, 0x00,
-	0x14, 0x6a, 0xb2, 0x5b,
-	0xa9, 0x6a, 0xb4, 0x5b,
-	0x00, 0x65, 0x34, 0x42,
-	0xef, 0x36, 0x6c, 0x08,
-	0x00, 0x65, 0x34, 0x42,
-	0x0f, 0x64, 0xc8, 0x08,
-	0x07, 0x64, 0xc8, 0x08,
-	0x00, 0x37, 0x6e, 0x00,
-	0xff, 0x6a, 0xa4, 0x00,
-	0x00, 0x65, 0x44, 0x5b,
-	0xff, 0x51, 0xa0, 0x72,
-	0x20, 0x36, 0xaa, 0x7a,
-	0x00, 0x90, 0x32, 0x5b,
-	0x00, 0x65, 0xac, 0x42,
-	0xff, 0x06, 0xd4, 0x08,
-	0x00, 0x65, 0x9e, 0x5b,
-	0xe0, 0x3d, 0xc6, 0x62,
-	0x20, 0x12, 0xc6, 0x62,
-	0x51, 0x6a, 0xda, 0x5a,
-	0x00, 0x65, 0x2c, 0x5b,
-	0xff, 0x37, 0xc8, 0x08,
-	0x00, 0xa1, 0xbe, 0x62,
-	0x04, 0xa0, 0xbe, 0x7a,
-	0xfb, 0xa0, 0x40, 0x09,
-	0x80, 0x36, 0x6c, 0x00,
-	0x80, 0xa0, 0x34, 0x7a,
-	0x7f, 0xa0, 0x40, 0x09,
-	0xff, 0x6a, 0xd6, 0x5a,
-	0x00, 0x65, 0x34, 0x42,
-	0x04, 0xa0, 0xc4, 0x7a,
-	0x00, 0x65, 0x50, 0x5c,
-	0x00, 0x65, 0xc6, 0x42,
-	0x00, 0x65, 0x38, 0x5c,
-	0x31, 0x6a, 0x22, 0x01,
-	0x0c, 0x6a, 0xd6, 0x5a,
-	0x00, 0x65, 0x34, 0x42,
-	0x61, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0x34, 0x42,
-	0x51, 0x6a, 0xda, 0x5a,
-	0x51, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0x34, 0x42,
-	0x10, 0x3d, 0x06, 0x00,
-	0xff, 0x65, 0x68, 0x0c,
-	0xff, 0x06, 0xd4, 0x08,
-	0x01, 0x0c, 0xdc, 0x7a,
-	0x04, 0x0c, 0xde, 0x6a,
-	0xe0, 0x03, 0x7a, 0x08,
-	0xe0, 0x3d, 0xea, 0x62,
-	0xff, 0x65, 0xcc, 0x08,
-	0xff, 0x12, 0xda, 0x0c,
-	0xff, 0x06, 0xd4, 0x0c,
-	0xd1, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0xaa, 0x40,
-	0xff, 0x65, 0x26, 0x09,
-	0x01, 0x0b, 0xfe, 0x6a,
-	0x10, 0x0c, 0xf0, 0x7a,
-	0x04, 0x0b, 0xf8, 0x6a,
-	0xff, 0x6a, 0xca, 0x08,
-	0x04, 0x93, 0xfc, 0x6a,
-	0x01, 0x94, 0xfa, 0x7a,
-	0x10, 0x94, 0xfc, 0x6a,
-	0x80, 0x3d, 0x02, 0x73,
-	0x0f, 0x04, 0x06, 0x6b,
-	0x02, 0x03, 0x06, 0x7b,
-	0x11, 0x0c, 0x02, 0x7b,
-	0xc7, 0x93, 0x26, 0x09,
-	0xff, 0x99, 0xd4, 0x08,
-	0x38, 0x93, 0x08, 0x6b,
-	0xff, 0x6a, 0xd4, 0x0c,
-	0x80, 0x36, 0x0c, 0x6b,
-	0x21, 0x6a, 0x22, 0x05,
-	0xff, 0x65, 0x20, 0x09,
-	0xff, 0x51, 0x1a, 0x63,
-	0xff, 0x37, 0xc8, 0x08,
-	0xa1, 0x6a, 0x26, 0x43,
-	0xff, 0x51, 0xc8, 0x08,
-	0xb9, 0x6a, 0x26, 0x43,
-	0xff, 0x90, 0xa4, 0x08,
-	0xff, 0xba, 0x2a, 0x73,
-	0xff, 0xba, 0x20, 0x09,
-	0xff, 0x65, 0xca, 0x18,
-	0x00, 0x6c, 0x1e, 0x63,
-	0xff, 0x90, 0xca, 0x0c,
-	0xff, 0x6a, 0xca, 0x04,
-	0x20, 0x36, 0x3e, 0x7b,
-	0x00, 0x90, 0x12, 0x5b,
-	0xff, 0x65, 0x3e, 0x73,
-	0xff, 0x52, 0x3c, 0x73,
-	0xff, 0xba, 0xcc, 0x08,
-	0xff, 0x52, 0x20, 0x09,
-	0xff, 0x66, 0x74, 0x09,
-	0xff, 0x65, 0x20, 0x0d,
-	0xff, 0xba, 0x7e, 0x0c,
-	0x00, 0x6a, 0x3e, 0x5c,
-	0x0d, 0x6a, 0x6a, 0x00,
-	0x00, 0x51, 0xca, 0x43,
-	0xff, 0x3f, 0x98, 0x73,
-	0xff, 0x6a, 0xa2, 0x00,
-	0x00, 0x3f, 0x12, 0x5b,
-	0xff, 0x65, 0x98, 0x73,
-	0x20, 0x36, 0x6c, 0x00,
-	0x20, 0xa0, 0x52, 0x6b,
-	0xff, 0xb9, 0xa2, 0x0c,
-	0xff, 0x6a, 0xa2, 0x04,
-	0xff, 0x65, 0xa4, 0x08,
-	0xe0, 0x6a, 0xcc, 0x00,
-	0x45, 0x6a, 0xbe, 0x5b,
-	0x01, 0x6a, 0xd0, 0x01,
-	0x09, 0x6a, 0xd6, 0x01,
-	0x80, 0xeb, 0x5e, 0x7b,
-	0x01, 0x6a, 0xd6, 0x01,
-	0x01, 0xe9, 0xa4, 0x34,
-	0x88, 0x6a, 0xcc, 0x00,
-	0x45, 0x6a, 0xbe, 0x5b,
-	0x01, 0x6a, 0x18, 0x01,
-	0xff, 0x6a, 0x1a, 0x09,
-	0xff, 0x6a, 0x1c, 0x09,
-	0x0d, 0x6a, 0x26, 0x01,
-	0x00, 0x65, 0x30, 0x5c,
-	0xff, 0x99, 0xa4, 0x0c,
-	0xff, 0x65, 0xa4, 0x08,
-	0xe0, 0x6a, 0xcc, 0x00,
-	0x45, 0x6a, 0xbe, 0x5b,
-	0x01, 0x6a, 0xd0, 0x01,
-	0x01, 0x6a, 0xdc, 0x05,
-	0x88, 0x6a, 0xcc, 0x00,
-	0x45, 0x6a, 0xbe, 0x5b,
-	0x01, 0x6a, 0x18, 0x01,
-	0xff, 0x6a, 0x1a, 0x09,
-	0xff, 0x6a, 0x1c, 0x09,
-	0x01, 0x6a, 0x26, 0x05,
-	0x01, 0x65, 0xd8, 0x31,
-	0x09, 0xee, 0xdc, 0x01,
-	0x80, 0xee, 0x8e, 0x7b,
-	0xff, 0x6a, 0xdc, 0x0d,
-	0xff, 0x65, 0x32, 0x09,
-	0x0a, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0x30, 0x44,
-	0xff, 0x37, 0xc8, 0x08,
-	0x00, 0x6a, 0x54, 0x5b,
-	0xff, 0x52, 0xa2, 0x0c,
-	0x01, 0x0c, 0x9e, 0x7b,
-	0x04, 0x0c, 0x9e, 0x6b,
-	0xe0, 0x03, 0x06, 0x08,
-	0xe0, 0x03, 0x7a, 0x0c,
-	0xff, 0x8c, 0x10, 0x08,
-	0xff, 0x8d, 0x12, 0x08,
-	0xff, 0x8e, 0x14, 0x0c,
-	0xff, 0x6c, 0xda, 0x08,
-	0xff, 0x6c, 0xda, 0x08,
-	0xff, 0x6c, 0xda, 0x08,
-	0xff, 0x6c, 0xda, 0x08,
-	0xff, 0x6c, 0xda, 0x08,
-	0xff, 0x6c, 0xda, 0x08,
-	0xff, 0x6c, 0xda, 0x0c,
-	0x3d, 0x64, 0xa4, 0x28,
-	0x55, 0x64, 0xc8, 0x28,
-	0x00, 0x6c, 0xda, 0x18,
-	0xff, 0x52, 0xc8, 0x08,
-	0x00, 0x6c, 0xda, 0x20,
-	0xff, 0x6a, 0xc8, 0x08,
-	0x00, 0x6c, 0xda, 0x20,
-	0x00, 0x6c, 0xda, 0x24,
-	0xff, 0x65, 0xc8, 0x08,
-	0xe0, 0x6a, 0xcc, 0x00,
-	0x41, 0x6a, 0xba, 0x5b,
-	0xff, 0x90, 0xe2, 0x09,
-	0x20, 0x6a, 0xd0, 0x01,
-	0x04, 0x35, 0xdc, 0x7b,
-	0x1d, 0x6a, 0xdc, 0x01,
-	0xdc, 0xee, 0xd8, 0x63,
-	0x00, 0x65, 0xe8, 0x43,
-	0x01, 0x6a, 0xdc, 0x01,
-	0x20, 0xa0, 0xd8, 0x31,
-	0x09, 0xee, 0xdc, 0x01,
-	0x80, 0xee, 0xe2, 0x7b,
-	0x19, 0x6a, 0xdc, 0x01,
-	0xd8, 0xee, 0xe6, 0x63,
-	0xff, 0x6a, 0xdc, 0x09,
-	0x18, 0xee, 0xea, 0x6b,
-	0xff, 0x6a, 0xd4, 0x0c,
-	0x88, 0x6a, 0xcc, 0x00,
-	0x41, 0x6a, 0xba, 0x5b,
-	0x20, 0x6a, 0x18, 0x01,
-	0xff, 0x6a, 0x1a, 0x09,
-	0xff, 0x6a, 0x1c, 0x09,
-	0xff, 0x35, 0x26, 0x09,
-	0x04, 0x35, 0x14, 0x6c,
-	0xa0, 0x6a, 0xca, 0x00,
-	0x20, 0x65, 0xc8, 0x18,
-	0xff, 0x6c, 0x32, 0x09,
-	0xff, 0x6c, 0x32, 0x09,
-	0xff, 0x6c, 0x32, 0x09,
-	0xff, 0x6c, 0x32, 0x09,
-	0xff, 0x6c, 0x32, 0x09,
-	0xff, 0x6c, 0x32, 0x09,
-	0xff, 0x6c, 0x32, 0x09,
-	0xff, 0x6c, 0x32, 0x09,
-	0x00, 0x65, 0x00, 0x64,
-	0x0a, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0x30, 0x5c,
-	0x04, 0x35, 0x0c, 0x7b,
-	0xa0, 0x6a, 0x20, 0x5c,
-	0x00, 0x65, 0x22, 0x5c,
-	0x00, 0x65, 0x22, 0x5c,
-	0x00, 0x65, 0x22, 0x44,
-	0xff, 0x65, 0xcc, 0x08,
-	0xff, 0x99, 0xda, 0x08,
-	0xff, 0x99, 0xda, 0x08,
-	0xff, 0x99, 0xda, 0x08,
-	0xff, 0x99, 0xda, 0x08,
-	0xff, 0x99, 0xda, 0x08,
-	0xff, 0x99, 0xda, 0x08,
-	0xff, 0x99, 0xda, 0x0c,
-	0x08, 0x94, 0x30, 0x7c,
-	0xf7, 0x93, 0x26, 0x09,
-	0x08, 0x93, 0x34, 0x6c,
-	0xff, 0x6a, 0xd4, 0x0c,
-	0xff, 0x40, 0x74, 0x09,
-	0xff, 0x90, 0x80, 0x08,
-	0xff, 0x6a, 0x72, 0x05,
-	0xff, 0x40, 0x4c, 0x64,
-	0xff, 0x3f, 0x44, 0x64,
-	0xff, 0x6a, 0xca, 0x04,
-	0xff, 0x3f, 0x20, 0x09,
-	0x01, 0x6a, 0x6a, 0x00,
-	0x00, 0xb9, 0xca, 0x5b,
-	0xff, 0xba, 0x7e, 0x0c,
-	0xff, 0x40, 0x20, 0x09,
-	0xff, 0xba, 0x80, 0x0c,
-	0xff, 0x3f, 0x74, 0x09,
-	0xff, 0x90, 0x7e, 0x0c,
-};
-
-static int aic7xxx_patch12_func(struct aic7xxx_host *p);
-
-static int
-aic7xxx_patch12_func(struct aic7xxx_host *p)
-{
-	return ((p->features & AHC_WIDE) != 0);
-}
-
-static int aic7xxx_patch11_func(struct aic7xxx_host *p);
-
-static int
-aic7xxx_patch11_func(struct aic7xxx_host *p)
-{
-	return ((p->features & AHC_ULTRA2) == 0);
-}
-
-static int aic7xxx_patch10_func(struct aic7xxx_host *p);
-
-static int
-aic7xxx_patch10_func(struct aic7xxx_host *p)
-{
-	return ((p->features & AHC_CMD_CHAN) == 0);
-}
-
-static int aic7xxx_patch9_func(struct aic7xxx_host *p);
-
-static int
-aic7xxx_patch9_func(struct aic7xxx_host *p)
-{
-	return ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895);
-}
-
-static int aic7xxx_patch8_func(struct aic7xxx_host *p);
-
-static int
-aic7xxx_patch8_func(struct aic7xxx_host *p)
-{
-	return ((p->features & AHC_ULTRA) != 0);
-}
-
-static int aic7xxx_patch7_func(struct aic7xxx_host *p);
-
-static int
-aic7xxx_patch7_func(struct aic7xxx_host *p)
-{
-	return ((p->features & AHC_ULTRA2) != 0);
-}
-
-static int aic7xxx_patch6_func(struct aic7xxx_host *p);
-
-static int
-aic7xxx_patch6_func(struct aic7xxx_host *p)
-{
-	return ((p->flags & AHC_PAGESCBS) == 0);
-}
-
-static int aic7xxx_patch5_func(struct aic7xxx_host *p);
-
-static int
-aic7xxx_patch5_func(struct aic7xxx_host *p)
-{
-	return ((p->flags & AHC_PAGESCBS) != 0);
-}
-
-static int aic7xxx_patch4_func(struct aic7xxx_host *p);
-
-static int
-aic7xxx_patch4_func(struct aic7xxx_host *p)
-{
-	return ((p->features & AHC_QUEUE_REGS) != 0);
-}
-
-static int aic7xxx_patch3_func(struct aic7xxx_host *p);
-
-static int
-aic7xxx_patch3_func(struct aic7xxx_host *p)
-{
-	return ((p->features & AHC_TWIN) != 0);
-}
-
-static int aic7xxx_patch2_func(struct aic7xxx_host *p);
-
-static int
-aic7xxx_patch2_func(struct aic7xxx_host *p)
-{
-	return ((p->features & AHC_QUEUE_REGS) == 0);
-}
-
-static int aic7xxx_patch1_func(struct aic7xxx_host *p);
-
-static int
-aic7xxx_patch1_func(struct aic7xxx_host *p)
-{
-	return ((p->features & AHC_CMD_CHAN) != 0);
-}
-
-static int aic7xxx_patch0_func(struct aic7xxx_host *p);
-
-static int
-aic7xxx_patch0_func(struct aic7xxx_host *p)
-{
-	return (0);
-}
-
-struct sequencer_patch {
-	int		(*patch_func)(struct aic7xxx_host *);
-	unsigned int	begin	   :10,
-			skip_instr :10,
-			skip_patch :12;
-} sequencer_patches[] = {
-	{ aic7xxx_patch1_func, 3, 2, 1 },
-	{ aic7xxx_patch2_func, 7, 1, 1 },
-	{ aic7xxx_patch2_func, 8, 1, 1 },
-	{ aic7xxx_patch3_func, 11, 4, 1 },
-	{ aic7xxx_patch4_func, 16, 3, 2 },
-	{ aic7xxx_patch0_func, 19, 4, 1 },
-	{ aic7xxx_patch5_func, 23, 1, 1 },
-	{ aic7xxx_patch6_func, 26, 1, 1 },
-	{ aic7xxx_patch1_func, 29, 1, 2 },
-	{ aic7xxx_patch0_func, 30, 3, 1 },
-	{ aic7xxx_patch3_func, 39, 4, 1 },
-	{ aic7xxx_patch7_func, 43, 3, 2 },
-	{ aic7xxx_patch0_func, 46, 3, 1 },
-	{ aic7xxx_patch8_func, 52, 7, 1 },
-	{ aic7xxx_patch3_func, 60, 3, 1 },
-	{ aic7xxx_patch7_func, 63, 2, 1 },
-	{ aic7xxx_patch7_func, 102, 1, 2 },
-	{ aic7xxx_patch0_func, 103, 2, 1 },
-	{ aic7xxx_patch7_func, 107, 2, 1 },
-	{ aic7xxx_patch9_func, 109, 1, 1 },
-	{ aic7xxx_patch10_func, 110, 2, 1 },
-	{ aic7xxx_patch7_func, 113, 1, 2 },
-	{ aic7xxx_patch0_func, 114, 1, 1 },
-	{ aic7xxx_patch1_func, 118, 1, 1 },
-	{ aic7xxx_patch1_func, 121, 3, 2 },
-	{ aic7xxx_patch0_func, 124, 5, 1 },
-	{ aic7xxx_patch1_func, 132, 2, 3 },
-	{ aic7xxx_patch7_func, 132, 1, 1 },
-	{ aic7xxx_patch0_func, 134, 3, 1 },
-	{ aic7xxx_patch11_func, 138, 1, 2 },
-	{ aic7xxx_patch0_func, 139, 1, 1 },
-	{ aic7xxx_patch7_func, 140, 7, 2 },
-	{ aic7xxx_patch0_func, 147, 1, 1 },
-	{ aic7xxx_patch1_func, 152, 14, 3 },
-	{ aic7xxx_patch11_func, 165, 1, 1 },
-	{ aic7xxx_patch0_func, 166, 9, 1 },
-	{ aic7xxx_patch7_func, 180, 2, 1 },
-	{ aic7xxx_patch7_func, 182, 1, 1 },
-	{ aic7xxx_patch11_func, 183, 6, 3 },
-	{ aic7xxx_patch1_func, 183, 2, 2 },
-	{ aic7xxx_patch0_func, 185, 4, 1 },
-	{ aic7xxx_patch7_func, 190, 1, 1 },
-	{ aic7xxx_patch7_func, 194, 20, 1 },
-	{ aic7xxx_patch1_func, 215, 3, 3 },
-	{ aic7xxx_patch11_func, 217, 1, 1 },
-	{ aic7xxx_patch0_func, 218, 5, 1 },
-	{ aic7xxx_patch11_func, 223, 1, 2 },
-	{ aic7xxx_patch0_func, 224, 9, 1 },
-	{ aic7xxx_patch12_func, 240, 1, 2 },
-	{ aic7xxx_patch0_func, 241, 1, 1 },
-	{ aic7xxx_patch4_func, 302, 1, 2 },
-	{ aic7xxx_patch0_func, 303, 1, 1 },
-	{ aic7xxx_patch2_func, 306, 1, 1 },
-	{ aic7xxx_patch1_func, 316, 3, 2 },
-	{ aic7xxx_patch0_func, 319, 5, 1 },
-	{ aic7xxx_patch12_func, 327, 1, 2 },
-	{ aic7xxx_patch0_func, 328, 1, 1 },
-	{ aic7xxx_patch5_func, 333, 1, 1 },
-	{ aic7xxx_patch11_func, 375, 15, 1 },
-	{ aic7xxx_patch1_func, 427, 7, 2 },
-	{ aic7xxx_patch0_func, 434, 8, 1 },
-	{ aic7xxx_patch1_func, 443, 4, 2 },
-	{ aic7xxx_patch0_func, 447, 6, 1 },
-	{ aic7xxx_patch1_func, 453, 4, 2 },
-	{ aic7xxx_patch0_func, 457, 3, 1 },
-	{ aic7xxx_patch10_func, 467, 10, 1 },
-	{ aic7xxx_patch1_func, 486, 17, 4 },
-	{ aic7xxx_patch9_func, 494, 4, 2 },
-	{ aic7xxx_patch0_func, 498, 2, 1 },
-	{ aic7xxx_patch0_func, 503, 33, 1 },
-	{ aic7xxx_patch10_func, 536, 4, 1 },
-	{ aic7xxx_patch5_func, 540, 2, 1 },
-	{ aic7xxx_patch5_func, 543, 9, 1 },
-
-};
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/atp870u.c linux.19p18/drivers/scsi/atp870u.c
--- linux.vanilla/drivers/scsi/atp870u.c	Mon Dec 11 22:12:53 2000
+++ linux.19p18/drivers/scsi/atp870u.c	Thu Dec 21 10:54:32 2000
@@ -10,6 +10,7 @@
  *		   support atp876 chip
  *		   enable 32 bit fifo transfer
  *		   support cdrom & remove device run ultra speed
+ *		   fix disconnect bug  2000/12/21
  */
 
 #include <linux/module.h>
@@ -76,6 +77,7 @@
 		unsigned char dirctu;
 		unsigned char devspu;
 		unsigned char devtypeu;
+		unsigned char devlcmdu;
 		unsigned long prdaddru;
 		unsigned long tran_lenu;
 		unsigned long last_lenu;
@@ -143,14 +145,6 @@
 		tmport -= 0x08;
 
 		i = inb(tmport);
-		if ((j & 0x40) == 0)
-		{
-			if ((dev->last_cmd & 0x40) == 0)
-			{
-				dev->last_cmd = 0xff;
-			}
-		}
-		else dev->last_cmd |= 0x40;
 
 		tmport -= 0x02;
 		target_id = inb(tmport);
@@ -166,8 +160,21 @@
 			target_id &= 0x07;
 		}
 
+		if ((j & 0x40) != 0)
+		{
+		     if (dev->last_cmd == 0xff)
+		     {
+			dev->last_cmd = target_id;
+		     }
+		     dev->last_cmd |= 0x40;
+		}
+
 		if (i == 0x85)
 		{
+			if ((dev->last_cmd & 0xf0) != 0x40)
+			{
+			   dev->last_cmd = 0xff;
+			}
 			/*
 			 *	Flip wide
 			 */
@@ -196,6 +203,10 @@
 		}
 		if (i == 0x21)
 		{
+			if ((dev->last_cmd & 0xf0) != 0x40)
+			{
+			   dev->last_cmd = 0xff;
+			}
 			tmport -= 0x05;
 			adrcntu = 0;
 			((unsigned char *) &adrcntu)[2] = inb(tmport++);
@@ -221,6 +232,10 @@
 				tmport += 0x0d;
 				lun = inb(tmport) & 0x07;
 			} else {
+				if ((dev->last_cmd & 0xf0) != 0x40)
+				{
+				   dev->last_cmd = 0xff;
+				}
 				if (j == 0x41)
 				{
 					tmport += 0x02;
@@ -251,6 +266,10 @@
 					return;
 				}
 			}
+			if (dev->last_cmd != 0xff)
+			{
+			   dev->last_cmd |= 0x40;
+			}
 			tmport = workportu + 0x10;
 			outb(0x45, tmport);
 			tmport += 0x06;
@@ -371,12 +390,20 @@
 		workrequ = dev->id[target_id].curr_req;
 
 		if (i == 0x42) {
+			if ((dev->last_cmd & 0xf0) != 0x40)
+			{
+			   dev->last_cmd = 0xff;
+			}
 			errstus = 0x02;
 			workrequ->result = errstus;
 			goto go_42;
 		}
 		if (i == 0x16)
 		{
+			if ((dev->last_cmd & 0xf0) != 0x40)
+			{
+			   dev->last_cmd = 0xff;
+			}
 			errstus = 0;
 			tmport -= 0x08;
 			errstus = inb(tmport);
@@ -387,13 +414,13 @@
 			 */
 			spin_lock_irqsave(&io_request_lock, flags);
 			(*workrequ->scsi_done) (workrequ);
-			spin_unlock_irqrestore(&io_request_lock, flags);
 
 			/*
 			 *	Clear it off the queue
 			 */
 			dev->id[target_id].curr_req = 0;
 			dev->working--;
+			spin_unlock_irqrestore(&io_request_lock, flags);
 			/*
 			 *	Take it back wide
 			 */
@@ -411,11 +438,15 @@
 			if (((dev->last_cmd != 0xff) || (dev->quhdu != dev->quendu)) &&
 			    (dev->in_snd == 0))
 			{
-				send_s870(h);
+			   send_s870(h);
 			}
 			dev->in_int = 0;
 			return;
 		}
+		if ((dev->last_cmd & 0xf0) != 0x40)
+		{
+		   dev->last_cmd = 0xff;
+		}
 		if (i == 0x4f) {
 			i = 0x89;
 		}
@@ -480,7 +511,7 @@
 
 int atp870u_queuecommand(Scsi_Cmnd * req_p, void (*done) (Scsi_Cmnd *))
 {
-	unsigned char i, h;
+	unsigned char h;
 	unsigned long flags;
 	unsigned short int m;
 	unsigned int tmport;
@@ -522,6 +553,8 @@
 	/*
 	 *	Count new command
 	 */
+	save_flags(flags);
+	cli();
 	dev->quendu++;
 	if (dev->quendu >= qcnt) {
 		dev->quendu = 0;
@@ -529,18 +562,17 @@
 	/*
 	 *	Check queue state
 	 */
-wait_que_empty:
 	if (dev->quhdu == dev->quendu) {
-		goto wait_que_empty;
+		if (dev->quendu == 0) {
+			dev->quendu = qcnt;
+		}
+		dev->quendu--;
+		req_p->result = 0x00020000;
+		done(req_p);
+		restore_flags(flags);
+		return 0;
 	}
-	save_flags(flags);
-	cli();
 	dev->querequ[dev->quendu] = req_p;
-	if (dev->quendu == 0) {
-		i = qcnt - 1;
-	} else {
-		i = dev->quendu - 1;
-	}
 	tmport = dev->ioport + 0x1c;
 	restore_flags(flags);
 	if ((inb(tmport) == 0) && (dev->in_int == 0) && (dev->in_snd == 0)) {
@@ -593,6 +625,12 @@
 		   return ;
 		}
 	}
+	if ((dev->last_cmd != 0xff) && (dev->working != 0))
+	{
+	     dev->in_snd = 0;
+	     restore_flags(flags);
+	     return ;
+	}
 	dev->working++;
 	j = dev->quhdu;
 	dev->quhdu++;
@@ -626,6 +664,7 @@
 	restore_flags(flags);
 	return;
 oktosend:
+	dev->id[workrequ->target].devlcmdu=0;
 	memcpy(&dev->ata_cdbu[0], &workrequ->cmnd[0], workrequ->cmd_len);
 	if (dev->ata_cdbu[0] == READ_CAPACITY) {
 		if (workrequ->request_bufflen > 8) {
@@ -635,15 +674,6 @@
 	if (dev->ata_cdbu[0] == 0x00) {
 		workrequ->request_bufflen = 0;
 	}
-	/*
-	 *	Why limit this ????
-	 */
-	if (dev->ata_cdbu[0] == INQUIRY) {
-		if (workrequ->request_bufflen > 0x24) {
-			workrequ->request_bufflen = 0x24;
-			dev->ata_cdbu[4] = 0x24;
-		}
-	}
 
 	tmport = workportu + 0x1b;
 	j = 0;
@@ -735,6 +765,7 @@
 		} else {
 			dev->last_cmd |= 0x40;
 		}
+		dev->id[target_id].devlcmdu=dev->last_cmd;
 		dev->in_snd = 0;
 		restore_flags(flags);
 		return;
@@ -809,6 +840,7 @@
 		} else {
 			dev->last_cmd |= 0x40;
 		}
+		dev->id[target_id].devlcmdu=dev->last_cmd;
 		dev->in_snd = 0;
 		restore_flags(flags);
 		return;
@@ -821,6 +853,7 @@
 	} else {
 		dev->last_cmd |= 0x40;
 	}
+	dev->id[target_id].devlcmdu=dev->last_cmd;
 	dev->in_snd = 0;
 	restore_flags(flags);
 	return;
@@ -1751,7 +1784,7 @@
 		if (chip_ver[h] > 0x07) 	  /* check if atp876 chip   */
 		{				  /* then enable terminator */
 		   tmport = base_io + 0x3e;
-		   outb(0x30, tmport);
+		   outb(0x00, tmport);
 		}
 
 		tmport = base_io + 0x3a;
@@ -1812,7 +1845,8 @@
 
 int atp870u_abort(Scsi_Cmnd * SCpnt)
 {
-	unsigned char h, j;
+	unsigned char h, j, k;
+	Scsi_Cmnd *workrequ;
 	unsigned int tmport;
 	struct atp_unit *dev;
 	for (h = 0; h <= admaxu; h++) {
@@ -1839,12 +1873,27 @@
 	printk(" r22=%2x", inb(tmport));
 	tmport += 0x18;
 	printk(" r3a=%2x \n",inb(tmport));
+	for(j=0;j<16;j++)
+	{
+	   if (dev->id[j].curr_req != NULL)
+	   {
+		workrequ = dev->id[j].curr_req;
+		printk("\n que cdb= ");
+		for (k=0; k < workrequ->cmd_len; k++)
+		{
+		    printk(" %2x ",workrequ->cmnd[k]);
+		}
+		printk(" last_lenu= %x ",dev->id[j].last_lenu);
+		printk(" dev_lcmd= %x ",dev->id[j].devlcmdu);
+	   }
+	}
 	return (SCSI_ABORT_SNOOZE);
 }
 
 int atp870u_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
 {
 	unsigned char h;
+	struct atp_unit *dev;
 	/*
 	 * See if a bus reset was suggested.
 	 */
@@ -1855,6 +1904,7 @@
 	}
 	panic("Reset bus host not found !");
 find_host:
+	dev=&atp_unit[h];
 /*	SCpnt->result = 0x00080000;
 	SCpnt->scsi_done(SCpnt);
 	dev->working=0;
@@ -1868,7 +1918,7 @@
 {
 	static char buffer[128];
 
-	strcpy(buffer, "ACARD AEC-6710/6712 PCI Ultra/W SCSI-3 Adapter Driver V2.1+ac ");
+	strcpy(buffer, "ACARD AEC-6710/6712 PCI Ultra/W SCSI-3 Adapter Driver V2.3+ac ");
 
 	return buffer;
 }
@@ -1913,7 +1963,7 @@
 	if (offset == 0) {
 		memset(buff, 0, sizeof(buff));
 	}
-	size += sprintf(BLS, "ACARD AEC-671X Driver Version: 2.1+ac\n");
+	size += sprintf(BLS, "ACARD AEC-671X Driver Version: 2.3+ac\n");
 	len += size;
 	pos = begin + len;
 	size = 0;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/dc390.h linux.19p18/drivers/scsi/dc390.h
--- linux.vanilla/drivers/scsi/dc390.h	Wed May  3 22:31:20 2000
+++ linux.19p18/drivers/scsi/dc390.h	Sat Mar 10 23:19:10 2001
@@ -4,9 +4,7 @@
  *	Description: Device Driver for Tekram DC-390(T) PCI SCSI       *
  *		     Bus Master Host Adapter			       *
  ***********************************************************************/
-/* $Id: dc390.h,v 2.12 1998/12/25 17:33:27 garloff Exp $ */
-
-#include <linux/version.h>
+/* $Id: dc390.h,v 2.43.2.22 2000/12/20 00:39:36 garloff Exp $ */
 
 /*
  * DC390/AMD 53C974 driver, header file
@@ -15,12 +13,27 @@
 #ifndef DC390_H
 #define DC390_H
 
+#include <linux/version.h>
+#ifndef KERNEL_VERSION
+# define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+#endif
+
 #define DC390_BANNER "Tekram DC390/AM53C974"
-#define DC390_VERSION "2.0d 1998/12/25"
+#define DC390_VERSION "2.0f 2000-12-20"
 
-#if defined(HOSTS_C) || defined(MODULE)
+/* We don't have eh_abort_handler, eh_device_reset_handler, 
+ * eh_bus_reset_handler, eh_host_reset_handler yet! 
+ * So long: Use old exception handling :-( */
+#define OLD_EH
 
-#include <scsi/scsicam.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION (2,1,70) || defined (OLD_EH)
+# define NEW_EH
+#else
+# define NEW_EH use_new_eh_code: 1,
+# define USE_NEW_EH
+#endif
+
+#if defined(HOSTS_C) || defined(MODULE) || LINUX_VERSION_CODE > KERNEL_VERSION(2,3,99)
 
 extern int DC390_detect(Scsi_Host_Template *psht);
 extern int DC390_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *));
@@ -34,9 +47,29 @@
 # define DC390_release NULL
 #endif
 
-extern struct proc_dir_entry DC390_proc_scsi_tmscsim;
 extern int DC390_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout);
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,30)
+#define DC390_T    {					\
+   proc_name:      "tmscsim",                           \
+   proc_info:      DC390_proc_info,			\
+   name:           DC390_BANNER " V" DC390_VERSION,	\
+   detect:         DC390_detect,			\
+   release:        DC390_release,			\
+   queuecommand:   DC390_queue_command,			\
+   abort:          DC390_abort,				\
+   reset:          DC390_reset,				\
+   bios_param:     DC390_bios_param,			\
+   can_queue:      42,					\
+   this_id:        7,					\
+   sg_tablesize:   SG_ALL,				\
+   cmd_per_lun:    16,					\
+   NEW_EH						\
+   unchecked_isa_dma: 0,				\
+   use_clustering: DISABLE_CLUSTERING			\
+   }
+#else
+extern struct proc_dir_entry DC390_proc_scsi_tmscsim;
 #define DC390_T    {					\
    proc_dir:       &DC390_proc_scsi_tmscsim,		\
    proc_info:      DC390_proc_info,			\
@@ -47,13 +80,15 @@
    abort:          DC390_abort,				\
    reset:          DC390_reset,				\
    bios_param:     DC390_bios_param,			\
-   can_queue:      17,					\
+   can_queue:      42,					\
    this_id:        7,					\
    sg_tablesize:   SG_ALL,				\
-   cmd_per_lun:    8,					\
+   cmd_per_lun:    16,					\
+   NEW_EH						\
+   unchecked_isa_dma: 0,				\
    use_clustering: DISABLE_CLUSTERING			\
    }
-
+#endif
 #endif /* defined(HOSTS_C) || defined(MODULE) */
 
 #endif /* DC390_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/gdth.c linux.19p18/drivers/scsi/gdth.c
--- linux.vanilla/drivers/scsi/gdth.c	Mon Dec 11 22:12:54 2000
+++ linux.19p18/drivers/scsi/gdth.c	Tue Jan  9 12:14:00 2001
@@ -20,9 +20,19 @@
  * along with this kernel; if not, write to the Free Software           *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            *
  *                                                                      *
- * Tested with Linux 1.2.13, ..., 2.2.16, ..., 2.4.0-test4              *
+ * Tested with Linux 1.2.13, ..., 2.2.16, ..., 2.4.0-test10             *
  *                                                                      *
  * $Log: gdth.c,v $
+ * Revision 1.45  2000/11/16 12:02:24  achim
+ * Changes for kernel 2.4
+ *
+ * Revision 1.44  2000/10/11 08:44:10  achim
+ * Clustering changes: New flag media_changed added
+ *
+ * Revision 1.43  2000/09/20 12:59:01  achim
+ * DPMEM remap functions for all PCI controller types implemented
+ * Small changes for ia64 platform
+ *
  * Revision 1.42  2000/07/20 09:04:50  achim
  * Small changes for kernel 2.4
  *
@@ -180,7 +190,7 @@
  * Initial revision
  *
  ************************************************************************/
-#ident "$Id: gdth.c,v 1.42 2000/07/20 09:04:50 achim Exp $" 
+#ident "$Id: gdth.c,v 1.45 2000/11/16 12:02:24 achim Exp $" 
 
 /* All GDT Disk Array Controllers are fully supported by this driver.
  * This includes the PCI/EISA/ISA SCSI Disk Array Controllers and the
@@ -1111,8 +1121,51 @@
             printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
             return 0;
         }
+        /* check and reset interface area */
         dp6_ptr = (gdt6_dpram_str *)ha->brd;
-        /* reset interface area */
+        gdth_writel(DPMEM_MAGIC, &dp6_ptr->u);
+        if (gdth_readl(&dp6_ptr->u) != DPMEM_MAGIC) {
+            printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", 
+                   pcistr->dpmem);
+            found = FALSE;
+            for (i = 0xC8000; i < 0xE8000; i += 0x4000) {
+                gdth_munmap(ha->brd);
+                ha->brd = gdth_mmap(i, sizeof(ushort)); 
+                if (ha->brd == NULL) {
+                    printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
+                    return 0;
+                }
+                if (gdth_readw(ha->brd) != 0xffff) {
+                    TRACE2(("init_pci_old() address 0x%x busy\n", i));
+                    continue;
+                }
+                gdth_munmap(ha->brd);
+#if LINUX_VERSION_CODE >= 0x2015C
+                pci_write_config_dword(pcistr->pdev, 
+                                       PCI_BASE_ADDRESS_0, i);
+#else
+                pcibios_write_config_dword(pcistr->bus, pcistr->device_fn,
+                                           PCI_BASE_ADDRESS_0, i);
+#endif
+                ha->brd = gdth_mmap(i, sizeof(gdt6_dpram_str)); 
+                if (ha->brd == NULL) {
+                    printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
+                    return 0;
+                }
+                dp6_ptr = (gdt6_dpram_str *)ha->brd;
+                gdth_writel(DPMEM_MAGIC, &dp6_ptr->u);
+                if (gdth_readl(&dp6_ptr->u) == DPMEM_MAGIC) {
+                    printk("GDT-PCI: Use free address at 0x%x\n", i);
+                    found = TRUE;
+                    break;
+                }
+            }   
+            if (!found) {
+                printk("GDT-PCI: No free address found!\n");
+                gdth_munmap(ha->brd);
+                return 0;
+            }
+        }
         memset_io((char *)&dp6_ptr->u,0,sizeof(dp6_ptr->u));
         if (gdth_readl(&dp6_ptr->u) != 0) {
             printk("GDT-PCI: Initialization error (DPMEM write error)\n");
@@ -1181,8 +1234,51 @@
             gdth_munmap(ha->brd);
             return 0;
         }
+        /* check and reset interface area */
         dp6c_ptr = (gdt6c_dpram_str *)ha->brd;
-        /* reset interface area */
+        gdth_writel(DPMEM_MAGIC, &dp6c_ptr->u);
+        if (gdth_readl(&dp6c_ptr->u) != DPMEM_MAGIC) {
+            printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", 
+                   pcistr->dpmem);
+            found = FALSE;
+            for (i = 0xC8000; i < 0xE8000; i += 0x4000) {
+                gdth_munmap(ha->brd);
+                ha->brd = gdth_mmap(i, sizeof(ushort)); 
+                if (ha->brd == NULL) {
+                    printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
+                    return 0;
+                }
+                if (gdth_readw(ha->brd) != 0xffff) {
+                    TRACE2(("init_pci_plx() address 0x%x busy\n", i));
+                    continue;
+                }
+                gdth_munmap(ha->brd);
+#if LINUX_VERSION_CODE >= 0x2015C
+                pci_write_config_dword(pcistr->pdev, 
+                                       PCI_BASE_ADDRESS_2, i);
+#else
+                pcibios_write_config_dword(pcistr->bus, pcistr->device_fn,
+                                           PCI_BASE_ADDRESS_2, i);
+#endif
+                ha->brd = gdth_mmap(i, sizeof(gdt6c_dpram_str)); 
+                if (ha->brd == NULL) {
+                    printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
+                    return 0;
+                }
+                dp6c_ptr = (gdt6c_dpram_str *)ha->brd;
+                gdth_writel(DPMEM_MAGIC, &dp6c_ptr->u);
+                if (gdth_readl(&dp6c_ptr->u) == DPMEM_MAGIC) {
+                    printk("GDT-PCI: Use free address at 0x%x\n", i);
+                    found = TRUE;
+                    break;
+                }
+            }   
+            if (!found) {
+                printk("GDT-PCI: No free address found!\n");
+                gdth_munmap(ha->brd);
+                return 0;
+            }
+        }
         memset_io((char *)&dp6c_ptr->u,0,sizeof(dp6c_ptr->u));
         if (gdth_readl(&dp6c_ptr->u) != 0) {
             printk("GDT-PCI: Initialization error (DPMEM write error)\n");
@@ -1741,6 +1837,7 @@
     register gdth_ha_str *ha;
     ushort cdev_cnt, i;
     ulong32 bus_no, drv_cnt, drv_no, j;
+    unsigned long flags;
     gdth_getch_str *chn;
     gdth_drlist_str *drl;
     gdth_iochan_str *ioc;
@@ -1765,6 +1862,7 @@
 #ifdef GDTH_RTC
     /* read realtime clock info, send to controller */
     /* 1. wait for the falling edge of update flag */
+    spin_lock_irqsave(&rtc_lock, flags)
     for (j = 0; j < 1000000; ++j)
         if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
             break;
@@ -1776,6 +1874,7 @@
         for (j = 0; j < 12; ++j) 
             rtc[j] = CMOS_READ(j);
     } while (rtc[0] != CMOS_READ(0));
+    spin_unlock_irqrestore(&rtc_lock, flags);
     TRACE2(("gdth_search_drives(): RTC: %x/%x/%x\n",*(ulong32 *)&rtc[0],
             *(ulong32 *)&rtc[4], *(ulong32 *)&rtc[8]));
     /* 3. send to controller firmware */
@@ -1966,7 +2065,6 @@
     TRACE2(("gdth_search_drives(): RAWSERVICE initialized\n"));
 
     /* set/get features raw service (scatter/gather) */
-    ha->raw_feat = 0;
     if (gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_SET_FEAT,SCATTER_GATHER,
                           0,0)) {
         TRACE2(("gdth_search_drives(): set features RAWSERVICE OK\n"));
@@ -2061,18 +2159,14 @@
         TRACE2(("gdth_search_dr() cache drive %d cluster info %d\n",
                 hdrive,ha->info));
         ha->hdr[hdrive].cluster_type = (unchar)ha->info;
-    } else {
-        ha->hdr[hdrive].cluster_type = 0;
-    }           
+    }
 
     /* R/W attributes */
     if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_RW_ATTRIBS,hdrive,0,0)) {
         TRACE2(("gdth_search_dr() cache drive %d r/w attrib. %d\n",
                 hdrive,ha->info));
         ha->hdr[hdrive].rw_attribs = (unchar)ha->info;
-    } else {
-        ha->hdr[hdrive].rw_attribs = 0;
-    }           
+    }
 
     return 1;
 }
@@ -2264,10 +2358,14 @@
             TRACE2(("Command 0x%x to bus %d id %d lun %d -> IGNORE\n",
                     nscp->cmnd[0], b, t, nscp->lun));
             nscp->result = DID_BAD_TARGET << 16;
-            GDTH_UNLOCK_HA(ha,flags);
-            /* io_request_lock already active ! */      
-            nscp->scsi_done(nscp);
-            GDTH_LOCK_HA(ha,flags);
+	    if (!nscp->SCp.have_data_in)
+		nscp->SCp.have_data_in++;
+	    else {
+		GDTH_UNLOCK_HA(ha,flags);
+		/* io_request_lock already active ! */      
+		nscp->scsi_done(nscp);
+		GDTH_LOCK_HA(ha,flags);
+	    }
         } else {
             switch (nscp->cmnd[0]) {
               case TEST_UNIT_READY:
@@ -2280,7 +2378,24 @@
                 TRACE(("cache cmd %x/%x/%x/%x/%x/%x\n",nscp->cmnd[0],
                        nscp->cmnd[1],nscp->cmnd[2],nscp->cmnd[3],
                        nscp->cmnd[4],nscp->cmnd[5]));
-                if (gdth_internal_cache_cmd(hanum,nscp)) {
+                if (ha->hdr[t].media_changed && nscp->cmnd[0] != INQUIRY) {
+                    /* return UNIT_ATTENTION */
+                    TRACE2(("cmd 0x%x target %d: UNIT_ATTENTION\n",
+                             nscp->cmnd[0], t));
+                    ha->hdr[t].media_changed = FALSE;
+                    memset((char*)nscp->sense_buffer,0,16);
+                    nscp->sense_buffer[0] = 0x70;
+                    nscp->sense_buffer[2] = UNIT_ATTENTION;
+                    nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+                    if (!nscp->SCp.have_data_in)
+                        nscp->SCp.have_data_in++;
+                    else {
+                        GDTH_UNLOCK_HA(ha,flags);
+                        /* io_request_lock already active ! */      
+                        nscp->scsi_done(nscp);
+                        GDTH_LOCK_HA(ha,flags);
+                    }
+		} else if (gdth_internal_cache_cmd(hanum,nscp)) {
                     GDTH_UNLOCK_HA(ha,flags);
                     /* io_request_lock already active ! */      
                     nscp->scsi_done(nscp);
@@ -2325,7 +2440,24 @@
               case WRITE_6:
               case READ_10:
               case WRITE_10:
-                if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t)))
+                if (ha->hdr[t].media_changed) {
+                    /* return UNIT_ATTENTION */
+                    TRACE2(("cmd 0x%x target %d: UNIT_ATTENTION\n",
+                             nscp->cmnd[0], t));
+                    ha->hdr[t].media_changed = FALSE;
+                    memset((char*)nscp->sense_buffer,0,16);
+                    nscp->sense_buffer[0] = 0x70;
+                    nscp->sense_buffer[2] = UNIT_ATTENTION;
+                    nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+                    if (!nscp->SCp.have_data_in)
+                        nscp->SCp.have_data_in++;
+                    else {
+                        GDTH_UNLOCK_HA(ha,flags);
+                        /* io_request_lock already active ! */      
+                        nscp->scsi_done(nscp);
+                        GDTH_LOCK_HA(ha,flags);
+                    }
+		} else if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t)))
                     this_cmd = FALSE;
                 break;
 
@@ -2471,6 +2603,7 @@
         TRACE2(("Internal cache cmd 0x%x unknown\n",scp->cmnd[0]));
         break;
     }
+
     scp->result = DID_OK << 16;
     scp->sense_buffer[0] = 0;
 
@@ -2487,7 +2620,8 @@
     register gdth_ha_str *ha;
     register gdth_cmd_str *cmdp;
     struct scatterlist *sl;
-    ushort i;
+    ushort i, cnt;
+    ulong32 no;
     int cmd_index, read_write;
 
     ha = HADATA(gdth_ctr_tab[hanum]);
@@ -2543,11 +2677,13 @@
 
     if (read_write) {
         if (scp->cmd_len != 6) {
-            cmdp->u.cache.BlockNo = ntohl(*(ulong32*)&scp->cmnd[2]);
-            cmdp->u.cache.BlockCnt= (ulong32)ntohs(*(ushort*)&scp->cmnd[7]);
+            memcpy(&no, &scp->cmnd[2], sizeof(ulong32));
+            cmdp->u.cache.BlockNo = ntohl(no);
+            memcpy(&cnt, &scp->cmnd[7], sizeof(ushort));
+            cmdp->u.cache.BlockCnt = (ulong32)ntohs(cnt);
         } else {
-            cmdp->u.cache.BlockNo = 
-                ntohl(*(ulong32*)&scp->cmnd[0]) & 0x001fffffUL;
+            memcpy(&no, &scp->cmnd[0], sizeof(ulong32));
+            cmdp->u.cache.BlockNo = ntohl(no) & 0x001fffffUL;
             cmdp->u.cache.BlockCnt= scp->cmnd[4]==0 ? 0x100 : scp->cmnd[4];
         }
 
@@ -2660,7 +2796,7 @@
         cmdp->u.raw.lun        = l;
         cmdp->u.raw.bus        = b;
         cmdp->u.raw.priority   = 0;
-        cmdp->u.raw.link_p     = NULL;
+        cmdp->u.raw.link_p     = 0;
         cmdp->u.raw.sdlen      = scp->request_bufflen;
         cmdp->u.raw.sense_len  = 16;
         cmdp->u.raw.sense_data = virt_to_bus(scp->sense_buffer);
@@ -2825,6 +2961,7 @@
         e->first_stamp = e->last_stamp = tv.tv_sec;
         e->same_count = 1;
         e->event_data = *evt;
+        e->application = 0;
     }
     return e;
 }
@@ -3195,36 +3332,28 @@
                     if (!(ha->hdr[scp->target].cluster_type & 
                         CLUSTER_MOUNTED)) {
                         /* NOT MOUNTED -> MOUNT */
-                        if (!(ha->hdr[scp->target].cluster_type & 
-                            CLUSTER_RESERVED)) {
-                            /* cluster drive NOT RESERVED */
-                            scp->SCp.Status = GDT_MOUNT;
-                        } else {
+                        scp->SCp.Status = GDT_MOUNT;
+                        if (ha->hdr[scp->target].cluster_type & 
+                            CLUSTER_RESERVED) {
                             /* cluster drive RESERVED (on the other node) */
-                            scp->SCp.Status = GDT_MOUNT;
                             scp->SCp.phase = -2;      /* reservation conflict */
                         }
                     } else {
                         scp->SCp.Status = -1;
                     }
-                    /* retry */
-                    scp->SCp.this_residual = HIGH_PRI;
-                    return 2;
-                } else if (scp->SCp.Status == GDT_MOUNT) {
-                    ha->hdr[scp->target].cluster_type |= CLUSTER_MOUNTED;
-                    scp->SCp.Status = -1;
-                    /* return UNIT_ATTENTION */
-                    memset((char*)scp->sense_buffer,0,16);
-                    scp->sense_buffer[0] = 0x70;
-                    scp->sense_buffer[2] = UNIT_ATTENTION;
-                    scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
-                    scp->SCp.Message = (int)(ha->info<<16|S_BSY);
-                } else {
+		} else {
+                    if (scp->SCp.Status == GDT_MOUNT) {
+                        ha->hdr[scp->target].cluster_type |= CLUSTER_MOUNTED;
+                        ha->hdr[scp->target].media_changed = TRUE;
+                    } else if (scp->SCp.Status == GDT_UNMOUNT) {
+                        ha->hdr[scp->target].cluster_type &= ~CLUSTER_MOUNTED;
+                        ha->hdr[scp->target].media_changed = TRUE;
+                    } 
                     scp->SCp.Status = -1;
-                    /* retry */
-                    scp->SCp.this_residual = HIGH_PRI;
-                    return 2;
                 }
+                /* retry */
+                scp->SCp.this_residual = HIGH_PRI;
+                return 2;
             } else {
                 /* RESERVE/RELEASE ? */
                 if (scp->cmnd[0] == RESERVE) {
@@ -3259,12 +3388,6 @@
                 scp->sense_buffer[0] = 0x70;
                 scp->sense_buffer[2] = NOT_READY;
                 scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
-            } else if (scp->cmnd[0] == RESERVE ||
-                       scp->cmnd[0] == RELEASE) {
-                memset((char*)scp->sense_buffer,0,16);
-                scp->sense_buffer[0] = 0x70;
-                scp->sense_buffer[2] = NOT_READY;
-                scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
             } else if (service == CACHESERVICE) {
                 if (ha->status == S_CACHE_UNKNOWN &&
                     (ha->hdr[scp->target].cluster_type & 
@@ -3293,7 +3416,7 @@
                 }
             } else {
                 /* sense buffer filled from controller firmware (DMA) */
-                if (ha->status!=S_RAW_SCSI || ha->info>=0x100) {
+                if (ha->status != S_RAW_SCSI || ha->info >= 0x100) {
                     scp->result = DID_BAD_TARGET << 16;
                 } else {
                     scp->result = (DID_OK << 16) | ha->info;
@@ -4467,8 +4590,12 @@
     }
 }
 
-
+#if LINUX_VERSION_CODE < 0x020400
 #ifdef MODULE
+Scsi_Host_Template driver_template = GDTH;
+#include "scsi_module.c"
+#endif
+#else
 Scsi_Host_Template driver_template = GDTH;
 #include "scsi_module.c"
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/gdth.h linux.19p18/drivers/scsi/gdth.h
--- linux.vanilla/drivers/scsi/gdth.h	Mon Dec 11 22:12:54 2000
+++ linux.19p18/drivers/scsi/gdth.h	Sat Mar 10 23:19:10 2001
@@ -10,7 +10,7 @@
  *
  * <achim@vortex.de>
  *
- * $Id: gdth.h,v 1.33 2000/07/24 09:29:25 achim Exp $
+ * $Id: gdth.h,v 1.35 2000/10/11 08:42:38 achim Exp $
  */
 
 #include <linux/version.h>
@@ -29,9 +29,9 @@
 /* defines, macros */
 
 /* driver version */
-#define GDTH_VERSION_STR        "1.23"
+#define GDTH_VERSION_STR        "1.25"
 #define GDTH_VERSION            1
-#define GDTH_SUBVERSION         23
+#define GDTH_SUBVERSION         25
 
 /* protocol version */
 #define PROTOCOL_VERSION        1
@@ -625,7 +625,7 @@
             unchar      priority;               /* only 0 used */
             ulong32     sense_len;              /* sense data length */
             ulong32     sense_data;             /* sense data addr. */
-            struct raw  *link_p;                /* linked cmds (not supp.) */
+            ulong32     link_p;                 /* linked cmds (not supp.) */
             ulong32     sg_ranz;                /* s/g element count */
             gdth_sg_str sg_lst[GDTH_MAXSG];     /* s/g list */
         } PACKED raw;                           /* raw service cmd. struct. */
@@ -877,7 +877,7 @@
     Scsi_Cmnd           *req_first;             /* top of request queue */
     struct {
         unchar          present;                /* Flag: host drive present? */
-        unchar          is_logdrv;              /* Flag: logical drive (master)? */
+        unchar          is_logdrv;              /* Flag: log. drive (master)? */
         unchar          is_arraydrv;            /* Flag: array drive? */
         unchar          is_master;              /* Flag: array drive master? */
         unchar          is_parity;              /* Flag: parity drive? */
@@ -891,7 +891,7 @@
         unchar          ldr_no;                 /* log. drive no. */
         unchar          rw_attribs;             /* r/w attributes */
         unchar          cluster_type;           /* cluster properties */
-        unchar          reserved;
+        unchar          media_changed;          /* Flag:MOUNT/UNMOUNT occured */
         ulong32         start_sec;              /* start sector */
     } hdr[MAX_LDRIVES];                         /* host drives */
     struct {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/gdth_ioctl.h linux.19p18/drivers/scsi/gdth_ioctl.h
--- linux.vanilla/drivers/scsi/gdth_ioctl.h	Mon Dec 11 22:12:54 2000
+++ linux.19p18/drivers/scsi/gdth_ioctl.h	Thu Nov 16 12:03:24 2000
@@ -2,7 +2,7 @@
 #define _GDTH_IOCTL_H
 
 /* gdth_ioctl.h
- * $Id: gdth_ioctl.h,v 1.6 2000/07/24 09:29:43 achim Exp $
+ * $Id: gdth_ioctl.h,v 1.7 2000/10/11 08:43:35 achim Exp $
  */
 
 /* IOCTLs */
@@ -19,6 +19,7 @@
 #define GDTIOCTL_SCSI       (GDTIOCTL_MASK | 9) /* SCSI command */
 #define GDTIOCTL_RESET_BUS  (GDTIOCTL_MASK |10) /* reset SCSI bus */
 #define GDTIOCTL_RESCAN     (GDTIOCTL_MASK |11) /* rescan host drives */
+#define GDTIOCTL_RESET_DRV  (GDTIOCTL_MASK |12) /* reset (remote) drv. res. */
 
 #define GDTIOCTL_MAGIC      0xaffe0003UL
 #define EVENT_SIZE          294 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/gdth_proc.c linux.19p18/drivers/scsi/gdth_proc.c
--- linux.vanilla/drivers/scsi/gdth_proc.c	Mon Dec 11 22:12:54 2000
+++ linux.19p18/drivers/scsi/gdth_proc.c	Thu Nov 16 12:03:24 2000
@@ -1,5 +1,5 @@
 /* gdth_proc.c 
- * $Id: gdth_proc.c,v 1.22 2000/07/24 09:30:28 achim Exp $
+ * $Id: gdth_proc.c,v 1.23 2000/10/11 08:43:11 achim Exp $
  */
 
 #include "gdth_ioctl.h"
@@ -524,6 +524,30 @@
             gdth_analyse_hdrive(hanum, k);
         gdth_polling = FALSE;
         GDTH_UNLOCK_HA(ha, flags);
+        break;
+
+      case GDTIOCTL_RESET_DRV:
+        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) ))
+            return(-EBUSY);
+        piord = (gdth_iord_str *)ha->pscratch;
+        piord->size = sizeof(gdth_iord_str);
+        piord->status = S_OK;
+        i = piowr->iu.scsi.target;
+        if (ha->hdr[i].present) {
+            gdtcmd.BoardNode = LOCALBOARD;
+            gdtcmd.Service = CACHESERVICE;
+            gdtcmd.OpCode = GDT_CLUST_RESET;
+            gdtcmd.u.cache.DeviceNo = i;
+            gdtcmd.u.cache.BlockNo = 0;
+            gdtcmd.u.cache.sg_canz = 0;
+#if LINUX_VERSION_CODE >= 0x020322
+            gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+            piord->status = (ulong32)scp->SCp.Message;
+#else
+            gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+            piord->status = (ulong32)scp.SCp.Message;
+#endif
+        }
         break;
 
       default:
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/hosts.c linux.19p18/drivers/scsi/hosts.c
--- linux.vanilla/drivers/scsi/hosts.c	Mon Dec 11 22:12:54 2000
+++ linux.19p18/drivers/scsi/hosts.c	Mon Feb 12 14:57:23 2001
@@ -136,7 +136,7 @@
 #endif
 
 #ifdef CONFIG_SCSI_AIC7XXX
-#include "aic7xxx.h"
+#include "aic7xxx/aic7xxx.h"
 #endif
 
 #ifdef CONFIG_SCSI_IPS
@@ -897,6 +897,9 @@
 #endif
 #ifdef CONFIG_CHR_DEV_ST
     scsi_register_device(&st_template);
+#endif
+#ifdef CONFIG_CHR_DEV_OSST
+    scsi_register_device(&osst_template);
 #endif
 #ifdef CONFIG_CHR_DEV_SG
     scsi_register_device(&sg_template);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/hosts.h linux.19p18/drivers/scsi/hosts.h
--- linux.vanilla/drivers/scsi/hosts.h	Sun Jun 11 21:44:15 2000
+++ linux.19p18/drivers/scsi/hosts.h	Sat Mar  3 22:43:56 2001
@@ -458,6 +458,7 @@
 
 extern struct Scsi_Device_Template sd_template;
 extern struct Scsi_Device_Template st_template;
+extern struct Scsi_Device_Template osst_template;
 extern struct Scsi_Device_Template sr_template;
 extern struct Scsi_Device_Template sg_template;
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/i60uscsi.c linux.19p18/drivers/scsi/i60uscsi.c
--- linux.vanilla/drivers/scsi/i60uscsi.c	Fri Apr 21 12:46:28 2000
+++ linux.19p18/drivers/scsi/i60uscsi.c	Wed Dec 13 21:25:35 2000
@@ -765,10 +765,10 @@
 		if (inia100_adpt[i].ADPT_BIOS < wBIOS)
 			continue;
 		if (inia100_adpt[i].ADPT_BIOS == wBIOS) {
-			if (inia100_adpt[i].ADPT_BASE == wBASE)
+			if (inia100_adpt[i].ADPT_BASE == wBASE) {
 				if (inia100_adpt[i].ADPT_Bus != 0xFF)
 					return (FAILURE);
-				else if (inia100_adpt[i].ADPT_BASE < wBASE)
+			} else if (inia100_adpt[i].ADPT_BASE < wBASE)
 					continue;
 		}
 		for (j = MAX_SUPPORTED_ADAPTERS - 1; j > i; j--) {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/i60uscsi.h linux.19p18/drivers/scsi/i60uscsi.h
--- linux.vanilla/drivers/scsi/i60uscsi.h	Fri Apr 21 12:46:28 2000
+++ linux.19p18/drivers/scsi/i60uscsi.h	Sun Feb 25 23:16:33 2001
@@ -78,6 +78,14 @@
 #define U32     unsigned long
 #endif
 
+#ifndef VIRT_TO_BUS
+#define VIRT_TO_BUS(x)           (unsigned long)virt_to_bus((void *) x)
+#endif
+
+#ifndef VIRT_TO_BUS
+#define VIRT_TO_BUS(x)           (unsigned int)virt_to_bus((void *) x)
+#endif
+
 #ifndef NULL
 #define NULL     0		/* zero          */
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/osst.c linux.19p18/drivers/scsi/osst.c
--- linux.vanilla/drivers/scsi/osst.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/scsi/osst.c	Sat Dec 30 19:50:25 2000
@@ -0,0 +1,5184 @@
+/*
+  SCSI Tape Driver for Linux version 1.1 and newer. See the accompanying
+  file README.st for more information.
+
+  History:
+
+  OnStream SCSI Tape support (osst) cloned from st.c by
+  Willem Riede (osst@riede.org) Feb 2000
+  Fixes ... Kurt Garloff <garloff@suse.de> Mar 2000
+
+  Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara.
+  Contribution and ideas from several people including (in alphabetical
+  order) Klaus Ehrenfried, Wolfgang Denk, Steve Hirsch, Andreas Koppenh"ofer,
+  Michael Leodolter, Eyal Lebedinsky, J"org Weule, and Eric Youngdale.
+
+  Copyright 1992 - 2000 Kai Makisara
+		 email Kai.Makisara@metla.fi
+
+  $Header: /home/cvsroot/Driver/osst.c,v 1.28.2.12.2.1 2000/12/15 20:36:12 garloff Exp $
+
+  Last modified: Wed Feb  2 22:04:05 2000 by makisara@kai.makisara.local
+  Some small formal changes - aeb, 950809
+*/
+
+static const char * cvsid = "$Id: osst.c,v 1.28.2.12.2.1 2000/12/15 20:36:12 garloff Exp $";
+const char * osst_version = "0.8.6.1";
+
+/* The "failure to reconnect" firmware bug */
+#define OSST_FW_NEED_POLL_MIN 10602 /*(107A)*/
+#define OSST_FW_NEED_POLL_MAX 10708 /*(108D)*/
+#define OSST_FW_NEED_POLL(x,d) ((x) >= OSST_FW_NEED_POLL_MIN && (x) <= OSST_FW_NEED_POLL_MAX && d->host->this_id != 7)
+
+#include <linux/module.h>
+
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/mtio.h>
+#include <linux/ioctl.h>
+#include <linux/fcntl.h>
+#include <asm/uaccess.h>
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/spinlock.h>
+
+/* The driver prints some debugging information on the console if DEBUG
+   is defined and non-zero. */
+#define DEBUG 0
+
+/* The message level for the debug messages is currently set to KERN_NOTICE
+   so that people can easily see the messages. Later when the debugging messages
+   in the drivers are more widely classified, this may be changed to KERN_DEBUG. */
+#define OSST_DEB_MSG  KERN_NOTICE
+
+#define MAJOR_NR OSST_MAJOR
+#include <linux/blk.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include <scsi/scsi_ioctl.h>
+
+#define ST_KILOBYTE 1024
+
+#include "st.h"
+#include "osst.h"
+#include "osst_options.h"
+#include "osst_detect.h"
+
+#include "constants.h"
+
+#ifdef MODULE
+MODULE_PARM(buffer_kbs, "i");
+MODULE_PARM(write_threshold_kbs, "i");
+MODULE_PARM(max_buffers, "i");
+MODULE_PARM(max_sg_segs, "i");
+static int buffer_kbs = 0;
+static int write_threshold_kbs = 0;
+static int max_buffers = 0;
+static int max_sg_segs = 0;
+#endif
+
+/* Some default definitions have been moved to osst_options.h */
+#define OSST_BUFFER_SIZE (OSST_BUFFER_BLOCKS * ST_KILOBYTE)
+#define OSST_WRITE_THRESHOLD (OSST_WRITE_THRESHOLD_BLOCKS * ST_KILOBYTE)
+
+/* The buffer size should fit into the 24 bits for length in the
+   6-byte SCSI read and write commands. */
+#if OSST_BUFFER_SIZE >= (2 << 24 - 1)
+#error "Buffer size should not exceed (2 << 24 - 1) bytes!"
+#endif
+
+#if DEBUG
+static int debugging = 1;
+#endif
+
+#define MAX_RETRIES 0
+#define MAX_WRITE_RETRIES 0
+#define MAX_READY_RETRIES 5
+#define NO_TAPE  NOT_READY
+
+#define OSST_TIMEOUT (200 * HZ)
+#define OSST_LONG_TIMEOUT (1800 * HZ)
+
+#define TAPE_NR(x) (MINOR(x) & ~(128 | ST_MODE_MASK))
+#define TAPE_MODE(x) ((MINOR(x) & ST_MODE_MASK) >> ST_MODE_SHIFT)
+
+/* Internal ioctl to set both density (uppermost 8 bits) and blocksize (lower
+   24 bits) */
+#define SET_DENS_AND_BLK 0x10001
+
+static int osst_nbr_buffers;
+static OSST_buffer **osst_buffers;
+static int osst_buffer_size     = OSST_BUFFER_SIZE;
+static int osst_write_threshold = OSST_WRITE_THRESHOLD;
+static int osst_max_buffers     = OSST_MAX_BUFFERS;
+static int osst_max_sg_segs     = OSST_MAX_SG;
+
+static OS_Scsi_Tape ** os_scsi_tapes = NULL;
+
+static int modes_defined = FALSE;
+
+static OSST_buffer *new_tape_buffer(int, int);
+static int enlarge_buffer(OSST_buffer *, int, int);
+static void normalize_buffer(OSST_buffer *);
+static int append_to_buffer(const char *, OSST_buffer *, int);
+static int from_buffer(OSST_buffer *, char *, int);
+static int osst_zero_buffer_tail(OSST_buffer *);
+static int osst_copy_to_buffer(OSST_buffer *, unsigned char *);
+static int osst_copy_from_buffer(OSST_buffer *, unsigned char *);
+
+static int osst_init(void);
+static int osst_attach(Scsi_Device *);
+static int osst_detect(Scsi_Device *);
+static void osst_detach(Scsi_Device *);
+
+struct Scsi_Device_Template osst_template = {NULL, "OnStream tape", "osst", NULL, TYPE_TAPE,
+					     OSST_MAJOR, 0, 0, 0, 0,
+					     osst_detect, osst_init,
+					     NULL, osst_attach, osst_detach};
+
+static int osst_int_ioctl(OS_Scsi_Tape *STp, Scsi_Cmnd ** aSCpnt, unsigned int cmd_in,unsigned long arg);
+
+static int osst_set_frame_position(OS_Scsi_Tape *STp, Scsi_Cmnd ** aSCpnt, int frame, int skip);
+
+static int osst_get_frame_position(OS_Scsi_Tape *STp, Scsi_Cmnd ** aSCpnt);
+
+static int osst_flush_write_buffer(OS_Scsi_Tape *STp, Scsi_Cmnd ** aSCpnt, int file_blk);
+
+static int osst_write_error_recovery(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int pending);
+
+
+/* Routines that handle the interaction with mid-layer SCSI routines */
+
+/* Convert the result to success code */
+static int osst_chk_result(Scsi_Cmnd * SCpnt)
+{
+  int dev = TAPE_NR(SCpnt->request.rq_dev);
+  int result = SCpnt->result;
+  unsigned char * sense = SCpnt->sense_buffer, scode;
+#if DEBUG
+  const char *stp;
+#endif
+
+  if (!result /* && SCpnt->sense_buffer[0] == 0 */ )
+    return 0;
+
+  if (driver_byte(result) & DRIVER_SENSE)
+      scode = sense[2] & 0x0f;
+  else {
+      sense[0] = 0;    /* We don't have sense data if this byte is zero */
+      scode = 0;
+      if ((sense[2] & 0x0f) == 1)
+	return 0;			/* FIXME -- is this safe? */
+  }
+
+#if DEBUG
+  if (debugging) {
+    printk(OSST_DEB_MSG "osst%d: Error: %x, cmd: %x %x %x %x %x %x Len: %d\n",
+	   dev, result,
+	   SCpnt->data_cmnd[0], SCpnt->data_cmnd[1], SCpnt->data_cmnd[2],
+	   SCpnt->data_cmnd[3], SCpnt->data_cmnd[4], SCpnt->data_cmnd[5],
+	   SCpnt->request_bufflen);
+    if (driver_byte(result) & DRIVER_SENSE)
+      print_sense("osst", SCpnt);
+  }
+  else
+#endif
+  if (!(driver_byte(result) & DRIVER_SENSE) ||
+      ((sense[0] & 0x70) == 0x70 &&
+       scode != NO_SENSE &&
+       scode != RECOVERED_ERROR &&
+/*       scode != UNIT_ATTENTION && */
+       scode != BLANK_CHECK &&
+       scode != VOLUME_OVERFLOW &&
+       SCpnt->data_cmnd[0] != MODE_SENSE &&
+       SCpnt->data_cmnd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */
+    if (driver_byte(result) & DRIVER_SENSE) {
+      printk(KERN_WARNING "osst%d: Error with sense data: ", dev);
+      print_sense("osst", SCpnt);
+    }
+    else
+      printk(KERN_WARNING
+	     "osst%d: Error %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n",
+	     dev, result, suggestion(result), driver_byte(result),
+	     host_byte(result));
+  }
+
+  if ((sense[0] & 0x70) == 0x70 &&
+      scode == RECOVERED_ERROR
+      ) {
+    os_scsi_tapes[dev]->recover_count++;
+    os_scsi_tapes[dev]->recover_erreg++;
+#if DEBUG
+    if (debugging) {
+      if (SCpnt->data_cmnd[0] == READ_6)
+	stp = "read";
+      else if (SCpnt->data_cmnd[0] == WRITE_6)
+	stp = "write";
+      else
+	stp = "ioctl";
+      printk(OSST_DEB_MSG "osst%d: Recovered %s error (%d).\n", dev, stp,
+	     os_scsi_tapes[dev]->recover_count);
+    }
+#endif
+    if ((sense[2] & 0xe0) == 0)
+      return 0;
+  }
+  return (-EIO);
+}
+
+
+/* Wakeup from interrupt */
+static void osst_sleep_done (Scsi_Cmnd * SCpnt)
+{
+  unsigned int st_nbr;
+  int remainder;
+  OS_Scsi_Tape * STp;
+
+  if ((st_nbr = TAPE_NR(SCpnt->request.rq_dev)) < osst_template.nr_dev) {
+    STp = os_scsi_tapes[st_nbr];
+    if ((STp->buffer)->writing &&
+	(SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
+	(SCpnt->sense_buffer[2] & 0x40)) {
+      /* EOM at write-behind, has all been written? */
+      if ((SCpnt->sense_buffer[0] & 0x80) != 0)
+	remainder = (SCpnt->sense_buffer[3] << 24) |
+	      (SCpnt->sense_buffer[4] << 16) |
+		(SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6];
+      else
+	remainder = 0;
+      if ((SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW ||
+	  remainder > 0)
+	(STp->buffer)->last_result = SCpnt->result; /* Error */
+      else
+	(STp->buffer)->last_result = INT_MAX; /* OK */
+    }
+    else
+      (STp->buffer)->last_result = SCpnt->result;
+    SCpnt->request.rq_status = RQ_SCSI_DONE;
+    (STp->buffer)->last_SCpnt = SCpnt;
+
+#if DEBUG
+    STp->write_pending = 0;
+#endif
+    up(SCpnt->request.sem);
+  }
+#if DEBUG
+  else if (debugging)
+    printk(KERN_ERR "osst?: Illegal interrupt device %x\n", st_nbr);
+#endif
+}
+
+
+/* Do the scsi command. Waits until command performed if do_wait is true.
+   Otherwise osst_write_behind_check() is used to check that the command
+   has finished. */
+static Scsi_Cmnd * osst_do_scsi(Scsi_Cmnd *SCpnt, OS_Scsi_Tape *STp, 
+	 unsigned char *cmd, int bytes, int timeout, int retries, int do_wait)
+{
+  unsigned long flags;
+  unsigned char *bp;
+//static int inject = 0; /* FIXME - take out inject occasional read errors */
+//static int repeat = 0;
+  spin_lock_irqsave(&io_request_lock, flags);
+  if (SCpnt == NULL)
+    if ((SCpnt = scsi_allocate_device(NULL, STp->device, 1)) == NULL) {
+      printk(KERN_ERR "osst%d: Can't get SCSI request.\n", TAPE_NR(STp->devt));
+      spin_unlock_irqrestore(&io_request_lock, flags);
+      return NULL;
+    }
+
+  cmd[1] |= (SCpnt->lun << 5) & 0xe0;
+  STp->sem = MUTEX_LOCKED;
+  SCpnt->use_sg = (bytes > (STp->buffer)->sg[0].length) ?
+      (STp->buffer)->use_sg : 0;
+  if (SCpnt->use_sg) {
+      bp = (char *)&((STp->buffer)->sg[0]);
+      if ((STp->buffer)->sg_segs < SCpnt->use_sg)
+	  SCpnt->use_sg = (STp->buffer)->sg_segs;
+  }
+  else
+      bp = (STp->buffer)->b_data;
+  SCpnt->cmd_len = 0;
+  SCpnt->request.sem = &(STp->sem);
+  SCpnt->request.rq_status = RQ_SCSI_BUSY;
+  SCpnt->request.rq_dev = STp->devt;
+
+  scsi_do_cmd(SCpnt, (void *)cmd, bp, bytes,
+	      osst_sleep_done, timeout, retries);
+  spin_unlock_irqrestore(&io_request_lock, flags);
+
+  if (do_wait) {
+      down(SCpnt->request.sem);
+
+      (STp->buffer)->last_result_fatal = osst_chk_result(SCpnt);
+//if ((STp->buffer)->last_result_fatal == 0 &&
+//    cmd[0] == READ_6 && cmd[4] && ( /* (++ inject % 83) == 29  || */
+//     (STp->first_frame_position == 240 /* or STp->read_error_frame to fail again on the block calculated above */ && ++repeat < 3))) {
+//	printk(OSST_DEB_MSG "osst%d: injecting read error\n", TAPE_NR(STp->devt));
+//	STp->buffer->last_result_fatal = 1; /* FIXME - take out inject occasional read errors */
+//}
+  }
+
+  return SCpnt;
+}
+
+
+/* Handle the write-behind checking (downs the semaphore) */
+static void osst_write_behind_check(OS_Scsi_Tape *STp)
+{
+  OSST_buffer * STbuffer;
+  ST_partstat * STps;
+
+  STbuffer = STp->buffer;
+
+#if DEBUG
+  if (STp->write_pending)
+    STp->nbr_waits++;
+  else
+    STp->nbr_finished++;
+#endif
+
+  down(&(STp->sem));
+
+  (STp->buffer)->last_result_fatal = osst_chk_result((STp->buffer)->last_SCpnt);
+
+  if ((STp->buffer)->last_result_fatal)
+    (STp->buffer)->last_result_fatal =
+        osst_write_error_recovery(STp, &((STp->buffer)->last_SCpnt), 1);
+  else
+    STp->first_frame_position++;
+
+  scsi_release_command((STp->buffer)->last_SCpnt);
+
+  if (STbuffer->writing < STbuffer->buffer_bytes)
+#if 0
+    memcpy(STbuffer->b_data,
+	   STbuffer->b_data + STbuffer->writing,
+	   STbuffer->buffer_bytes - STbuffer->writing);
+#else
+  printk(KERN_WARNING "osst: write_behind_check: something left in buffer!\n");
+#endif
+  STbuffer->buffer_bytes -= STbuffer->writing;
+  STps = &(STp->ps[STp->partition]);
+  if (STps->drv_block >= 0) {
+    if (STp->block_size == 0)
+      STps->drv_block++;
+    else
+      STps->drv_block += STbuffer->writing / STp->block_size;
+  }
+  STbuffer->writing = 0;
+
+  return;
+}
+
+
+
+/* Onstream specific Routines */
+/*
+ * Initialize the OnStream AUX
+ */
+static void osst_init_aux(OS_Scsi_Tape * STp, int frame_type, int logical_blk_num)
+{
+	os_aux_t       *aux = STp->buffer->aux;
+	os_partition_t *par = &aux->partition;
+	os_dat_t       *dat = &aux->dat;
+
+	if (STp->raw) return;
+
+	memset(aux, 0, sizeof(*aux));
+	aux->format_id = htonl(0);
+	memcpy(aux->application_sig, "LIN4", 4);
+	aux->hdwr = htonl(0);
+	aux->frame_type = frame_type;
+
+	switch (frame_type) {
+	  case	OS_FRAME_TYPE_HEADER:
+		aux->update_frame_cntr    = htonl(STp->update_frame_cntr);
+		par->partition_num        = OS_CONFIG_PARTITION;
+		par->par_desc_ver         = OS_PARTITION_VERSION;
+		par->wrt_pass_cntr        = htons(0xffff);
+		/* 0-4 = reserved, 5-9 = header, 2990-2994 = header, 2995-2999 = reserved */
+		par->first_frame_ppos     = htonl(0);
+		par->last_frame_ppos      = htonl(0xbb7);
+		aux->frame_seq_num        = htonl(0);
+		aux->logical_blk_num_high = htonl(0);
+		aux->logical_blk_num      = htonl(0);
+		aux->next_mark_ppos       = htonl(STp->first_mark_ppos);
+		break;
+	  case	OS_FRAME_TYPE_DATA:
+	  case	OS_FRAME_TYPE_MARKER:
+		dat->dat_sz = 8;
+		dat->reserved1 = 0;
+		dat->entry_cnt = 1;
+		dat->reserved3 = 0;
+		dat->dat_list[0].blk_sz   = htonl(frame_type==OS_FRAME_TYPE_DATA?STp->block_size:0);
+		dat->dat_list[0].blk_cnt  = htons(1);
+		dat->dat_list[0].flags    = frame_type==OS_FRAME_TYPE_MARKER?OS_DAT_FLAGS_MARK:OS_DAT_FLAGS_DATA;
+		dat->dat_list[0].reserved = 0;
+	  case	OS_FRAME_TYPE_EOD:
+		aux->update_frame_cntr    = htonl(0);
+		par->partition_num        = OS_DATA_PARTITION;
+		par->par_desc_ver         = OS_PARTITION_VERSION;
+		par->wrt_pass_cntr        = htons(STp->wrt_pass_cntr);
+		par->first_frame_ppos     = htonl(STp->first_data_ppos);
+		par->last_frame_ppos      = htonl(STp->capacity);
+		aux->frame_seq_num        = htonl(logical_blk_num);
+		aux->logical_blk_num_high = htonl(0);
+		aux->logical_blk_num      = htonl(logical_blk_num);
+		break;
+	  default: ; /* probably FILL */
+	}
+	aux->filemark_cnt = ntohl(STp->filemark_cnt);        /* FIXME -- violates ADR spec */
+	aux->phys_fm = ntohl(0xffffffff);
+	aux->last_mark_ppos = ntohl(STp->last_mark_ppos);
+}
+
+/*
+ * Verify that we have the correct tape frame
+ */
+static int osst_verify_frame(OS_Scsi_Tape * STp, int logical_blk_num, int quiet)
+{
+	os_aux_t       * aux  = STp->buffer->aux;
+        os_partition_t * par  = &(aux->partition);
+	ST_partstat    * STps = &(STp->ps[STp->partition]);
+        int              i;
+	int		 dev  = TAPE_NR(STp->devt);
+
+        if (STp->raw) {
+                if (STp->buffer->last_result_fatal) {
+                        for (i=0; i < STp->buffer->sg_segs; i++)
+                                memset(STp->buffer->sg[i].address, 0, STp->buffer->sg[i].length);
+                        strcpy(STp->buffer->b_data, "READ ERROR ON FRAME");
+                }
+                return 1;
+        }
+        if (STp->buffer->last_result_fatal) {
+                printk(KERN_INFO "osst%d: Skipping frame, read error\n", dev);
+                return 0;
+        }
+        if (ntohl(aux->format_id) != 0) {
+                printk(KERN_INFO "osst%d: Skipping frame, format_id %u\n", dev, ntohl(aux->format_id));
+                return 0;
+        }
+        if (memcmp(aux->application_sig, STp->application_sig, 4) != 0 &&
+	    (memcmp(aux->application_sig, "LIN3", 4) != 0 || STp->linux_media_version != 4)) {
+                printk(KERN_INFO "osst%d: Skipping frame, incorrect application signature\n", dev);
+                return 0;
+        }
+        if (par->partition_num != OS_DATA_PARTITION) {
+                if (!STp->linux_media || STp->linux_media_version != 2) {
+                        printk(KERN_INFO "osst%d: Skipping frame, partition num %d\n", dev, par->partition_num);              		    return 0;
+                }
+        }
+        if (par->par_desc_ver != OS_PARTITION_VERSION) {
+                printk(KERN_INFO "osst%d: Skipping frame, partition version %d\n", dev, par->par_desc_ver);
+                return 0;
+        }
+        if (ntohs(par->wrt_pass_cntr) != STp->wrt_pass_cntr) {
+                printk(KERN_INFO "osst%d: Skipping frame, wrt_pass_cntr %d (expected %d)\n", 
+				 dev, ntohs(par->wrt_pass_cntr), STp->wrt_pass_cntr);
+                return 0;
+        }
+        if (aux->frame_seq_num != aux->logical_blk_num) {
+                printk(KERN_INFO "osst%d: Skipping frame, seq != logical\n", dev);
+                return 0;
+        }
+        if (aux->frame_type != OS_FRAME_TYPE_DATA &&
+            aux->frame_type != OS_FRAME_TYPE_EOD &&
+            aux->frame_type != OS_FRAME_TYPE_MARKER) {
+                if (!quiet)
+			printk(KERN_INFO "osst%d: Skipping frame, frame type %x\n", dev, aux->frame_type);
+                return 0;
+        }
+        if (aux->frame_type == OS_FRAME_TYPE_EOD &&
+	    STp->first_frame_position < STp->eod_frame_ppos) {
+                printk(KERN_INFO "osst%d: skipping premature EOD frame %d\n", dev, STp->first_frame_position);
+                return 0;
+	}
+	STp->logical_blk_in_buffer = 1;
+
+        if (logical_blk_num != -1 && ntohl(aux->logical_blk_num) != logical_blk_num) {
+                if (!quiet)
+                        printk(KERN_INFO "osst%d: Skipping frame, logical_blk_num %u (expected %d)\n", 
+					 dev, ntohl(aux->logical_blk_num), logical_blk_num);
+                return 0;
+        }
+        if (aux->frame_type == OS_FRAME_TYPE_MARKER) {
+                STps->eof = ST_FM_HIT;
+
+		i = ntohl(aux->filemark_cnt);
+		if (STp->header_cache != NULL && i < OS_FM_TAB_MAX && (i > STp->filemark_cnt ||
+		    STp->first_frame_position - 1 != ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i]))) {
+#if 1 //DEBUG
+			printk(OSST_DEB_MSG "osst%i: %s filemark %d at frame %d\n", dev,
+				  STp->header_cache->dat_fm_tab.fm_tab_ent[i] == 0?"Learned":"Corrected",
+				  i, STp->first_frame_position - 1);
+#endif
+			STp->header_cache->dat_fm_tab.fm_tab_ent[i] = htonl(STp->first_frame_position - 1);
+			if (i >= STp->filemark_cnt)
+				 STp->filemark_cnt = i+1;
+		}
+        }
+        if (aux->frame_type == OS_FRAME_TYPE_EOD) {
+                STps->eof = ST_EOD_1;
+        }
+        if (aux->frame_type == OS_FRAME_TYPE_DATA) {
+                STps->eof = ST_NOEOF;
+        }
+        return 1;
+}
+
+/*
+ * Wait for the unit to become Ready
+ */
+static int osst_wait_ready(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, unsigned timeout)
+{
+	unsigned char	cmd[MAX_COMMAND_SIZE];
+        Scsi_Cmnd     * SCpnt;
+	long		startwait = jiffies;
+#if DEBUG
+	int		dbg = debugging;
+	int		dev  = TAPE_NR(STp->devt);
+
+	printk(OSST_DEB_MSG "osst%d: reached onstream wait ready\n", dev);
+#endif
+
+	memset(cmd, 0, MAX_COMMAND_SIZE);
+	cmd[0] = TEST_UNIT_READY;
+
+	SCpnt = osst_do_scsi(*aSCpnt, STp, cmd, 0, STp->timeout, MAX_READY_RETRIES, TRUE);
+        *aSCpnt = SCpnt;
+	if (!SCpnt) return (-EBUSY);
+
+	while ( SCpnt->sense_buffer[2] == 2 && SCpnt->sense_buffer[12] == 4 &&
+		( SCpnt->sense_buffer[13] == 1 || SCpnt->sense_buffer[13] == 8 ) && 
+		time_before(jiffies, startwait + timeout*HZ) ) {
+#if DEBUG
+	    if (debugging) {
+		printk(OSST_DEB_MSG "osst%d: Sleeping in onstream wait ready\n", dev);
+		printk(OSST_DEB_MSG "osst%d: Turning off debugging for a while\n", dev);
+		debugging = 0;
+	    }
+#endif
+	    current->state = TASK_INTERRUPTIBLE;
+	    schedule_timeout(HZ / 10);
+
+	    memset(cmd, 0, MAX_COMMAND_SIZE);
+	    cmd[0] = TEST_UNIT_READY;
+
+	    SCpnt = osst_do_scsi(SCpnt, STp, cmd, 0, STp->timeout, MAX_READY_RETRIES, TRUE);
+	}
+        *aSCpnt = SCpnt;
+#if DEBUG
+	debugging = dbg;
+#endif
+	if ( SCpnt->sense_buffer[2] &&
+	     osst_write_error_recovery(STp, aSCpnt, 0) ) {
+#if DEBUG
+	    printk(OSST_DEB_MSG "osst%d: Abnormal exit from onstream wait ready\n", dev);
+#endif
+	    return (-EIO);
+	}
+#if DEBUG
+	printk(OSST_DEB_MSG "osst%d: Normal exit from onstream wait ready\n", dev);
+#endif
+	return 0;
+}
+
+static int osst_position_tape_and_confirm(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int frame)
+{
+	int           retval;
+
+	osst_wait_ready(STp, aSCpnt, 15 * 60);			/* TODO - can this catch a write error? */
+	retval = osst_set_frame_position(STp, aSCpnt, frame, 0);
+	if (retval) return (retval);
+	osst_wait_ready(STp, aSCpnt, 15 * 60);
+	return (osst_get_frame_position(STp, aSCpnt));
+}
+
+/*
+ * Wait for write(s) to complete
+ */
+static int osst_flush_drive_buffer(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt)
+{
+	unsigned char	cmd[MAX_COMMAND_SIZE];
+        Scsi_Cmnd     * SCpnt;
+
+	int             result = 0;
+#if DEBUG
+	int		dev  = TAPE_NR(STp->devt);
+
+	printk(OSST_DEB_MSG "osst%d: Reached onstream flush drive buffer (write filemark)\n", dev);
+#endif
+
+	memset(cmd, 0, MAX_COMMAND_SIZE);
+	cmd[0] = WRITE_FILEMARKS;
+	cmd[1] = 1;
+
+	SCpnt = osst_do_scsi(*aSCpnt, STp, cmd, 0, STp->timeout, MAX_WRITE_RETRIES, TRUE);
+        *aSCpnt = SCpnt;
+	if (!SCpnt) return (-EBUSY);
+
+	if ((STp->buffer)->last_result_fatal)
+		result = osst_write_error_recovery(STp, aSCpnt, 0);
+
+	result |= osst_wait_ready(STp, aSCpnt, 5 * 60);
+	STp->ps[STp->partition].rw = ST_IDLE;
+	return (result);
+}
+/*
+static int osst_buffer_stats[64];
+
+static void osst_build_stats(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt)
+{
+	unsigned int i;
+
+	osst_get_frame_position (STp, aSCpnt);
+	i = STp->cur_frames > 63 ? 63 : STp->cur_frames;
+	osst_buffer_stats[i]++;
+}
+
+static void osst_report_stats()
+{
+	unsigned int i;
+
+	for (i=0; i<64; i+=8) {
+		printk(OSST_DEB_MSG "osst buffer stats %2d: %5d %5d %5d %5d %5d %5d %5d %5d\n", i,
+			osst_buffer_stats[i  ], osst_buffer_stats[i+1],
+		       	osst_buffer_stats[i+2], osst_buffer_stats[i+3], 
+			osst_buffer_stats[i+4], osst_buffer_stats[i+5],
+		       	osst_buffer_stats[i+6], osst_buffer_stats[i+7]);
+	}
+
+}
+*/
+#define OSST_POLL_PER_SEC 10
+static int osst_wait_frame(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int curr, int minlast, int to)
+{
+	long        startwait = jiffies;
+	int         dev       = TAPE_NR(STp->devt);
+#if DEBUG
+	char    notyetprinted = 1;
+#endif
+	if (minlast >= 0 && STp->ps[STp->partition].rw != ST_READING)
+		printk(KERN_ERR "osst%i: waiting for frame without having initialized read!\n", dev);
+
+	while (time_before (jiffies, startwait + to*HZ))
+	{ 
+		int result;
+		result = osst_get_frame_position (STp, aSCpnt);
+		if (result == -EIO)
+			if ((result = osst_write_error_recovery(STp, aSCpnt, 0)) == 0)
+				return 0;	/* successfull recovery leaves drive ready for frame */
+		if (result < 0) break;
+		if (STp->first_frame_position == curr &&
+		    ((minlast < 0 &&
+		      (signed)STp->last_frame_position > (signed)curr + minlast) ||
+		     (minlast >= 0 && STp->cur_frames > minlast)
+		    ) && result >= 0)
+		{
+#if DEBUG			
+			if (jiffies - startwait >= 2*HZ/OSST_POLL_PER_SEC)
+				printk ("osst%i: Succ wait f fr %i (>%i): %i-%i %i (%i): %3li.%li s\n",
+					dev, curr, curr+minlast, STp->first_frame_position,
+					STp->last_frame_position, STp->cur_frames,
+					result, (jiffies-startwait)/HZ, 
+					(((jiffies-startwait)%HZ)*10)/HZ);
+#endif
+			return 0;
+		}
+#if DEBUG
+		if (jiffies - startwait >= 2*HZ/OSST_POLL_PER_SEC && notyetprinted)
+		{
+			printk ("osst%i: Wait for frame %i (>%i): %i-%i %i (%i)\n",
+				dev, curr, curr+minlast, STp->first_frame_position,
+				STp->last_frame_position, STp->cur_frames, result);
+			notyetprinted--;
+		}
+#endif
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout (HZ / OSST_POLL_PER_SEC);
+	}
+#if DEBUG
+	printk ("osst%i: Fail wait f fr %i (>%i): %i-%i %i: %3li.%li s\n",
+		dev, curr, curr+minlast, STp->first_frame_position,
+		STp->last_frame_position, STp->cur_frames,
+		(jiffies-startwait)/HZ, (((jiffies-startwait)%HZ)*10)/HZ);
+#endif	
+	return -EBUSY;
+}
+
+/*
+ * Read the next OnStream tape block at the current location
+ */
+static int osst_read_block(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int timeout)
+{
+	unsigned char	cmd[MAX_COMMAND_SIZE];
+	Scsi_Cmnd     * SCpnt;
+	int		retval = 0;
+#if DEBUG
+	os_aux_t      * aux    = STp->buffer->aux;
+	int		dev    = TAPE_NR(STp->devt);
+#endif
+
+	/* TODO: Error handling */
+	if (STp->poll)
+		retval = osst_wait_frame (STp, aSCpnt, STp->first_frame_position, 0, timeout);
+#if 0// DEBUG
+	printk ("osst_read: wait for frame returned %i\n", retval);
+#endif
+	
+	memset(cmd, 0, MAX_COMMAND_SIZE);
+	cmd[0] = READ_6;
+	cmd[1] = 1;
+	cmd[4] = 1;
+
+#if DEBUG
+	if (debugging)
+	    printk(OSST_DEB_MSG "osst%i: Reading block from OnStream tape\n", dev);
+#endif
+	SCpnt = osst_do_scsi(*aSCpnt, STp, cmd, OS_FRAME_SIZE, STp->timeout, MAX_RETRIES, TRUE);
+	*aSCpnt = SCpnt;
+        if (!SCpnt)
+	    return (-EBUSY);
+
+	if ((STp->buffer)->last_result_fatal) {
+	    retval = 1;
+	    if (STp->read_error_frame == 0) {
+		STp->read_error_frame = STp->first_frame_position;
+		printk(OSST_DEB_MSG "osst: recording read error at %d\n", STp->read_error_frame);/*FIXME*/
+	    }
+#if DEBUG
+	    if (debugging)
+	        printk(OSST_DEB_MSG "osst%d: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n",
+		   dev,
+		   SCpnt->sense_buffer[0], SCpnt->sense_buffer[1],
+		   SCpnt->sense_buffer[2], SCpnt->sense_buffer[3],
+		   SCpnt->sense_buffer[4], SCpnt->sense_buffer[5],
+		   SCpnt->sense_buffer[6], SCpnt->sense_buffer[7]);
+#endif
+	}
+	else
+	    STp->first_frame_position++;
+#if DEBUG
+	if (debugging) {
+	   printk(OSST_DEB_MSG "osst%i: AUX: %c%c%c%c UpdFrCt#%d %s FrSeq#%d LogBlk#%d\n", dev,
+			aux->application_sig[0], aux->application_sig[1],
+			aux->application_sig[2], aux->application_sig[3], ntohl(aux->update_frame_cntr),
+			aux->frame_type==1?"EOD":aux->frame_type==2?"MARK":
+			aux->frame_type==8?"HEADR":aux->frame_type==0x80?"DATA":"FILL", 
+			ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num) );
+	   if (aux->frame_type==2)
+		printk(OSST_DEB_MSG "osst%i: mark_cnt=%d, last_mark=%d, next_mark=%d\n", dev,
+			ntohl(aux->filemark_cnt), ntohl(aux->last_mark_ppos), ntohl(aux->next_mark_ppos));
+	   printk(OSST_DEB_MSG "osst%i: Exit read block from OnStream tape with code %d\n", dev, retval);
+	}
+#endif
+	return (retval);
+}
+
+static int osst_initiate_read(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt)
+{
+        ST_partstat   * STps   = &(STp->ps[STp->partition]);
+	Scsi_Cmnd     * SCpnt  ;
+	unsigned char	cmd[MAX_COMMAND_SIZE];
+	int		retval = 0;
+#if DEBUG
+	int		dev    = TAPE_NR(STp->devt);
+#endif
+
+        if (STps->rw != ST_READING) {         /* Initialize read operation */
+                if (STps->rw == ST_WRITING) {
+                        osst_flush_write_buffer(STp, aSCpnt, 1);
+			osst_flush_drive_buffer(STp, aSCpnt);
+                }
+                STps->rw = ST_READING;
+		STp->logical_blk_in_buffer = 0;
+
+                /*
+                 *      Issue a read 0 command to get the OnStream drive
+                 *      read blocks into its buffer.
+                 */
+		memset(cmd, 0, MAX_COMMAND_SIZE);
+		cmd[0] = READ_6;
+		cmd[1] = 1;
+
+#if DEBUG
+		printk(OSST_DEB_MSG "osst%i: Start Read Ahead on OnStream tape\n", dev);
+#endif
+		SCpnt   = osst_do_scsi(*aSCpnt, STp, cmd, 0, STp->timeout, MAX_RETRIES, TRUE);
+		*aSCpnt = SCpnt;
+		retval  = STp->buffer->last_result_fatal;
+        }
+
+        return retval;
+}
+
+static int osst_get_logical_blk(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int logical_blk_num, int quiet)
+{
+	ST_partstat * STps  = &(STp->ps[STp->partition]);
+	int           dev   = TAPE_NR(STp->devt);
+        int           cnt   = 0,
+		      bad   = 0,
+		      past  = 0,
+		      x,
+		      position;
+
+        /*
+         * Search and wait for the next logical tape block
+         */
+        while (1) {
+                if (cnt++ > 400) {
+                        printk(KERN_WARNING "osst%d: Couldn't find logical block %d, aborting\n",
+					    dev, logical_blk_num);
+			if (STp->read_error_frame) {
+				osst_set_frame_position(STp, aSCpnt, STp->read_error_frame, 0);
+#if 1 //DEBUG
+                        	printk(OSST_DEB_MSG "osst%d: Repositioning tape to bad block %d\n",
+						 dev, STp->read_error_frame);
+#endif
+				STp->read_error_frame = 0;
+			}
+                        return (-EIO);
+                }
+#if DEBUG
+		if (debugging)
+			printk(OSST_DEB_MSG "osst%d: Looking for block %d, attempt %d\n",
+					  dev, logical_blk_num, cnt);
+#endif
+                if ( osst_initiate_read(STp, aSCpnt)
+                || ( (!STp->logical_blk_in_buffer) && osst_read_block(STp, aSCpnt, 30) ) ) {
+                        position = osst_get_frame_position(STp, aSCpnt);
+			if (position >= 0xbae && position < 0xbb8)
+				position = 0xbb8;
+			else if (position > STp->eod_frame_ppos || ++bad == 10) {
+printk(OSST_DEB_MSG "osst%d: start again from pos %d, eod %d, bad %d\n", dev, position, STp->eod_frame_ppos, bad); /*FIXME*/
+				position = STp->read_error_frame - 1;
+			}
+			else {
+				position += 39;
+                        	cnt += 20;
+			}
+#if 1 //DEBUG
+                        printk(OSST_DEB_MSG "osst%d: Bad block detected, positioning tape to block %d\n",
+					 dev, position);
+#endif
+                        osst_set_frame_position(STp, aSCpnt, position, 0);
+                        continue;
+                }
+                if (osst_verify_frame(STp, logical_blk_num, quiet))
+                        break;
+                if (osst_verify_frame(STp, -1, quiet)) {
+                        x = ntohl(STp->buffer->aux->logical_blk_num);
+			if (STp->fast_open) {
+#if 1 //DEBUG
+				printk(OSST_DEB_MSG "osst%d: Found logical block %d instead of %d after fast open\n",
+					  dev, x, logical_blk_num);
+#endif
+				STp->header_ok = 0;
+				STp->read_error_frame = 0;
+				return (-EIO);
+			}
+                        if (x > logical_blk_num) {
+				if (++past > 3) {
+					/* positioning backwards did not bring us to the desired block */
+					position = STp->read_error_frame - 1;
+				}
+				else
+			        	position = osst_get_frame_position(STp, aSCpnt)
+					         + logical_blk_num - x - 1;
+#if 1 //DEBUG
+                                printk(OSST_DEB_MSG
+				       "osst%d: Found logical block %d while looking for %d: back up %d\n",
+						dev, x, logical_blk_num,
+					       	STp->first_frame_position - position);
+#endif
+                        	osst_set_frame_position(STp, aSCpnt, position, 0);
+                        	cnt += 10;
+                        }
+			else
+				past = 0;
+                }
+                if (osst_get_frame_position(STp, aSCpnt) == 0xbaf) {
+#if DEBUG
+                        printk(OSST_DEB_MSG "osst%d: Skipping config partition\n", dev);
+#endif
+			osst_set_frame_position(STp, aSCpnt, 0xbb8, 0);
+			cnt--;
+		}
+		STp->logical_blk_in_buffer = 0;
+        }
+        if (cnt > 1) {
+		STp->recover_count++;
+		STp->recover_erreg++;
+ 	}
+        STp->logical_blk_num = ntohl(STp->buffer->aux->logical_blk_num);
+
+#if DEBUG
+	if (debugging || STps->eof)
+		printk(OSST_DEB_MSG "osst%i: Exit get logical block (%d=>%d) from OnStream tape with code %d\n",							 dev, logical_blk_num, STp->logical_blk_num, STps->eof);
+#endif
+	STp->fast_open = FALSE;
+	STp->read_error_frame = 0;
+        return (STps->eof);
+}
+
+static int osst_seek_logical_blk(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int logical_blk_num)
+{
+	int  estimate;
+	int  retries = 0;
+	int  dev     = TAPE_NR(STp->devt);
+
+	if (logical_blk_num < 0) logical_blk_num = 0;
+	/* FIXME -- this may not be valid for foreign formats */
+	if (logical_blk_num < 2980) estimate  = logical_blk_num + 10;
+	else			    estimate  = logical_blk_num + 20;
+
+#if DEBUG
+	printk(OSST_DEB_MSG "osst%d: Seeking logical block %d (now at %d)\n",
+			  dev, logical_blk_num, STp->logical_blk_num);
+#endif
+	while (++retries < 10) {
+	   osst_set_frame_position(STp, aSCpnt, estimate, 0);
+	   if (osst_get_logical_blk(STp, aSCpnt, logical_blk_num, 1) >= 0)
+	      return 0;
+	   if (osst_get_logical_blk(STp, aSCpnt, -1, 1) < 0)
+	      goto error;
+	   if (STp->logical_blk_num != logical_blk_num)
+	      estimate += logical_blk_num - STp->logical_blk_num;
+	   else
+	      break;
+	}
+error:
+	printk(KERN_WARNING "osst%d: Couldn't seek to logical block %d (at %d), %d retries\n", 
+			    dev, logical_blk_num, STp->logical_blk_num, retries);
+	return (-EIO);
+}
+
+static int osst_seek_frame(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int frame)
+{
+        ST_partstat   * STps = &(STp->ps[STp->partition]);
+	int		r;
+
+	if (frame < 0 || frame >= STp->capacity) return (-ENXIO);
+
+	if (frame <= STp->first_data_ppos) {
+		STp->logical_blk_num = STps->drv_file = STps->drv_block = 0;
+		return (osst_set_frame_position(STp, aSCpnt, frame, 0));
+	}
+	r = osst_set_frame_position(STp, aSCpnt, frame-1, 0);
+	if (r < 0) return r;
+
+	r = osst_get_logical_blk(STp, aSCpnt, -1, 1);
+	if (r < 0) return r;
+
+	if (osst_get_frame_position(STp, aSCpnt) != frame) return (-EIO);
+
+	STp->logical_blk_num++;
+	STp->logical_blk_in_buffer = 0;
+	STps->drv_file  = htonl(STp->buffer->aux->filemark_cnt);
+	STps->drv_block = -1;
+	STps->eof       = ST_NOEOF; /* FIXME test for eod */
+	return 0;
+}
+
+/*
+ * Read back the drive's internal buffer contents, as a part
+ * of the write error recovery mechanism for old OnStream
+ * firmware revisions.
+ */
+static int osst_read_back_buffer_and_rewrite(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt,
+					unsigned int block, unsigned int skip, int pending)
+{
+	Scsi_Cmnd     * SCpnt = * aSCpnt;
+	unsigned char * buffer, * p;
+	unsigned char	cmd[MAX_COMMAND_SIZE];
+	int             frames, flag, new_block, i, logical_blk_num;
+	int		dev  = TAPE_NR(STp->devt);
+	long		startwait = jiffies;
+#if DEBUG
+	int		dbg = debugging;
+#endif
+
+	frames = STp->cur_frames;
+	if ((buffer = (unsigned char *)vmalloc((frames + pending) * OS_DATA_SIZE)) == NULL)
+		return (-EIO);
+
+	logical_blk_num = STp->logical_blk_num - frames - pending;
+	printk(KERN_INFO "osst%d: Reading back %d frames from drive buffer%s\n",
+			 dev, frames, pending?" and one that was pending":"");
+
+	if (pending) {
+		osst_copy_from_buffer(STp->buffer, (p = &buffer[frames * OS_DATA_SIZE]));
+//		memcpy((p = &buffer[frames * OS_DATA_SIZE]), STp->buffer->b_data, OS_DATA_SIZE);
+#if DEBUG
+		if (debugging)
+			printk(OSST_DEB_MSG "osst%d: Pending logical block %d, data %x %x %x %x\n",
+					  dev, logical_blk_num + frames, p[0], p[1], p[2], p[3]);
+#endif
+	}
+	for (i = 0, p = buffer; i < frames; i++, p += OS_DATA_SIZE) {
+
+		memset(cmd, 0, MAX_COMMAND_SIZE);
+		cmd[0] = 0x3C;		/* Buffer Read           */
+		cmd[1] = 6;		/* Retrieve Faulty Block */
+		cmd[7] = 32768 >> 8;
+		cmd[8] = 32768 & 0xff;
+
+		SCpnt = osst_do_scsi(SCpnt, STp, cmd, OS_FRAME_SIZE, STp->timeout, MAX_RETRIES, TRUE);
+	
+		if ((STp->buffer)->last_result_fatal) {
+			printk(KERN_ERR "osst%d: Failed to read block back from OnStream buffer\n", dev);
+			vfree((void *)buffer);
+			*aSCpnt = SCpnt;
+			return (-EIO);
+		}
+		osst_copy_from_buffer(STp->buffer, p);
+//		memcpy(p, STp->buffer->b_data, OS_DATA_SIZE);
+#if DEBUG
+		if (debugging)
+			printk(OSST_DEB_MSG "osst%d: Read back logical block %d, data %x %x %x %x\n",
+					  dev, logical_blk_num + i, p[0], p[1], p[2], p[3]);
+#endif
+	}
+        *aSCpnt = SCpnt;
+	osst_get_frame_position(STp, aSCpnt);
+
+#if DEBUG
+	printk(OSST_DEB_MSG "osst%d: Frames left in buffer: %d\n", dev, STp->cur_frames);
+#endif
+	/* Write synchronously so we can be sure we're OK again and don't have to recover recursively */
+	/* In the header we don't actually re-write the blocks that fail, just the ones after them */
+
+	for (flag=1, new_block=block, p=buffer, i=0; i < frames + pending; ) {
+
+		if (flag) {
+			if (STp->write_type == OS_WRITE_HEADER) {
+				i += skip;
+				p += skip * OS_DATA_SIZE;
+			}
+			else if (new_block < 2990 && new_block+skip+frames+pending >= 2990)
+				new_block = 3000-i;
+			else
+				new_block += skip;
+#if DEBUG
+			printk(OSST_DEB_MSG "osst%d: Position to frame %d, write lblk %d\n",
+						dev, new_block+i, logical_blk_num+i); /* FIXME var blk sz */
+#endif
+			osst_set_frame_position(STp, aSCpnt, new_block + i, 0);
+			osst_wait_ready(STp, aSCpnt, 60);
+			osst_get_frame_position(STp, aSCpnt);
+			SCpnt = * aSCpnt;
+
+			if (new_block > block + 1000) {
+				printk(KERN_ERR "osst%d: Failed to find valid tape media\n", dev);
+				vfree((void *)buffer);
+				return (-EIO);
+			}
+			flag = 0;
+			if ( i >= frames + pending ) break;
+		}
+		osst_copy_to_buffer(STp->buffer, p);
+//		memcpy(STp->buffer->b_data, p, OS_DATA_SIZE);
+		/*
+		 * IMPORTANT: for error recovery to work, _never_ queue frames with mixed frame type!
+		 */
+		osst_init_aux(STp, STp->buffer->aux->frame_type, logical_blk_num+i );
+		memset(cmd, 0, MAX_COMMAND_SIZE);
+		cmd[0] = WRITE_6;
+		cmd[1] = 1;
+		cmd[4] = 1;
+
+#if DEBUG
+		if (debugging)
+			printk(OSST_DEB_MSG "osst%d: About to attempt to write to frame %d\n", dev, new_block+i);
+#endif
+		SCpnt = osst_do_scsi(SCpnt, STp, cmd, OS_FRAME_SIZE, STp->timeout, MAX_WRITE_RETRIES, TRUE);
+
+		if (STp->buffer->last_result_fatal)
+			flag = 1;
+		else {
+			p += OS_DATA_SIZE; i++;
+
+			/* if we just sent the last frame, wait till all successfully written */
+			if ( i == frames + pending ) {
+#if DEBUG
+				printk(OSST_DEB_MSG "osst%d: Check re-write successful\n", dev);
+#endif
+				memset(cmd, 0, MAX_COMMAND_SIZE);
+				cmd[0] = WRITE_FILEMARKS;
+				cmd[1] = 1;
+				SCpnt = osst_do_scsi(SCpnt, STp, cmd, 0, STp->timeout, MAX_WRITE_RETRIES, TRUE);
+
+#if DEBUG
+				if (debugging) {
+					printk(OSST_DEB_MSG "osst%d: Sleeping in re-write wait ready\n", dev);
+					printk(OSST_DEB_MSG "osst%d: Turning off debugging for a while\n", dev);
+					debugging = 0;
+				}
+#endif
+				flag = STp->buffer->last_result_fatal;
+				while ( !flag && time_before(jiffies, startwait + 60*HZ) ) {
+
+					memset(cmd, 0, MAX_COMMAND_SIZE);
+					cmd[0] = TEST_UNIT_READY;
+
+					SCpnt = osst_do_scsi(SCpnt, STp, cmd, 0, STp->timeout,
+									 MAX_READY_RETRIES, TRUE);
+
+					if (SCpnt->sense_buffer[2] == 2 && SCpnt->sense_buffer[12] == 4 &&
+					    (SCpnt->sense_buffer[13] == 1 || SCpnt->sense_buffer[13] == 8)) {
+						/* in the process of becoming ready */
+						schedule_timeout(HZ / 10);
+						continue;
+					}
+					if (STp->buffer->last_result_fatal)
+						flag = 1;
+					break;
+				}
+#if DEBUG
+				debugging = dbg;
+				printk(OSST_DEB_MSG "osst%d: Wait re-write finished\n", dev);
+#endif
+			}
+		}
+		if (flag) {
+			if ((SCpnt->sense_buffer[ 2] & 0x0f) == 13 &&
+			     SCpnt->sense_buffer[12]         ==  0 &&
+			     SCpnt->sense_buffer[13]         ==  2) {
+				printk(KERN_ERR "osst%d: Volume overflow in write error recovery\n", dev);
+				vfree((void *)buffer);
+				return (-EIO);			/* hit end of tape = fail */
+			}
+			i = ((SCpnt->sense_buffer[3] << 24) |
+	        	     (SCpnt->sense_buffer[4] << 16) |
+			     (SCpnt->sense_buffer[5] <<  8) |
+			      SCpnt->sense_buffer[6]        ) - new_block;
+			p = &buffer[i * OS_DATA_SIZE];
+#if DEBUG
+			printk(OSST_DEB_MSG "osst%d: Additional write error at %d\n", dev, new_block+i);
+#endif
+			osst_get_frame_position(STp, aSCpnt);
+#if DEBUG
+			printk(OSST_DEB_MSG "osst%d: reported frame positions: host = %d, tape = %d\n",
+					  dev, STp->first_frame_position, STp->last_frame_position);
+#endif
+		}
+		*aSCpnt = SCpnt;
+	}    
+	vfree((void *)buffer);
+	return 0;
+}
+
+static int osst_reposition_and_retry(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt,
+					unsigned int block, unsigned int skip, int pending)
+{
+	unsigned char	cmd[MAX_COMMAND_SIZE];
+	Scsi_Cmnd     * SCpnt     = * aSCpnt;
+	int		dev       = TAPE_NR(STp->devt);
+	int		attempts  = 1000 / skip;
+	int		flag      = 1;
+	long		startwait = jiffies;
+#if DEBUG
+	int		dbg       = debugging;
+#endif
+
+	while (attempts && time_before(jiffies, startwait + 60*HZ)) {
+		if (flag) {
+#if DEBUG
+			debugging = dbg;
+#endif
+			if (block < 2990 && block+skip+STp->cur_frames+pending >= 2990)
+				block = 3000-skip;
+#if DEBUG
+			printk(OSST_DEB_MSG "osst%d: Position to frame %d, re-write from lblk %d\n",
+					  dev, block+skip, STp->logical_blk_num-STp->cur_frames-pending);
+#endif
+			osst_set_frame_position(STp, aSCpnt, block + skip, 1);
+			flag = 0;
+			attempts--;
+		}
+		if (osst_get_frame_position(STp, aSCpnt) < 0) {		/* additional write error */
+#if DEBUG
+			printk(OSST_DEB_MSG "osst%d: Addl error, host %d, tape %d, buffer %d\n",
+					  dev, STp->first_frame_position,
+					  STp->last_frame_position, STp->cur_frames);
+#endif
+			block = STp->last_frame_position;
+			flag = 1;
+			continue;
+		}
+		if (pending && STp->cur_frames < 50) {
+
+			memset(cmd, 0, MAX_COMMAND_SIZE);
+			cmd[0] = WRITE_6;
+			cmd[1] = 1;
+			cmd[4] = 1;
+#if DEBUG
+			printk(OSST_DEB_MSG "osst%d: About to write pending lblk %d at frame %d\n",
+					  dev, STp->logical_blk_num-1, STp->first_frame_position);
+#endif
+			SCpnt = osst_do_scsi(SCpnt, STp, cmd, OS_FRAME_SIZE, STp->timeout,
+									MAX_WRITE_RETRIES, TRUE);
+			*aSCpnt = SCpnt;
+
+			if (STp->buffer->last_result_fatal) {		/* additional write error */
+				if ((SCpnt->sense_buffer[ 2] & 0x0f) == 13 &&
+				     SCpnt->sense_buffer[12]         ==  0 &&
+				     SCpnt->sense_buffer[13]         ==  2) {
+					printk(OSST_DEB_MSG
+					       "osst%d: Volume overflow in write error recovery\n",
+					       dev);
+					break;				/* hit end of tape = fail */
+				}
+				flag = 1;
+			}
+			else
+				pending = 0;
+
+			continue;
+		}
+		if (STp->cur_frames == 0) {
+#if DEBUG
+			debugging = dbg;
+			printk(OSST_DEB_MSG "osst%d: Wait re-write finished\n", dev);
+#endif
+			return 0;
+		}
+#if DEBUG
+		if (debugging) {
+			printk(OSST_DEB_MSG "osst%d: Sleeping in re-write wait ready\n", dev);
+			printk(OSST_DEB_MSG "osst%d: Turning off debugging for a while\n", dev);
+			debugging = 0;
+		}
+#endif
+		schedule_timeout(HZ / 10);
+	}
+	printk(KERN_ERR "osst%d: Failed to find valid tape media\n", dev);
+#if DEBUG
+	debugging = dbg;
+#endif
+	return (-EIO);
+}
+
+/*
+ * Error recovery algorithm for the OnStream tape.
+ */
+
+static int osst_write_error_recovery(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int pending)
+{
+	Scsi_Cmnd   * SCpnt  = * aSCpnt;
+	ST_partstat * STps   = & STp->ps[STp->partition];
+	int           dev    = TAPE_NR(STp->devt);
+	int           retval = 0;
+	int           rw_state;
+	unsigned int  block, skip;
+
+	rw_state = STps->rw;
+
+	if ((SCpnt->sense_buffer[ 2] & 0x0f) != 3
+	  || SCpnt->sense_buffer[12]         != 12
+	  || SCpnt->sense_buffer[13]         != 0) {
+#if DEBUG
+		printk(OSST_DEB_MSG "osst%d: Write error recovery cannot handle %02x:%02x:%02x\n",
+			dev, SCpnt->sense_buffer[ 2], SCpnt->sense_buffer[12], SCpnt->sense_buffer[13]);
+#endif
+		return (-EIO);
+	}
+	block =	(SCpnt->sense_buffer[3] << 24) |
+	        (SCpnt->sense_buffer[4] << 16) |
+		(SCpnt->sense_buffer[5] <<  8) |
+		 SCpnt->sense_buffer[6];
+	skip  =  SCpnt->sense_buffer[9];
+ 
+#if DEBUG
+	printk(OSST_DEB_MSG "osst%d: Detected physical bad block at %u, advised to skip %d\n", dev, block, skip);
+#endif
+	osst_get_frame_position(STp, aSCpnt);
+#if DEBUG
+	printk(OSST_DEB_MSG "osst%d: reported frame positions: host = %d, tape = %d\n",
+			dev, STp->first_frame_position, STp->last_frame_position);
+#endif
+	switch (STp->write_type) {
+	   case OS_WRITE_DATA:
+	   case OS_WRITE_EOD:
+	   case OS_WRITE_NEW_MARK:
+		printk(KERN_WARNING "osst%d: Relocating %d buffered logical blocks to physical block %u\n",
+			dev, STp->cur_frames, block + skip);
+		if (STp->os_fw_rev >= 10600)
+			retval = osst_reposition_and_retry(STp, aSCpnt, block, skip, pending);
+		else
+			retval = osst_read_back_buffer_and_rewrite(STp, aSCpnt, block, skip, pending);
+		break;
+	   case OS_WRITE_LAST_MARK:
+		printk(KERN_ERR "osst%d: Bad block in update last marker, fatal\n", dev);
+		osst_set_frame_position(STp, aSCpnt, block + STp->cur_frames + pending, 0);
+		retval = -EIO;
+		break;
+	   case OS_WRITE_HEADER:
+		printk(KERN_WARNING "osst%d: Bad block in header partition, skipped\n", dev);
+		retval = osst_read_back_buffer_and_rewrite(STp, aSCpnt, block, 1, pending);
+		break;
+	   default:
+		printk(KERN_WARNING "osst%d: Bad block in filler, ignored\n", dev);
+		osst_set_frame_position(STp, aSCpnt, block + STp->cur_frames + pending, 0);
+	}
+	osst_get_frame_position(STp, aSCpnt);
+#if DEBUG
+	printk(KERN_ERR "osst%d: Positioning complete, cur_frames %d, pos %d, tape pos %d\n", 
+			dev, STp->cur_frames, STp->first_frame_position, STp->last_frame_position);
+	printk(OSST_DEB_MSG "osst%d: next logical block to write: %d\n", dev, STp->logical_blk_num);
+#endif
+	if (retval == 0) {
+		STp->recover_count++;
+		STp->recover_erreg++;
+	}
+	STps->rw = rw_state;
+	return retval;
+}
+
+static int osst_space_over_filemarks_backward(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int mt_op, int mt_count)
+{
+	int     dev = TAPE_NR(STp->devt);
+	int     cnt;
+	int     last_mark_ppos = -1;
+
+#if DEBUG
+	printk(OSST_DEB_MSG "osst%d: Reached space_over_filemarks_backwards %d %d\n", dev, mt_op, mt_count);
+#endif
+	if (osst_get_logical_blk(STp, aSCpnt, -1, 0) < 0) {
+		printk(KERN_INFO "osst%i: Couldn't get logical blk num in space_filemarks_bwd\n", dev);
+		return -EIO;
+	}
+	if (STp->linux_media_version >= 4) {
+		/*
+		 * direct lookup in header filemark list
+		 */
+		cnt = ntohl(STp->buffer->aux->filemark_cnt);
+		if (STp->header_ok                         && 
+		    STp->header_cache != NULL              &&
+		    (cnt - mt_count)  >= 0                 &&
+		    (cnt - mt_count)   < OS_FM_TAB_MAX     &&
+		    (cnt - mt_count)   < STp->filemark_cnt &&
+		    STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] == STp->buffer->aux->last_mark_ppos)
+
+			last_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt - mt_count]);
+#if 1 //DEBUG
+		if (STp->header_cache == NULL || (cnt - mt_count) < 0 || (cnt - mt_count) >= OS_FM_TAB_MAX)
+			printk(OSST_DEB_MSG "osst%i: Filemark lookup fail due to %s\n", dev,
+			       STp->header_cache == NULL?"lack of header cache":"count out of range");
+		else
+			printk(OSST_DEB_MSG "osst%i: Filemark lookup: prev mark %d (%s), skip %d to %d\n", dev, cnt,
+			       ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
+			        (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] ==
+					 STp->buffer->aux->last_mark_ppos))?"match":"error",
+			       mt_count, last_mark_ppos);
+#endif
+		if (last_mark_ppos > 10 && last_mark_ppos < STp->eod_frame_ppos) {
+			osst_set_frame_position(STp, aSCpnt, last_mark_ppos, 0);
+			if (osst_get_logical_blk(STp, aSCpnt, -1, 0) < 0) {
+				printk(KERN_INFO "osst%i: Couldn't get logical blk num in space_filemarks\n", dev);
+				return (-EIO);
+			}
+			if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
+				printk(KERN_INFO "osst%i: Expected to find marker at block %d, not found\n",
+						 dev, last_mark_ppos);
+				return (-EIO);
+			}
+			if (mt_op == MTBSFM) {
+				STp->logical_blk_num++;
+				STp->logical_blk_in_buffer = 0;
+			}
+			return 0;
+		}
+		printk(KERN_INFO "osst%i: Reverting to scan filemark backwards\n", dev);
+	}
+	cnt = 0;
+	while (cnt != mt_count) {
+		last_mark_ppos = ntohl(STp->buffer->aux->last_mark_ppos);
+		if (last_mark_ppos == -1)
+			return (-EIO);
+#if DEBUG
+		printk(OSST_DEB_MSG "osst%i: Positioning to last mark at %d\n", dev, last_mark_ppos);
+#endif
+		osst_set_frame_position(STp, aSCpnt, last_mark_ppos, 0);
+		cnt++;
+		if (osst_get_logical_blk(STp, aSCpnt, -1, 0) < 0) {
+			printk(KERN_INFO "osst%i: Couldn't get logical blk num in space_filemarks\n", dev);
+			return (-EIO);
+		}
+		if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
+			printk(KERN_INFO "osst%i: expected to find marker at block %d, not found\n", dev, last_mark_ppos);
+			return (-EIO);
+		}
+	}
+	if (mt_op == MTBSFM) {
+		STp->logical_blk_num++;
+		STp->logical_blk_in_buffer = 0;
+	}
+	return 0;
+}
+
+/*
+ * ADRL 1.1 compatible "slow" space filemarks fwd version
+ *
+ * Just scans for the filemark sequentially.
+ */
+static int osst_space_over_filemarks_forward_slow(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int mt_op, int mt_count)
+{
+	int           dev = TAPE_NR(STp->devt);
+	int           cnt = 0;
+
+#if DEBUG
+	printk(OSST_DEB_MSG "osst%d: Reached space_over_filemarks_forward_slow %d %d\n", dev, mt_op, mt_count);
+#endif
+	if (osst_get_logical_blk(STp, aSCpnt, -1, 0) < 0) {
+		printk(KERN_INFO "osst%i: Couldn't get logical blk num in space_filemarks_fwd\n", dev);
+		return (-EIO);
+	}
+	while (1) {
+		if (osst_get_logical_blk(STp, aSCpnt, -1, 0) < 0) {
+			printk(KERN_INFO "osst%i: Couldn't get logical blk num in space_filemarks\n", dev);
+			return (-EIO);
+		}
+		if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER)
+			cnt++;
+		if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) {
+#if DEBUG
+			printk(OSST_DEB_MSG "osst%i: space_fwd: EOD reached\n", dev);
+#endif
+			if (STp->first_frame_position > STp->eod_frame_ppos+1) {
+#if DEBUG
+				printk(OSST_DEB_MSG "osst%i: EOD position corrected (%d=>%d)\n",
+					       	dev, STp->eod_frame_ppos, STp->first_frame_position-1);
+#endif
+				STp->eod_frame_ppos = STp->first_frame_position-1;
+			}
+			return (-EIO);
+		}
+		if (cnt == mt_count)
+			break;
+		STp->logical_blk_in_buffer = 0;
+	}
+	if (mt_op == MTFSF) {
+		STp->logical_blk_num++;
+		STp->logical_blk_in_buffer = 0;
+	}
+	return 0;
+}
+
+/*
+ * Fast linux specific version of OnStream FSF
+ */
+static int osst_space_over_filemarks_forward_fast(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int mt_op, int mt_count)
+{
+	int           dev = TAPE_NR(STp->devt);
+	int           cnt = 0,
+		      next_mark_ppos = -1;
+
+#if DEBUG
+	printk(OSST_DEB_MSG "osst%d: Reached space_over_filemarks_forward_fast %d %d\n", dev, mt_op, mt_count);
+#endif
+	if (osst_get_logical_blk(STp, aSCpnt, -1, 0) < 0) {
+		printk(KERN_INFO "osst%i: Couldn't get logical blk num in space_filemarks_fwd\n", dev);
+		return (-EIO);
+	}
+
+	if (STp->linux_media_version >= 4) {
+		/*
+		 * direct lookup in header filemark list
+		 */
+		cnt = ntohl(STp->buffer->aux->filemark_cnt) - 1;
+		if (STp->header_ok                         && 
+		    STp->header_cache != NULL              &&
+		    (cnt + mt_count)   < OS_FM_TAB_MAX     &&
+		    (cnt + mt_count)   < STp->filemark_cnt &&
+		    ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
+		     (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] == STp->buffer->aux->last_mark_ppos)))
+
+			next_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt + mt_count]);
+#if 1 //DEBUG
+		if (STp->header_cache == NULL || (cnt + mt_count) >= OS_FM_TAB_MAX)
+			printk(OSST_DEB_MSG "osst%i: Filemark lookup fail due to %s\n", dev,
+			       STp->header_cache == NULL?"lack of header cache":"count out of range");
+		else
+			printk(OSST_DEB_MSG "osst%i: Filemark lookup: prev mark %d (%s), skip %d to %d\n", dev, cnt,
+			       ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
+			        (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] ==
+					 STp->buffer->aux->last_mark_ppos))?"match":"error",
+			       mt_count, next_mark_ppos);
+#endif
+		if (next_mark_ppos <= 10 || next_mark_ppos > STp->eod_frame_ppos) {
+			printk(KERN_INFO "osst%i: Reverting to slow filemark space\n", dev);
+			return osst_space_over_filemarks_forward_slow(STp, aSCpnt, mt_op, mt_count);
+		} else {
+			osst_set_frame_position(STp, aSCpnt, next_mark_ppos, 0);
+			if (osst_get_logical_blk(STp, aSCpnt, -1, 0) < 0) {
+				printk(KERN_INFO "osst%i: Couldn't get logical blk num in space_filemarks\n", dev);
+				return (-EIO);
+			}
+			if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
+				printk(KERN_INFO "osst%i: Expected to find marker at block %d, not found\n",
+						 dev, next_mark_ppos);
+				return (-EIO);
+			}
+			if (ntohl(STp->buffer->aux->filemark_cnt) != cnt + mt_count) {
+				printk(KERN_INFO "osst%i: Expected to find marker %d at block %d, not %d\n",
+						 dev, cnt+mt_count, next_mark_ppos,
+						 ntohl(STp->buffer->aux->filemark_cnt));
+				return (-EIO);
+			}
+		}
+	} else {
+		/*
+		 * Find nearest (usually previous) marker, then jump from marker to marker
+		 */
+		while (1) {
+			if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER)
+				break;
+			if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) {
+#if DEBUG
+				printk(OSST_DEB_MSG "osst%i: space_fwd: EOD reached\n", dev);
+#endif
+				return (-EIO);
+			}
+			if (ntohl(STp->buffer->aux->filemark_cnt) == 0) {
+				if (STp->first_mark_ppos == -1) {
+					printk(KERN_INFO "osst%i: Reverting to slow filemark space\n", dev);
+					return osst_space_over_filemarks_forward_slow(STp, aSCpnt, mt_op, mt_count);
+				}
+				osst_set_frame_position(STp, aSCpnt, STp->first_mark_ppos, 0);
+				if (osst_get_logical_blk(STp, aSCpnt, -1, 0) < 0) {
+					printk(KERN_INFO
+					       "osst%i: Couldn't get logical blk num in space_filemarks_fwd_fast\n",
+					       dev);
+					return (-EIO);
+				}
+				if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
+					printk(KERN_INFO "osst%i: Expected to find filemark at %d\n",
+							 dev, STp->first_mark_ppos);
+					return (-EIO);
+				}
+			} else {
+				if (osst_space_over_filemarks_backward(STp, aSCpnt, MTBSF, 1) < 0)
+					return (-EIO);
+				mt_count++;
+			}
+		}
+		cnt++;
+		while (cnt != mt_count) {
+			next_mark_ppos = ntohl(STp->buffer->aux->next_mark_ppos);
+			if (!next_mark_ppos || next_mark_ppos > STp->eod_frame_ppos) {
+				printk(KERN_INFO "osst%i: Reverting to slow filemark space\n", dev);
+				return osst_space_over_filemarks_forward_slow(STp, aSCpnt, mt_op, mt_count - cnt);
+			}
+#if DEBUG
+			else printk(OSST_DEB_MSG "osst%i: Positioning to next mark at %d\n", dev, next_mark_ppos);
+#endif
+			osst_set_frame_position(STp, aSCpnt, next_mark_ppos, 0);
+			cnt++;
+			if (osst_get_logical_blk(STp, aSCpnt, -1, 0) < 0) {
+				printk(KERN_INFO "osst%i: Couldn't get logical blk num in space_filemarks\n", dev);
+				return (-EIO);
+			}
+			if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
+				printk(KERN_INFO "osst%i: Expected to find marker at block %d, not found\n",
+						 dev, next_mark_ppos);
+				return (-EIO);
+			}
+		}
+	}
+	if (mt_op == MTFSF) 
+		STp->logical_blk_num++;
+		STp->logical_blk_in_buffer = 0;
+	return 0;
+}
+
+/*
+ * In debug mode, we want to see as many errors as possible
+ * to test the error recovery mechanism.
+ */
+#if DEBUG
+static void osst_set_retries(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int retries)
+{
+	unsigned char	cmd[MAX_COMMAND_SIZE];
+	Scsi_Cmnd     * SCpnt  = * aSCpnt;
+	int		dev  = TAPE_NR(STp->devt);
+
+	memset(cmd, 0, MAX_COMMAND_SIZE);
+	cmd[0] = MODE_SELECT;
+	cmd[1] = 0x10;
+	cmd[4] = NUMBER_RETRIES_PAGE_LENGTH + MODE_HEADER_LENGTH;
+
+	(STp->buffer)->b_data[0] = cmd[4] - 1;
+	(STp->buffer)->b_data[1] = 0;			/* Medium Type - ignoring */
+	(STp->buffer)->b_data[2] = 0;			/* Reserved */
+	(STp->buffer)->b_data[3] = 0;			/* Block Descriptor Length */
+	(STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = NUMBER_RETRIES_PAGE | (1 << 7);
+	(STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 2;
+	(STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 4;
+	(STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = retries;
+
+	if (debugging)
+	    printk(OSST_DEB_MSG "osst%i: Setting number of retries on OnStream tape to %d\n", dev, retries);
+
+	SCpnt = osst_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE);
+	*aSCpnt = SCpnt;
+
+	if ((STp->buffer)->last_result_fatal)
+	    printk (KERN_ERR "osst%d: Couldn't set retries to %d\n", dev, retries);
+}
+#endif
+
+#if 0
+static void osst_update_markers(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int last_mark_ppos, int this_mark_ppos)
+{
+	int           dev = TAPE_NR(STp->devt);
+	int	      frame,
+		      reslt;
+
+	if (STp->raw) return;
+
+	STp->last_mark_ppos = this_mark_ppos;
+	if (STp->header_cache != NULL && STp->filemark_cnt < OS_FM_TAB_MAX) 
+		STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt] = htonl(this_mark_ppos);
+	if (STp->filemark_cnt++ == 0)
+		STp->first_mark_ppos = this_mark_ppos;
+
+	if (STp->linux_media_version >= 4) return;
+	if (last_mark_ppos == -1)          return;
+
+	STp->write_type = OS_WRITE_LAST_MARK;
+	frame = osst_get_frame_position(STp, aSCpnt);
+#if DEBUG
+	printk(OSST_DEB_MSG "osst%i: Update last_marker at frame %d\n", dev, last_mark_ppos);
+	printk(OSST_DEB_MSG "osst%i: current position %d, lblk %d, tape blk %d\n",
+			  dev, frame, STp->logical_blk_num, STp->last_frame_position);
+#endif
+	osst_set_frame_position(STp, aSCpnt, last_mark_ppos, 0);
+	osst_initiate_read (STp, aSCpnt);
+	reslt = osst_read_block(STp, aSCpnt, 180);
+
+	if (reslt) {
+		printk(KERN_WARNING "osst%i: couldn't read last marker\n", dev);
+		osst_set_frame_position(STp, aSCpnt, frame, 0);
+		return;
+	}
+	if (STp->buffer->aux->frame_type  != OS_FRAME_TYPE_MARKER) {
+		printk(KERN_WARNING "osst%i: expected marker at addr %d\n", dev, last_mark_ppos);
+		osst_set_frame_position(STp, aSCpnt, frame, 0);
+		return;
+	}
+#if DEBUG
+	printk(OSST_DEB_MSG "osst%i: writing back marker\n", dev);
+#endif
+	STp->buffer->aux->next_mark_ppos = htonl(this_mark_ppos);
+	osst_set_frame_position(STp, aSCpnt, last_mark_ppos, 0);
+	STp->dirty = 1;
+	if (osst_flush_write_buffer(STp, aSCpnt, 0) ||
+	    osst_flush_drive_buffer(STp, aSCpnt)     ) {
+		printk(KERN_WARNING "osst%i: couldn't write marker back at addr %d\n", dev, last_mark_ppos);
+	}
+	osst_set_frame_position(STp, aSCpnt, frame, 0);	
+
+	return; /* FIXME -- errors should go back to user space */
+}
+#endif
+
+static int osst_write_filemark(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt)
+{
+	int	result;
+	int	this_mark_ppos;
+#if DEBUG
+	int	dev = TAPE_NR(STp->devt);
+#endif
+
+	if (STp->raw) return 0;
+
+	STp->write_type = OS_WRITE_NEW_MARK;
+	this_mark_ppos = osst_get_frame_position(STp, aSCpnt);
+#if DEBUG
+	printk(OSST_DEB_MSG "osst%i: Writing Filemark %i at frame %d (lblk %d)\n", 
+	       dev, STp->filemark_cnt, this_mark_ppos, STp->logical_blk_num);
+#endif
+	osst_init_aux(STp, OS_FRAME_TYPE_MARKER, STp->logical_blk_num++);
+	STp->dirty = 1;
+	result  = osst_flush_write_buffer(STp, aSCpnt, 0);
+	result |= osst_flush_drive_buffer(STp, aSCpnt);
+//printk(OSST_DEB_MSG "osst%d: Finished writing file\n",TAPE_NR(STp->devt));
+	STp->last_mark_ppos = this_mark_ppos;
+	if (STp->header_cache != NULL && STp->filemark_cnt < OS_FM_TAB_MAX) 
+		STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt] = htonl(this_mark_ppos);
+	if (STp->filemark_cnt++ == 0)
+		STp->first_mark_ppos = this_mark_ppos;
+//	osst_update_markers(STp, aSCpnt, STp->last_mark_ppos, this_mark_ppos);
+	return result;
+}
+
+static int osst_write_eod(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt)
+{
+	int	result;
+#if DEBUG
+	int	dev = TAPE_NR(STp->devt);
+#endif
+
+	if (STp->raw) return 0;
+
+	STp->write_type = OS_WRITE_EOD;
+	STp->eod_frame_ppos = osst_get_frame_position(STp, aSCpnt);
+#if DEBUG
+	printk(OSST_DEB_MSG "osst%i: Writing EOD at %d=>%d\n", dev, STp->logical_blk_num, STp->eod_frame_ppos);
+#endif
+	osst_init_aux(STp, OS_FRAME_TYPE_EOD, STp->logical_blk_num++);
+	STp->dirty = 1;
+
+	result  = osst_flush_write_buffer(STp, aSCpnt, 0);	
+	result |= osst_flush_drive_buffer(STp, aSCpnt);
+	STp->eod_frame_lfa = --(STp->logical_blk_num);
+	return result;
+}
+
+static int osst_write_filler(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int block, int count)
+{
+	int	      dev = TAPE_NR(STp->devt);
+
+#if DEBUG
+	printk(OSST_DEB_MSG "osst%i: Reached onstream write filler group %d\n", dev, block);
+#endif
+	osst_wait_ready(STp, aSCpnt, 60 * 5);
+	osst_set_frame_position(STp, aSCpnt, block, 0);
+	STp->write_type = OS_WRITE_FILLER;
+	osst_init_aux(STp, OS_FRAME_TYPE_FILL, 0);
+	while (count--) {
+	    memcpy(STp->buffer->b_data, "Filler", 6);
+	    STp->buffer->buffer_bytes = 6;
+	    STp->dirty = 1;
+	    if (osst_flush_write_buffer(STp, aSCpnt, 0)) {
+		printk(KERN_INFO "osst%i: Couldn't write filler frame\n", dev);
+		return (-EIO);
+	    }
+	}
+#if DEBUG
+	printk(OSST_DEB_MSG "osst%i: Exiting onstream write filler group\n", dev);
+#endif
+	return osst_flush_drive_buffer(STp, aSCpnt);
+}
+
+static int __osst_write_header(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int block, int count)
+{
+	int	dev   = TAPE_NR(STp->devt);
+	int     result;
+
+#if DEBUG
+	printk(OSST_DEB_MSG "osst%i: Reached onstream write header group %d\n", dev, block);
+#endif
+	osst_wait_ready(STp, aSCpnt, 60 * 5);
+	osst_set_frame_position(STp, aSCpnt, block, 0);
+	STp->write_type = OS_WRITE_HEADER;
+	osst_init_aux(STp, OS_FRAME_TYPE_HEADER, STp->logical_blk_num);
+	while (count--) {
+	    osst_copy_to_buffer(STp->buffer, (unsigned char *)STp->header_cache);
+//	    memcpy(STp->buffer->b_data, STp->header_cache, sizeof(os_header_t));
+	    STp->buffer->buffer_bytes = sizeof(os_header_t);
+	    STp->dirty = 1;
+	    if (osst_flush_write_buffer(STp, aSCpnt, 0)) {
+		printk(KERN_INFO "osst%i: Couldn't write header frame\n", dev);
+		return (-EIO);
+	    }
+	}
+	result = osst_flush_drive_buffer(STp, aSCpnt);
+#if DEBUG
+	printk(OSST_DEB_MSG "osst%i: Write onstream header group %s\n", dev, result?"failed":"done");
+#endif
+	return result;
+}
+
+static int osst_write_header(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int locate_eod)
+{
+	os_header_t * header;
+	int	      reslt ;
+	int	      dev   = TAPE_NR(STp->devt);
+
+#if DEBUG
+	printk(OSST_DEB_MSG "osst%i: Writing tape header\n", dev);
+#endif
+	if (STp->raw) return 0;
+
+	if (STp->header_cache == NULL) {
+		if ((STp->header_cache = (os_header_t *)vmalloc(sizeof(os_header_t))) == NULL) {
+			printk(KERN_ERR "osst%i: Failed to allocate header cache\n", dev);
+			return (-ENOMEM);
+		}
+		memset(STp->header_cache, 0, sizeof(os_header_t));
+#if DEBUG
+		printk(OSST_DEB_MSG "osst%d: Allocated and cleared memory for header cache\n", dev);
+#endif
+	}
+	if (STp->header_ok) STp->update_frame_cntr++;
+	else                STp->update_frame_cntr = 0;
+
+	header = STp->header_cache;
+	strcpy(header->ident_str, "ADR_SEQ");
+	header->major_rev      = 1;
+	header->minor_rev      = 4;
+	header->ext_trk_tb_off = htons(17192);
+	header->pt_par_num     = 1;
+	header->partition[0].partition_num              = OS_DATA_PARTITION;
+	header->partition[0].par_desc_ver               = OS_PARTITION_VERSION;
+	header->partition[0].wrt_pass_cntr              = htons(STp->wrt_pass_cntr);
+	header->partition[0].first_frame_ppos           = htonl(STp->first_data_ppos);
+	header->partition[0].last_frame_ppos            = htonl(STp->capacity);
+	header->partition[0].eod_frame_ppos             = htonl(STp->eod_frame_ppos);
+	header->cfg_col_width                           = htonl(20);
+	header->dat_col_width                           = htonl(1500);
+	header->qfa_col_width                           = htonl(0);
+	header->ext_track_tb.nr_stream_part             = 1;
+	header->ext_track_tb.et_ent_sz                  = 32;
+	header->ext_track_tb.dat_ext_trk_ey.et_part_num = 0;
+	header->ext_track_tb.dat_ext_trk_ey.fmt         = 1;
+	header->ext_track_tb.dat_ext_trk_ey.fm_tab_off  = htons(17736);
+	header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi = 0;
+	header->ext_track_tb.dat_ext_trk_ey.last_hlb    = htonl(STp->eod_frame_lfa);
+	header->ext_track_tb.dat_ext_trk_ey.last_pp	= htonl(STp->eod_frame_ppos);
+	header->dat_fm_tab.fm_part_num                  = 0;
+	header->dat_fm_tab.fm_tab_ent_sz                = 4;
+	header->dat_fm_tab.fm_tab_ent_cnt               = htons(STp->filemark_cnt<OS_FM_TAB_MAX?
+								STp->filemark_cnt:OS_FM_TAB_MAX);
+
+	reslt  = __osst_write_header(STp, aSCpnt, 0xbae, 5);
+	if (STp->update_frame_cntr == 0)
+		   osst_write_filler(STp, aSCpnt, 0xbb3, 5);
+	reslt &= __osst_write_header(STp, aSCpnt,     5, 5);
+
+	if (locate_eod) {
+#if DEBUG
+		printk(OSST_DEB_MSG "osst%i: locating back to eod frame addr %d\n", dev, STp->eod_frame_ppos);
+#endif
+		osst_set_frame_position(STp, aSCpnt, STp->eod_frame_ppos, 0);
+	}
+	if (reslt)
+		printk(KERN_WARNING "osst%i: write header failed\n", dev);
+	else {
+		memcpy(STp->application_sig, "LIN4", 4);
+		STp->linux_media         = 1;
+		STp->linux_media_version = 4;
+		STp->header_ok           = 1;
+	}
+	return reslt;
+}
+
+static int osst_reset_header(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt)
+{
+	if (STp->header_cache != NULL)
+		memset(STp->header_cache, 0, sizeof(os_header_t));
+
+	STp->logical_blk_num = 0;
+	STp->logical_blk_in_buffer = 0;
+	STp->eod_frame_ppos = STp->first_data_ppos = 0x0000000A;
+	STp->filemark_cnt = 0;
+	STp->first_mark_ppos = STp->last_mark_ppos = -1;
+	return osst_write_header(STp, aSCpnt, 1);
+}
+
+static int __osst_analyze_headers(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int block)
+{
+	int           dev = TAPE_NR(STp->devt);
+	os_header_t * header;
+	os_aux_t    * aux;
+	char          id_string[8];
+	int	      linux_media_version,
+		      update_frame_cntr;
+
+	if (STp->raw)
+		return 1;
+
+	if (block == 5 || block == 0xbae || STp->buffer->last_result_fatal) {
+		if (osst_set_frame_position(STp, aSCpnt, block, 0))
+			printk(KERN_WARNING "osst%i: Couldn't position tape\n", dev);
+		if (osst_initiate_read (STp, aSCpnt)) {
+			printk(KERN_WARNING "osst%i: Couldn't initiate read\n", dev);
+			return 0;
+		}
+	}
+	if (osst_read_block(STp, aSCpnt, 180)) {
+#if DEBUG
+		printk(OSST_DEB_MSG "osst%i: Couldn't read header frame\n", dev);
+#endif
+		return 0;
+	}
+	header = (os_header_t *) STp->buffer->b_data;	/* warning: only first segment addressable */
+	aux = STp->buffer->aux;
+	if (aux->frame_type != OS_FRAME_TYPE_HEADER) {
+#if DEBUG
+		printk(OSST_DEB_MSG "osst%i: Skipping non-header frame (%d)\n", dev, block);
+#endif
+		return 0;
+	}
+	if (strncmp(header->ident_str, "ADR_SEQ", 7) != 0 &&
+	    strncmp(header->ident_str, "ADR-SEQ", 7) != 0) {
+                strncpy(id_string, header->ident_str, 7);
+		id_string[7] = 0;
+		printk(KERN_INFO "osst%i: Invalid header identification string %s\n", dev, id_string);
+		return 0;
+	}
+	update_frame_cntr = ntohl(aux->update_frame_cntr);
+	if (update_frame_cntr < STp->update_frame_cntr) {
+#if DEBUG
+		printk(OSST_DEB_MSG "osst%i: Skipping frame %d with update_frame_counter %d<%d\n",
+				   dev, block, update_frame_cntr, STp->update_frame_cntr);
+#endif
+		return 0;
+	}
+	if (header->major_rev != 1 || header->minor_rev != 4 ) {
+		printk(KERN_INFO "osst%i: %s revision %d.%d detected (1.4 supported)\n", 
+				 dev, (header->major_rev != 1 || header->minor_rev < 2 || 
+				       header->minor_rev  > 4 )? "Invalid" : "Warning:",
+				 header->major_rev, header->minor_rev);
+		if (header->major_rev != 1 || header->minor_rev < 2 || header->minor_rev > 4)
+			return 0;
+	}
+	if (header->pt_par_num != 1)
+		printk(KERN_INFO "osst%i: Warning: %d partitions defined, only one supported\n", 
+				 dev, header->pt_par_num);
+	memcpy(id_string, aux->application_sig, 4);
+	id_string[4] = 0;
+	if (memcmp(id_string, "LIN", 3) == 0) {
+		STp->linux_media = 1;
+		linux_media_version = id_string[3] - '0';
+		if (linux_media_version != 4)
+			printk(KERN_INFO "osst%i: Linux media version %d detected (current 4)\n",
+					 dev, linux_media_version);
+	} else {
+		printk(KERN_WARNING "osst%i: non Linux media detected (%s)\n", dev, id_string);
+		return 0;
+	}
+	if (linux_media_version < STp->linux_media_version) {
+#if DEBUG
+		printk(OSST_DEB_MSG "osst%i: Skipping frame %d with linux_media_version %d\n",
+				  dev, block, linux_media_version);
+#endif
+		return 0;
+	}
+	if (linux_media_version > STp->linux_media_version) {
+#if DEBUG
+		printk(OSST_DEB_MSG "osst%i: Frame %d sets linux_media_version to %d\n",
+				   dev, block, linux_media_version);
+#endif
+		memcpy(STp->application_sig, id_string, 5);
+		STp->linux_media_version = linux_media_version;
+		STp->update_frame_cntr = -1;
+	}
+	if (update_frame_cntr > STp->update_frame_cntr) {
+#if DEBUG
+		printk(OSST_DEB_MSG "osst%i: Frame %d sets update_frame_counter to %d\n",
+				   dev, block, update_frame_cntr);
+#endif
+		if (STp->header_cache == NULL) {
+			if ((STp->header_cache = (os_header_t *)vmalloc(sizeof(os_header_t))) == NULL) {
+				printk(KERN_ERR "osst%i: Failed to allocate header cache\n", dev);
+				return 0;
+			}
+#if DEBUG
+			printk(OSST_DEB_MSG "osst%d: Allocated memory for header cache\n", dev);
+#endif
+		}
+		osst_copy_from_buffer(STp->buffer, (unsigned char *)STp->header_cache);
+		header = STp->header_cache;	/* further accesses from cached (full) copy */
+
+		STp->wrt_pass_cntr     = ntohs(header->partition[0].wrt_pass_cntr);
+		STp->first_data_ppos   = ntohl(header->partition[0].first_frame_ppos);
+		STp->eod_frame_ppos    = ntohl(header->partition[0].eod_frame_ppos);
+		STp->eod_frame_lfa     = ntohl(header->ext_track_tb.dat_ext_trk_ey.last_hlb);
+		STp->filemark_cnt      = ntohl(aux->filemark_cnt);
+		STp->first_mark_ppos   = ntohl(aux->next_mark_ppos);
+		STp->last_mark_ppos    = ntohl(aux->last_mark_ppos);
+		STp->update_frame_cntr = update_frame_cntr;
+#if DEBUG
+	printk(OSST_DEB_MSG "osst%i: detected write pass %d, update frame counter %d, filemark counter %d\n",
+			  dev, STp->wrt_pass_cntr, STp->update_frame_cntr, STp->filemark_cnt);
+	printk(OSST_DEB_MSG "osst%i: first data frame on tape = %d, last = %d, eod frame = %d\n", dev,
+			  STp->first_data_ppos,
+			  ntohl(header->partition[0].last_frame_ppos),
+			  ntohl(header->partition[0].eod_frame_ppos));
+	printk(OSST_DEB_MSG "osst%i: first mark on tape = %d, last = %d, eod frame = %d\n", 
+			  dev, STp->first_mark_ppos, STp->last_mark_ppos, STp->eod_frame_ppos);
+#endif
+		if (header->minor_rev < 4 && STp->linux_media_version == 4) {
+			printk(OSST_DEB_MSG "osst%i: Moving filemark list to ADR 1.4 location\n", dev);
+			memcpy((void *)header->dat_fm_tab.fm_tab_ent, 
+			       (void *)header->old_filemark_list, sizeof(header->dat_fm_tab.fm_tab_ent));
+			memset((void *)header->old_filemark_list, 0, sizeof(header->old_filemark_list));
+		}
+		if (header->minor_rev == 4   &&
+		    (header->ext_trk_tb_off                          != htons(17192)               ||
+		     header->partition[0].partition_num              != OS_DATA_PARTITION          ||
+		     header->partition[0].par_desc_ver               != OS_PARTITION_VERSION       ||
+		     header->partition[0].last_frame_ppos            != htonl(STp->capacity)       ||
+		     header->cfg_col_width                           != htonl(20)                  ||
+		     header->dat_col_width                           != htonl(1500)                ||
+		     header->qfa_col_width                           != htonl(0)                   ||
+		     header->ext_track_tb.nr_stream_part             != 1                          ||
+		     header->ext_track_tb.et_ent_sz                  != 32                         ||
+		     header->ext_track_tb.dat_ext_trk_ey.et_part_num != OS_DATA_PARTITION          ||
+		     header->ext_track_tb.dat_ext_trk_ey.fmt         != 1                          ||
+		     header->ext_track_tb.dat_ext_trk_ey.fm_tab_off  != htons(17736)               ||
+		     header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi != 0                          ||
+		     header->ext_track_tb.dat_ext_trk_ey.last_pp     != htonl(STp->eod_frame_ppos) ||
+		     header->dat_fm_tab.fm_part_num                  != OS_DATA_PARTITION          ||
+		     header->dat_fm_tab.fm_tab_ent_sz                != 4                          ||
+		     header->dat_fm_tab.fm_tab_ent_cnt               !=
+			     htons(STp->filemark_cnt<OS_FM_TAB_MAX?STp->filemark_cnt:OS_FM_TAB_MAX)))
+			printk(KERN_WARNING "osst%i: Failed consistency check ADR 1.4 format\n", dev);
+
+//		memcpy(STp->header_cache, header, sizeof(os_header_t));
+	}
+
+	return 1;
+}
+
+static int osst_analyze_headers(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt)
+{
+	int position, block;
+	int first, last;
+	int valid = 0;
+	int dev = TAPE_NR(STp->devt);
+
+        position = osst_get_frame_position(STp, aSCpnt);
+
+	if (STp->raw) {
+		STp->header_ok = STp->linux_media = 1;
+		STp->linux_media_version = 0;
+		return 1;
+	}
+	STp->header_ok = STp->linux_media = STp->linux_media_version = 0;
+	STp->wrt_pass_cntr = STp->update_frame_cntr = -1;
+	STp->eod_frame_ppos = STp->first_data_ppos = -1;
+	STp->first_mark_ppos = STp->last_mark_ppos = -1;
+#if DEBUG
+	printk(OSST_DEB_MSG "osst%i: Reading header\n", dev);
+#endif
+
+	/* optimization for speed - if we are positioned at block 10, read second group first */	
+	/* TODO try the ADR 1.1 locations for the second group if we have no valid one yet... */
+
+	first = position==10?0xbae: 5;
+	last  = position==10?0xbb3:10;
+
+	for (block = first; block < last; block++)
+		if (__osst_analyze_headers(STp, aSCpnt, block))
+			valid = 1;
+
+	first = position==10? 5:0xbae;
+	last  = position==10?10:0xbb3;
+
+	for (block = first; block < last; block++)
+		if (__osst_analyze_headers(STp, aSCpnt, block))
+			valid = 1;
+
+	if (!valid) {
+		printk(KERN_ERR "osst%i: Failed to find valid ADRL header, new media?\n", dev);
+		STp->eod_frame_ppos = STp->first_data_ppos = 0;
+		osst_set_frame_position(STp, aSCpnt, 10, 0);
+		return 0;
+	}
+	if (position <= STp->first_data_ppos) {
+		position = STp->first_data_ppos;
+		STp->ps[0].drv_file = STp->ps[0].drv_block = STp->logical_blk_num = 0;
+	}
+	osst_set_frame_position(STp, aSCpnt, position, 0);
+	STp->header_ok = 1;
+
+	return 1;
+}
+
+static int osst_verify_position(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt)
+{
+	int frame_position  = STp->first_frame_position;
+	int logical_blk_num = STp->logical_blk_num;
+	int prev_mark_ppos  = -1;
+	int actual_mark_ppos, i, n;
+#if 1 //DEBUG
+	int dev = TAPE_NR(STp->devt);
+
+	printk(OSST_DEB_MSG "osst%i: Verify that the tape is really the one we think before writing\n", dev);
+#endif
+	osst_set_frame_position(STp, aSCpnt, frame_position - 1, 0);
+	if (osst_get_logical_blk(STp, aSCpnt, -1, 0) < 0) {
+#if DEBUG
+		printk(OSST_DEB_MSG "osst%i: Couldn't get logical blk num in verify_position\n", dev);
+#endif
+		return (-EIO);
+	}
+	if (STp->linux_media_version >= 4) {
+		for (i=0; i<STp->filemark_cnt; i++)
+			if ((n=ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i])) < frame_position)
+				prev_mark_ppos = n;
+	} else
+		prev_mark_ppos = frame_position - 1;  /* usually - we don't really know */
+	actual_mark_ppos = STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER ?
+				frame_position - 1 : ntohl(STp->buffer->aux->last_mark_ppos);
+	if (frame_position  != STp->first_frame_position ||
+	    logical_blk_num != STp->logical_blk_num + 1  ||
+	    prev_mark_ppos  != actual_mark_ppos           ) {
+#if 1 //DEBUG
+		printk(OSST_DEB_MSG "osst%i: Block mismatch: frame %d-%d, lblk %d-%d, mark %d-%d\n", dev,
+				  STp->first_frame_position, frame_position, STp->logical_blk_num + 1,
+				  logical_blk_num, actual_mark_ppos, prev_mark_ppos);
+#endif
+		return (-EIO);
+	}
+	STp->logical_blk_in_buffer = 0;
+	STp->logical_blk_num = logical_blk_num;
+	return 0;
+}
+
+/* Acc. to OnStream, the vers. numbering is the following:
+ * X.XX for released versions (X=digit), 
+ * XXXY for unreleased versions (Y=letter)
+ * Ordering 1.05 < 106A < 106a < 106B < ... < 1.06
+ * This fn makes monoton numbers out of this scheme ...
+ */
+static unsigned int osst_parse_firmware_rev (const char * str)
+{
+	unsigned int rev;
+	if (str[1] == '.') {
+		rev = (str[0]-0x30)*10000
+			+(str[2]-0x30)*1000
+			+(str[3]-0x30)*100;
+	} else {
+		rev = (str[0]-0x30)*10000
+			+(str[1]-0x30)*1000
+			+(str[2]-0x30)*100 - 100;
+		rev += 2*(str[3] & 0x1f)
+			+(str[3] >= 0x60? 1: 0);
+	}
+	return rev;
+}
+
+/*
+ * Configure the OnStream SCII tape drive for default operation
+ */
+static int osst_configure_onstream(OS_Scsi_Tape *STp, Scsi_Cmnd ** aSCpnt)
+{
+	int                            dev   = TAPE_NR(STp->devt);
+	unsigned char                  cmd[MAX_COMMAND_SIZE];
+        Scsi_Cmnd                    * SCpnt = * aSCpnt;
+        osst_mode_parameter_header_t * header;
+        osst_block_size_page_t       * bs;
+	osst_capabilities_page_t     * cp;
+	osst_tape_paramtr_page_t     * prm;
+	int                            drive_buffer_size;
+
+	if (STp->ready != ST_READY) {
+#if DEBUG
+	    printk(OSST_DEB_MSG "osst%i: Not Ready\n", dev);
+#endif
+	    return (-EIO);
+	}
+	
+	if (STp->os_fw_rev < 10600) {
+            printk("osst%i: Old OnStream firmware revision detected (%s)\n", 
+                       dev, STp->device->rev);
+            printk("osst%i: An upgrade to version 1.06 or above is recommended\n",
+                       dev);
+        }
+
+        /*
+         * Configure 32.5KB (data+aux) frame size.
+         * Get the current block size from the block size mode page
+         */
+	memset(cmd, 0, MAX_COMMAND_SIZE);
+	cmd[0] = MODE_SENSE;
+	cmd[1] = 8;
+	cmd[2] = BLOCK_SIZE_PAGE;
+	cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH;
+
+	SCpnt = osst_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE);
+	if (SCpnt == NULL) {
+#if DEBUG
+ 	    printk(OSST_DEB_MSG "osst: Busy\n");
+#endif
+	    return (-EBUSY);
+	}
+	*aSCpnt = SCpnt;
+	if ((STp->buffer)->last_result_fatal != 0) {
+	    printk (KERN_ERR "osst%i: Can't get tape block size mode page\n", dev);
+	    return (-EIO);
+	}
+
+        header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
+        bs = (osst_block_size_page_t *) ((STp->buffer)->b_data + sizeof(osst_mode_parameter_header_t) + header->bdl);
+
+#if DEBUG
+        printk(KERN_INFO "osst%i: 32KB play back: %s\n",   dev, bs->play32     ? "Yes" : "No");
+        printk(KERN_INFO "osst%i: 32.5KB play back: %s\n", dev, bs->play32_5   ? "Yes" : "No");
+        printk(KERN_INFO "osst%i: 32KB record: %s\n",      dev, bs->record32   ? "Yes" : "No");
+        printk(KERN_INFO "osst%i: 32.5KB record: %s\n",    dev, bs->record32_5 ? "Yes" : "No");
+#endif
+
+        /*
+         * Configure default auto columns mode, 32.5KB transfer mode
+         */ 
+        bs->one = 1;
+        bs->play32 = 0;
+        bs->play32_5 = 1;
+        bs->record32 = 0;
+        bs->record32_5 = 1;
+
+	memset(cmd, 0, MAX_COMMAND_SIZE);
+	cmd[0] = MODE_SELECT;
+	cmd[1] = 0x10;
+	cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH;
+
+	SCpnt = osst_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE);
+	*aSCpnt = SCpnt;
+        if ((STp->buffer)->last_result_fatal != 0) {
+            printk (KERN_ERR "osst%i: Couldn't set tape block size mode page\n", dev);
+	    return (-EIO);
+	}
+
+	STp->block_size = (STp->raw) ? OS_FRAME_SIZE : OS_DATA_SIZE;
+	STp->min_block  = OS_FRAME_SIZE; /* FIXME */
+	STp->max_block  = STp->block_size;
+
+#if DEBUG
+        printk(KERN_INFO "osst%i: Block Size changed to 32.5K\n", dev);
+         /*
+         * In debug mode, we want to see as many errors as possible
+         * to test the error recovery mechanism.
+         */
+        osst_set_retries(STp, aSCpnt, 0);
+	SCpnt = * aSCpnt;
+#endif
+
+        /*
+         * Set vendor name to 'LIN4' for "Linux support version 4".
+         */
+
+	memset(cmd, 0, MAX_COMMAND_SIZE);
+	cmd[0] = MODE_SELECT;
+	cmd[1] = 0x10;
+	cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH;
+
+	header->mode_data_length = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH - 1;
+	header->medium_type      = 0;	/* Medium Type - ignoring */
+	header->dsp              = 0;	/* Reserved */
+	header->bdl              = 0;	/* Block Descriptor Length */
+	
+	(STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = VENDOR_IDENT_PAGE | (1 << 7);
+	(STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 6;
+	(STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 'L';
+	(STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 'I';
+	(STp->buffer)->b_data[MODE_HEADER_LENGTH + 4] = 'N';
+	(STp->buffer)->b_data[MODE_HEADER_LENGTH + 5] = '4';
+	(STp->buffer)->b_data[MODE_HEADER_LENGTH + 6] = 0;
+	(STp->buffer)->b_data[MODE_HEADER_LENGTH + 7] = 0;
+
+	SCpnt = osst_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE);
+	*aSCpnt = SCpnt;
+
+        if ((STp->buffer)->last_result_fatal != 0) {
+            printk (KERN_ERR "osst%i: Couldn't set vendor name to %s\n", dev, 
+			(char *) ((STp->buffer)->b_data + MODE_HEADER_LENGTH + 2));
+	    return (-EIO);
+	}
+
+	memset(cmd, 0, MAX_COMMAND_SIZE);
+	cmd[0] = MODE_SENSE;
+	cmd[1] = 8;
+	cmd[2] = CAPABILITIES_PAGE;
+	cmd[4] = CAPABILITIES_PAGE_LENGTH + MODE_HEADER_LENGTH;
+
+	SCpnt = osst_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE);
+	*aSCpnt = SCpnt;
+
+	if ((STp->buffer)->last_result_fatal != 0) {
+	    printk (KERN_ERR "osst%i: can't get capabilities page\n", dev);
+	    return (-EIO);
+	}
+
+        header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
+	cp     = (osst_capabilities_page_t    *) ((STp->buffer)->b_data +
+		 sizeof(osst_mode_parameter_header_t) + header->bdl);
+
+	drive_buffer_size = ntohs(cp->buffer_size) / 2;
+
+	memset(cmd, 0, MAX_COMMAND_SIZE);
+	cmd[0] = MODE_SENSE;
+	cmd[1] = 8;
+	cmd[2] = TAPE_PARAMTR_PAGE;
+	cmd[4] = TAPE_PARAMTR_PAGE_LENGTH + MODE_HEADER_LENGTH;
+
+	SCpnt = osst_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE);
+	*aSCpnt = SCpnt;
+
+	if ((STp->buffer)->last_result_fatal != 0) {
+	    printk (KERN_ERR "osst%i: can't get tape parameter page\n", dev);
+	    return (-EIO);
+	}
+
+        header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
+	prm    = (osst_tape_paramtr_page_t    *) ((STp->buffer)->b_data +
+		 sizeof(osst_mode_parameter_header_t) + header->bdl);
+
+	STp->density  = prm->density;
+	STp->capacity = ntohs(prm->segtrk) * ntohs(prm->trks);
+#if DEBUG
+	printk(OSST_DEB_MSG "osst%d: Density %d, tape length: %dMB, drive buffer size: %dKB\n",
+			  dev, STp->density, STp->capacity / 32, drive_buffer_size);
+#endif
+
+	return 0;
+	
+}
+
+
+/* Step over EOF if it has been inadvertently crossed (ioctl not used because
+   it messes up the block number). */
+static int cross_eof(OS_Scsi_Tape *STp, Scsi_Cmnd ** aSCpnt, int forward)
+{
+	int         result;
+	int         dev   = TAPE_NR(STp->devt);
+
+#if DEBUG
+	if (debugging)
+		printk(OSST_DEB_MSG "osst%d: Stepping over filemark %s.\n",
+	   			  dev, forward ? "forward" : "backward");
+#endif
+
+	if (forward) {
+	   /* assumes that the filemark is already read by the drive, so this is low cost */
+	   result = osst_space_over_filemarks_forward_slow(STp, aSCpnt, MTFSF, 1);
+	}
+	else
+	   /* assumes this is only called if we just read the filemark! */
+	   result = osst_seek_logical_blk(STp, aSCpnt, STp->logical_blk_num - 1);
+
+	if (result < 0)
+	   printk(KERN_ERR "osst%d: Stepping over filemark %s failed.\n",
+				dev, forward ? "forward" : "backward");
+
+	return result;
+}
+
+
+/* Get the tape position. */
+
+static int osst_get_frame_position(OS_Scsi_Tape *STp, Scsi_Cmnd ** aSCpnt)
+{
+    int result = 0;
+    unsigned char scmd[MAX_COMMAND_SIZE];
+    Scsi_Cmnd   * SCpnt;
+
+    /* KG: We want to be able to use it for checking Write Buffer availability
+     *  and thus don't want to risk to overwrite anything. Exchange buffers ... */
+    char mybuf[24];
+    char * olddata = STp->buffer->b_data;
+    int oldsize = STp->buffer->buffer_size;
+    int dev = TAPE_NR(STp->devt);
+
+    if (STp->ready != ST_READY)
+      return (-EIO);
+
+    memset (scmd, 0, MAX_COMMAND_SIZE);
+    scmd[0] = READ_POSITION;
+
+    STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
+    SCpnt = osst_do_scsi(*aSCpnt, STp, scmd, 20, STp->timeout, MAX_READY_RETRIES, TRUE);
+    if (!SCpnt) {
+	    STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
+	    return (-EBUSY);
+    }
+    *aSCpnt = SCpnt;
+
+    if (STp->buffer->last_result_fatal)
+      result = ((SCpnt->sense_buffer[2] & 0x0f) == 3) ? -EIO : -EINVAL;
+
+    if (result == -EINVAL)
+      printk(KERN_ERR "osst%d: Can't read tape position.\n", dev);
+    else {
+
+      if (result == -EIO) {	/* re-read position */
+	unsigned char mysense[16];
+	memcpy (mysense, SCpnt->sense_buffer, 16);
+	memset (scmd, 0, MAX_COMMAND_SIZE);
+	scmd[0] = READ_POSITION;
+	STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
+	SCpnt = osst_do_scsi(SCpnt, STp, scmd, 20, STp->timeout, MAX_READY_RETRIES, TRUE);
+	if (!STp->buffer->last_result_fatal)
+	   memcpy (SCpnt->sense_buffer, mysense, 16);
+      }
+      STp->first_frame_position = ((STp->buffer)->b_data[4] << 24)
+				+ ((STp->buffer)->b_data[5] << 16)
+				+ ((STp->buffer)->b_data[6] << 8)
+				+  (STp->buffer)->b_data[7];
+      STp->last_frame_position  = ((STp->buffer)->b_data[ 8] << 24)
+				+ ((STp->buffer)->b_data[ 9] << 16)
+				+ ((STp->buffer)->b_data[10] <<  8)
+				+  (STp->buffer)->b_data[11];
+      STp->cur_frames           =  (STp->buffer)->b_data[15];
+#if DEBUG
+      if (debugging) {
+	printk(OSST_DEB_MSG "osst%d: Drive Positions: host %d, tape %d%s, buffer %d\n", dev,
+			   STp->first_frame_position, STp->last_frame_position,
+			   ((STp->buffer)->b_data[0]&0x80)?" (BOP)":
+			   ((STp->buffer)->b_data[0]&0x40)?" (EOP)":"",
+			   STp->cur_frames);
+      }
+#endif
+      if (STp->cur_frames == 0 && STp->first_frame_position != STp->last_frame_position) {
+#if DEBUG
+	  printk(KERN_WARNING "osst%d: Correcting read position %d, %d, %d\n", dev,
+				STp->first_frame_position, STp->last_frame_position, STp->cur_frames);
+#endif
+	  STp->first_frame_position = STp->last_frame_position;
+      }
+    }
+    STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
+
+    return (result == 0 ? STp->first_frame_position : result);
+}
+
+
+/* Set the tape block */
+static int osst_set_frame_position(OS_Scsi_Tape *STp, Scsi_Cmnd ** aSCpnt, int block, int skip)
+{
+    ST_partstat *STps;
+    int result = 0;
+    int timeout;
+    unsigned char scmd[MAX_COMMAND_SIZE];
+    Scsi_Cmnd   * SCpnt;
+    int dev = TAPE_NR(STp->devt);
+
+    if (STp->ready != ST_READY)
+      return (-EIO);
+    timeout = STp->long_timeout;
+    STps = &(STp->ps[STp->partition]);
+
+    if (block < 0 || block > STp->capacity) {
+      printk(KERN_ERR "osst%d: Reposition request %d out of range\n", dev, block);
+      block = block < 0 ? 0 : (STp->capacity - 1);
+      result = (-EINVAL);
+    }
+#if DEBUG
+    if (debugging)
+      printk(OSST_DEB_MSG "osst%d: Setting block to %d.\n", dev, block);
+#endif
+    memset (scmd, 0, MAX_COMMAND_SIZE);
+    scmd[0] = SEEK_10;
+    scmd[1] = 1;
+    scmd[3] = (block >> 24);
+    scmd[4] = (block >> 16);
+    scmd[5] = (block >> 8);
+    scmd[6] = block;
+    if (skip)
+      scmd[9] = 0x80;
+
+    SCpnt = osst_do_scsi(*aSCpnt, STp, scmd, 20, timeout, MAX_READY_RETRIES, TRUE);
+    if (!SCpnt) {
+#if DEBUG
+      printk(OSST_DEB_MSG "osst%d: Busy\n", dev);
+#endif
+      return (-EBUSY);
+    }
+    *aSCpnt  = SCpnt;
+
+    STp->first_frame_position = STp->last_frame_position = block;
+    STps->eof = ST_NOEOF;
+    if ((STp->buffer)->last_result_fatal != 0) {
+#if DEBUG
+      printk(OSST_DEB_MSG "osst%d: SEEK command failed.\n", dev);
+#endif
+      result = (-EIO);
+    }
+    STps->at_sm = 0;
+    STps->rw = ST_IDLE;
+    STp->logical_blk_in_buffer = 0;
+    return result;
+}
+
+
+
+/* osst versions of st functions - augmented and stripped to suit OnStream only */
+
+/* Flush the write buffer (never need to write if variable blocksize). */
+static int osst_flush_write_buffer(OS_Scsi_Tape *STp, Scsi_Cmnd ** aSCpnt, int file_blk)
+{
+  int offset, transfer, blks = 0;
+  int result = 0;
+  unsigned char cmd[MAX_COMMAND_SIZE];
+  Scsi_Cmnd * SCpnt = *aSCpnt;
+  ST_partstat * STps;
+  int dev = TAPE_NR(STp->devt);
+
+  if ((STp->buffer)->writing) {
+    if (SCpnt == (STp->buffer)->last_SCpnt)
+#if DEBUG
+    { printk(OSST_DEB_MSG
+	 "osst%d: aSCpnt points to Scsi_Cmnd that write_behind_check will release -- cleared\n", dev);
+#endif
+      *aSCpnt = SCpnt = NULL;
+#if DEBUG
+    } else if (SCpnt)
+      printk(OSST_DEB_MSG
+	 "osst%d: aSCpnt does not point to Scsi_Cmnd that write_behind_check will release -- strange\n", dev);
+#endif	
+    osst_write_behind_check(STp);
+    if ((STp->buffer)->last_result_fatal) {
+#if DEBUG
+      if (debugging)
+	printk(OSST_DEB_MSG "osst%d: Async write error (flush) %x.\n",
+	       dev, (STp->buffer)->last_result);
+#endif
+      if ((STp->buffer)->last_result == INT_MAX)
+	return (-ENOSPC);
+      return (-EIO);
+    }
+  }
+
+  result = 0;
+  if (STp->dirty == 1) {
+
+    offset   = STp->buffer->buffer_bytes;
+    transfer = OS_FRAME_SIZE;
+    blks     = 1;
+    
+#if DEBUG
+    if (debugging)
+      printk(OSST_DEB_MSG "osst%d: Flushing %d bytes, Tranfering %d bytes in %d blocks.\n",
+			 dev, offset, transfer, blks);
+#endif
+    if (offset < OS_DATA_SIZE)
+      osst_zero_buffer_tail(STp->buffer);
+
+    /* TODO: Error handling! */
+    if (STp->poll)
+	result = osst_wait_frame (STp, aSCpnt, STp->first_frame_position, -50, 120);
+//osst_build_stats(STp, aSCpnt);
+    memset(cmd, 0, MAX_COMMAND_SIZE);
+    cmd[0] = WRITE_6;
+    cmd[1] = 1;
+    cmd[4] = blks;
+
+    SCpnt = osst_do_scsi(*aSCpnt, STp, cmd, transfer, STp->timeout, MAX_WRITE_RETRIES, TRUE);
+    *aSCpnt = SCpnt;
+    if (!SCpnt)
+      return (-EBUSY);
+
+    STps = &(STp->ps[STp->partition]);
+    if ((STp->buffer)->last_result_fatal != 0) {
+	printk(OSST_DEB_MSG "osst%d: write sense [0]=0x%02x [2]=%02x [12]=%02x [13]=%02x\n", TAPE_NR(STp->devt),
+		SCpnt->sense_buffer[0], SCpnt->sense_buffer[2], SCpnt->sense_buffer[12], SCpnt->sense_buffer[13]);
+      if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
+	  (SCpnt->sense_buffer[2] & 0x40) &&			/* FIXME - SC-30 drive doesn't assert EOM bit */
+	  (SCpnt->sense_buffer[2] & 0x0f) == NO_SENSE) {
+	STp->dirty = 0;
+	(STp->buffer)->buffer_bytes = 0;
+	result = (-ENOSPC);
+      }
+      else {
+	if (osst_write_error_recovery(STp, aSCpnt, 1)) {
+	  printk(KERN_ERR "osst%d: Error on flush.\n", dev);
+	  result = (-EIO);
+        }
+      }
+      STps->drv_block = (-1);
+    }
+    else {
+      STp->first_frame_position++;
+      if (file_blk && STps->drv_block >= 0)
+	STps->drv_block += blks;
+      STp->first_frame_position += blks;
+      STp->dirty = 0;
+      (STp->buffer)->buffer_bytes = 0;
+    }
+  }
+#if DEBUG
+  printk(OSST_DEB_MSG "osst%d: Exit flush write buffer with code %d\n", dev, result);
+#endif
+  return result;
+}
+
+
+/* Flush the tape buffer. The tape will be positioned correctly unless
+   seek_next is true. */
+static int osst_flush_buffer(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, int seek_next)
+{
+  int backspace, result;
+  OSST_buffer    * STbuffer;
+  ST_partstat  * STps;
+#if DEBUG
+  int dev = TAPE_NR(STp->devt);
+#endif
+
+  STbuffer = STp->buffer;
+
+  /*
+   * If there was a bus reset, block further access
+   * to this device.
+   */
+  if( STp->device->was_reset )
+    return (-EIO);
+
+  if (STp->ready != ST_READY)
+    return 0;
+
+  STps = &(STp->ps[STp->partition]);
+  if (STps->rw == ST_WRITING)  /* Writing */
+    return osst_flush_write_buffer(STp, aSCpnt, 1);
+
+  if (STp->block_size == 0)
+    return 0;
+
+#if DEBUG
+	printk(OSST_DEB_MSG "osst%i: Reached flush (read) buffer\n", dev);
+#endif
+  backspace = ((STp->buffer)->buffer_bytes +
+    (STp->buffer)->read_pointer) / STp->block_size -
+      ((STp->buffer)->read_pointer + STp->block_size - 1) /
+	STp->block_size;
+  (STp->buffer)->buffer_bytes = 0;
+  (STp->buffer)->read_pointer = 0;
+  result = 0;
+  if (!seek_next) {
+    if (STps->eof == ST_FM_HIT) {
+      result = cross_eof(STp, aSCpnt, FALSE); /* Back over the EOF hit */
+      if (!result)
+	  STps->eof = ST_NOEOF;
+      else {
+	  if (STps->drv_file >= 0)
+	      STps->drv_file++;
+	  STps->drv_block = 0;
+      }
+    }
+    if (!result && backspace > 0)	/* TODO -- design and run a test case for this */
+      result = osst_seek_logical_blk(STp, aSCpnt, STp->logical_blk_num - backspace);
+  }
+  else if (STps->eof == ST_FM_HIT) {
+    if (STps->drv_file >= 0)
+	STps->drv_file++;
+    STps->drv_block = 0;
+    STps->eof = ST_NOEOF;
+  }
+
+  return result;
+
+}
+
+
+/* Entry points to osst */
+
+/* Write command */
+static ssize_t osst_write(struct file * filp, const char * buf, size_t count, loff_t *ppos)
+{
+    struct inode *inode = filp->f_dentry->d_inode;
+    ssize_t total;
+    ssize_t i, do_count, blks, retval, transfer;
+    int write_threshold;
+    int doing_write = 0;
+    unsigned char cmd[MAX_COMMAND_SIZE];
+    const char *b_point;
+    Scsi_Cmnd * SCpnt = NULL;
+    OS_Scsi_Tape * STp;
+    ST_mode * STm;
+    ST_partstat * STps;
+    int dev = TAPE_NR(inode->i_rdev);
+
+    STp = os_scsi_tapes[dev];
+
+    /*
+     * If we are in the middle of error recovery, don't let anyone
+     * else try and use this device.  Also, if error recovery fails, it
+     * may try and take the device offline, in which case all further
+     * access to the device is prohibited.
+     */
+    if( !scsi_block_when_processing_errors(STp->device) ) {
+        return -ENXIO;
+    }
+    
+    if (ppos != &filp->f_pos) {
+      /* "A request was outside the capabilities of the device." */
+      return -ENXIO;
+    }
+
+    if (STp->ready != ST_READY) {
+      if (STp->ready == ST_NO_TAPE)
+	return (-ENOMEDIUM);
+      else
+        return (-EIO);
+    }
+    STm = &(STp->modes[STp->current_mode]);
+    if (!STm->defined)
+      return (-ENXIO);
+    if (count == 0)
+      return 0;
+
+    /*
+     * If there was a bus reset, block further access
+     * to this device.
+     */
+    if( STp->device->was_reset )
+      return (-EIO);
+
+#if DEBUG
+    if (!STp->in_use) {
+      printk(OSST_DEB_MSG "osst%d: Incorrect device.\n", dev);
+      return (-EIO);
+    }
+#endif
+
+    if (STp->write_prot)
+      return (-EACCES);
+
+    /* Write must be integral number of blocks */
+    if (STp->block_size != 0 && (count % STp->block_size) != 0) {
+	printk(KERN_WARNING "osst%d: Write (%d bytes) not multiple of tape block size (32k).\n",
+	       dev, count);
+	return (-EIO);
+    }
+
+    if (STp->first_frame_position >= STp->capacity - 164) {
+	printk(KERN_WARNING "osst%d: Write truncated at EOM early warning (frame %d).\n",
+	       dev, STp->first_frame_position);
+	return (-ENOSPC);
+    }
+
+    STps = &(STp->ps[STp->partition]);
+
+    if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED &&
+       !osst_int_ioctl(STp, &SCpnt, MTLOCK, 0))
+      STp->door_locked = ST_LOCKED_AUTO;
+
+    if (STps->rw == ST_READING) {
+      retval = osst_flush_buffer(STp, &SCpnt, 0);
+      if (retval) {
+	if (SCpnt) scsi_release_command(SCpnt);
+	return retval;
+      }
+      STps->rw = ST_IDLE;
+    }
+    else if (STps->rw != ST_WRITING) {
+      /* Are we totally rewriting this tape? */
+      if (!STp->header_ok || STp->first_frame_position == STp->first_data_ppos ||
+		            (STps->drv_file == 0 && STps->drv_block == 0)) {
+	STp->wrt_pass_cntr++;
+#if DEBUG
+	printk(OSST_DEB_MSG "osst%d: Allocating next write pass counter: %d\n",
+				  dev, STp->wrt_pass_cntr);
+#endif
+	osst_reset_header(STp, &SCpnt);
+	STps->drv_file = STps->drv_block = STp->logical_blk_num = 0;
+      }
+      /* Do we know where we'll be writing on the tape? */
+      else {
+	if ((STp->fast_open && osst_verify_position(STp, &SCpnt)) ||
+		STps->drv_file < 0 || STps->drv_block < 0) {
+	  if (STp->first_frame_position == STp->eod_frame_ppos) {
+	    STps->drv_file = STp->filemark_cnt;
+	    STps->drv_block = 0;
+	  }
+	  else {
+	    /* We have no idea where the tape is positioned - give up */
+#if DEBUG
+	    printk(OSST_DEB_MSG "osst%d: Cannot write at indeterminate position.\n", dev);
+#endif
+	    if (SCpnt) scsi_release_command(SCpnt);
+	    return (-EIO);
+	  }
+	}	  
+	if (STps->drv_file > 0 && STps->drv_file < STp->filemark_cnt) {
+	  STp->filemark_cnt = STps->drv_file;
+	  STp->last_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt-1]);
+	  printk(KERN_WARNING "osst%d: Overwriting file %d with old write pass counter %d\n",
+		      dev, STps->drv_file, STp->wrt_pass_cntr);
+	  printk(KERN_WARNING "osst%d: may lead to stale data being accepted on reading back!\n",
+		      dev);
+#if DEBUG
+	  printk(OSST_DEB_MSG "osst%d: resetting filemark count to %d and last mark ppos to %d\n",
+		dev, STp->filemark_cnt, STp->last_mark_ppos);
+#endif
+	}
+      }
+      STp->fast_open = FALSE;
+//printk(OSST_DEB_MSG "osst%d: Starting write next file\n",dev);
+    }
+    if (!STp->header_ok) {
+#if DEBUG
+      printk(OSST_DEB_MSG "osst%d: Write cannot proceed without valid headers\n", dev);
+#endif
+      if (SCpnt) scsi_release_command(SCpnt);
+      return (-EIO);
+    }
+    if ((STp->buffer)->writing) {
+if (SCpnt) printk(KERN_ERR "osst%d: Not supposed to have SCpnt at line %d\n", dev, __LINE__);
+      osst_write_behind_check(STp);
+      if ((STp->buffer)->last_result_fatal) {
+#if DEBUG
+	if (debugging)
+	  printk(OSST_DEB_MSG "osst%d: Async write error (write) %x.\n", dev,
+		 (STp->buffer)->last_result);
+#endif
+	if ((STp->buffer)->last_result == INT_MAX)
+	  STps->eof = ST_EOM_OK;
+	else
+	  STps->eof = ST_EOM_ERROR;
+      }
+    }
+    if (SCpnt) scsi_release_command(SCpnt);
+    SCpnt = NULL;
+    if (STps->eof == ST_EOM_OK)
+      return (-ENOSPC);
+    else if (STps->eof == ST_EOM_ERROR)
+      return (-EIO);
+
+    /* Check the buffer readability in cases where copy_user might catch
+       the problems after some tape movement. */
+    if ((copy_from_user(&i, buf, 1) != 0 ||
+	 copy_from_user(&i, buf + count - 1, 1) != 0))
+	return (-EFAULT);
+
+    if (!STm->do_buffer_writes) {
+#if 0
+      if (STp->block_size != 0 && (count % STp->block_size) != 0)
+	return (-EIO);   /* Write must be integral number of blocks */
+#endif
+      write_threshold = 1;
+    }
+    else
+      write_threshold = (STp->buffer)->buffer_blocks * STp->block_size;
+    if (!STm->do_async_writes)
+      write_threshold--;
+
+    total = count;
+
+    if ((!STp-> raw) && (STp->first_frame_position == 0xbae)) {
+#if DEBUG
+	printk(OSST_DEB_MSG "osst%d: Skipping over config partition.\n", dev);
+#endif
+	if (osst_flush_drive_buffer(STp, &SCpnt) < 0) {
+	    if (SCpnt) scsi_release_command(SCpnt);
+	    return (-EIO);
+	}
+	/* error recovery may have bumped us past the header partition */
+	if (osst_get_frame_position(STp, &SCpnt) < 0xbb8)
+	    osst_position_tape_and_confirm(STp, &SCpnt, 0xbb8);
+    }
+	
+    if (STp->poll)
+	retval = osst_wait_frame (STp, &SCpnt, STp->first_frame_position, -50, 60);
+    /* TODO: Check for an error ! */
+//osst_build_stats(STp, &SCpnt);	
+    memset(cmd, 0, MAX_COMMAND_SIZE);
+    cmd[0] = WRITE_6;
+    cmd[1] = 1;
+
+    STps->rw = ST_WRITING;
+    STp->write_type = OS_WRITE_DATA;
+
+#if DEBUG
+	printk(OSST_DEB_MSG "osst%d: Writing %d bytes to file %d block %d lblk %d frame %d\n",
+			  dev, count, STps->drv_file, STps->drv_block,
+			  STp->logical_blk_num, STp->first_frame_position);
+#endif
+
+    b_point = buf;
+    while ((STp->buffer)->buffer_bytes + count > write_threshold)
+    {
+      doing_write = 1;
+      do_count = (STp->buffer)->buffer_blocks * STp->block_size -
+	  (STp->buffer)->buffer_bytes;
+      if (do_count > count)
+	  do_count = count;
+
+      i = append_to_buffer(b_point, STp->buffer, do_count);
+      if (i) {
+	  if (SCpnt != NULL) {
+	      scsi_release_command(SCpnt);
+	      SCpnt = NULL;
+	  }
+	  return i;
+      }
+
+      transfer = OS_FRAME_SIZE;
+      blks     = 1;
+
+      osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->logical_blk_num++ );
+
+      cmd[2] = blks >> 16;
+      cmd[3] = blks >> 8;
+      cmd[4] = blks;
+
+      SCpnt = osst_do_scsi(SCpnt, STp, cmd, transfer, STp->timeout, MAX_WRITE_RETRIES, TRUE);
+      if (!SCpnt)
+	return (-EBUSY);
+
+      if ((STp->buffer)->last_result_fatal != 0) {
+#if DEBUG
+	if (debugging)
+	  printk(OSST_DEB_MSG "osst%d: Error on write:\n", dev);
+#endif
+	if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
+	    (SCpnt->sense_buffer[2] & 0x40)) {
+	  if ((SCpnt->sense_buffer[0] & 0x80) != 0)
+	    transfer = (SCpnt->sense_buffer[3] << 24) |
+		       (SCpnt->sense_buffer[4] << 16) |
+		       (SCpnt->sense_buffer[5] <<  8) | SCpnt->sense_buffer[6];
+	  else
+	    transfer = 0;
+	  transfer *= STp->block_size;
+	  if (transfer <= do_count) {
+	    filp->f_pos += do_count - transfer;
+	    count -= do_count - transfer;
+	    if (STps->drv_block >= 0) {
+		STps->drv_block += (do_count - transfer) / STp->block_size;
+	    }
+	    STps->eof = ST_EOM_OK;
+	    retval = (-ENOSPC); /* EOM within current request */
+#if DEBUG
+	    if (debugging)
+	      printk(OSST_DEB_MSG "osst%d: EOM with %d bytes unwritten.\n",
+		     dev, transfer);
+#endif
+	  }
+	  else {
+	    STps->eof = ST_EOM_ERROR;
+	    STps->drv_block = (-1);    /* Too cautious? */
+	    retval = (-EIO); /* EOM for old data */
+#if DEBUG
+	    if (debugging)
+	      printk(OSST_DEB_MSG "osst%d: EOM with lost data.\n", dev);
+#endif
+	  }
+	}
+	else {
+	  if (osst_write_error_recovery(STp, &SCpnt, 1) == 0) goto ok;
+	  STps->drv_block = (-1);    /* Too cautious? */
+	  retval = (-EIO);
+	}
+
+	scsi_release_command(SCpnt);
+	SCpnt = NULL;
+	(STp->buffer)->buffer_bytes = 0;
+	STp->dirty = 0;
+	if (count < total)
+	  return total - count;
+	else
+	  return retval;
+      }
+      STp->first_frame_position++;
+ok:
+      filp->f_pos += do_count;
+      b_point += do_count;
+      count -= do_count;
+      if (STps->drv_block >= 0) {
+	  STps->drv_block += blks;
+      }
+      STp->first_frame_position += blks;
+      (STp->buffer)->buffer_bytes = 0;
+      STp->dirty = 0;
+    }
+    if (count != 0) {
+      STp->dirty = 1;
+      i = append_to_buffer(b_point, STp->buffer, count);
+      if (i) {
+	  if (SCpnt != NULL) {
+	      scsi_release_command(SCpnt);
+	      SCpnt = NULL;
+	  }
+	  return i;
+      }
+      filp->f_pos += count;
+      count = 0;
+    }
+
+    if (doing_write && (STp->buffer)->last_result_fatal != 0) {
+      scsi_release_command(SCpnt);
+      SCpnt = NULL;
+      return (STp->buffer)->last_result_fatal;
+    }
+
+    if (STm->do_async_writes &&
+	((STp->buffer)->buffer_bytes >= STp->write_threshold &&
+	 (STp->buffer)->buffer_bytes >= OS_DATA_SIZE)      ) { 
+      /* Schedule an asynchronous write */
+      (STp->buffer)->writing = ((STp->buffer)->buffer_bytes /
+	  STp->block_size) * STp->block_size;
+      STp->dirty = !((STp->buffer)->writing ==
+		     (STp->buffer)->buffer_bytes);
+
+      transfer = OS_FRAME_SIZE;
+      blks     = 1;
+
+      osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->logical_blk_num++ );
+
+      cmd[2] = blks >> 16;
+      cmd[3] = blks >> 8;
+      cmd[4] = blks;
+#if DEBUG
+      STp->write_pending = 1;
+#endif
+
+      SCpnt = osst_do_scsi(SCpnt, STp, cmd, transfer, STp->timeout, MAX_WRITE_RETRIES, FALSE);
+      if (SCpnt == NULL)
+	  return (-EIO);
+    }
+    else if (SCpnt != NULL) {
+	scsi_release_command(SCpnt);
+	SCpnt = NULL;
+    }
+    STps->at_sm &= (total == 0);
+    if (total > 0)
+	STps->eof = ST_NOEOF;
+
+    return( total);
+}
+
+
+/* Read command */
+static ssize_t osst_read(struct file * filp, char * buf, size_t count, loff_t *ppos)
+{
+    struct inode * inode = filp->f_dentry->d_inode;
+    ssize_t total;
+    ssize_t i, transfer;
+    int special;
+    OS_Scsi_Tape * STp;
+    ST_mode * STm;
+    ST_partstat * STps;
+    Scsi_Cmnd *SCpnt = NULL;
+    int dev = TAPE_NR(inode->i_rdev);
+
+    STp = os_scsi_tapes[dev];
+
+    /*
+     * If we are in the middle of error recovery, don't let anyone
+     * else try and use this device.  Also, if error recovery fails, it
+     * may try and take the device offline, in which case all further
+     * access to the device is prohibited.
+     */
+    if( !scsi_block_when_processing_errors(STp->device) ) {
+        return -ENXIO;
+    }
+    
+    if (ppos != &filp->f_pos) {
+      /* "A request was outside the capabilities of the device." */
+      return -ENXIO;
+    }
+
+    if (STp->ready != ST_READY) {
+      if (STp->ready == ST_NO_TAPE)
+	return (-ENOMEDIUM);
+      else
+        return (-EIO);
+    }
+    STm = &(STp->modes[STp->current_mode]);
+    if (!STm->defined)
+      return (-ENXIO);
+#if DEBUG
+    if (!STp->in_use) {
+      printk(OSST_DEB_MSG "osst%d: Incorrect device.\n", dev);
+      return (-EIO);
+    }
+#endif
+    /* Must have initialized medium */
+    if (!STp->header_ok) return (-EIO);
+
+    if ((count % STp->block_size) != 0) {
+      printk(KERN_WARNING "osst%d: Use multiple of %d bytes as block size (%d requested)\n",
+			  dev, STp->block_size, count);
+      return (-EIO);	/* Read must be integral number of blocks */
+    }
+
+    if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED &&
+	!osst_int_ioctl(STp, &SCpnt, MTLOCK, 0))
+      STp->door_locked = ST_LOCKED_AUTO;
+
+    STps = &(STp->ps[STp->partition]);
+    if (STps->rw == ST_WRITING) {
+      transfer = osst_flush_buffer(STp, &SCpnt, 0);
+      if (SCpnt) scsi_release_command(SCpnt);
+      SCpnt = NULL;
+      if (transfer)
+	return transfer;
+      STps->rw = ST_IDLE;
+    }
+
+#if DEBUG
+    if (debugging && STps->eof != ST_NOEOF)
+      printk(OSST_DEB_MSG "osst%d: EOF/EOM flag up (%d). Bytes %d\n", dev,
+	     STps->eof, (STp->buffer)->buffer_bytes);
+#endif
+    if ((STp->buffer)->buffer_bytes == 0 &&
+	STps->eof >= ST_EOD_1) {
+	if (SCpnt) scsi_release_command(SCpnt);
+	if (STps->eof < ST_EOD) {
+	    STps->eof += 1;
+	    return 0;
+	}
+	return (-EIO);  /* EOM or Blank Check */
+    }
+
+    /* Check the buffer writability before any tape movement. Don't alter
+       buffer data. */
+    if (copy_from_user(&i, buf, 1) != 0 ||
+	copy_to_user(buf, &i, 1) != 0 ||
+	copy_from_user(&i, buf + count - 1, 1) != 0 ||
+	copy_to_user(buf + count - 1, &i, 1) != 0) {
+	if (SCpnt) scsi_release_command(SCpnt);
+	return (-EFAULT);
+    }
+
+    /* Loop until enough data in buffer or a special condition found */
+    for (total = 0, special = 0; total < count && !special; ) {
+
+      /* Get new data if the buffer is empty */
+      if ((STp->buffer)->buffer_bytes == 0) {
+	  special = osst_get_logical_blk(STp, &SCpnt, STp->logical_blk_num, 0);
+	  STp->buffer->buffer_bytes = special ? 0 : OS_DATA_SIZE; 
+	  STp->buffer->read_pointer = 0;
+	  STp->logical_blk_num++;		/* block to look for next time */
+	  STp->logical_blk_in_buffer = 0;
+	  if (special < 0) { 			/* No need to continue read */
+	      if (SCpnt) scsi_release_command(SCpnt);
+	      return special;
+          }
+	  STps->drv_block++;
+      }
+
+      /* Move the data from driver buffer to user buffer */
+      if ((STp->buffer)->buffer_bytes > 0) {
+#if DEBUG
+	if (debugging && STps->eof != ST_NOEOF)
+	  printk(OSST_DEB_MSG "osst%d: EOF up (%d). Left %d, needed %d.\n", dev,
+		 STps->eof, (STp->buffer)->buffer_bytes, count - total);
+#endif
+	transfer = (STp->buffer)->buffer_bytes < count - total ?
+	  (STp->buffer)->buffer_bytes : count - total;
+	i = from_buffer(STp->buffer, buf, transfer);
+	if (i) {
+	    if (SCpnt) scsi_release_command(SCpnt);
+	    return i;
+	}
+	filp->f_pos += transfer;
+	buf += transfer;
+	total += transfer;
+      }
+
+    } /* for (total = 0, special = 0; total < count && !special; ) */
+    if (SCpnt) scsi_release_command(SCpnt);
+
+    /* Change the eof state if no data from tape or buffer */
+    if (total == 0) {
+	if (STps->eof == ST_FM_HIT) {
+	    STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_FM;
+	    STps->drv_block = 0;
+	    if (STps->drv_file >= 0)
+		STps->drv_file++;
+	}
+	else if (STps->eof == ST_EOD_1) {
+	    STps->eof = ST_EOD_2;
+	    if (STps->drv_block > 0 && STps->drv_file >= 0)
+		STps->drv_file++;
+	    STps->drv_block = 0;
+	}
+	else if (STps->eof == ST_EOD_2)
+	    STps->eof = ST_EOD;
+    }
+    else if (STps->eof == ST_FM)
+	STps->eof = ST_NOEOF;
+
+    return total;
+}
+
+
+/* Set the driver options */
+static void osst_log_options(OS_Scsi_Tape *STp, ST_mode *STm, int dev)
+{
+  printk(KERN_INFO
+"osst%d: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n",
+	 dev, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes,
+	 STm->do_read_ahead);
+  printk(KERN_INFO
+"osst%d:    can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n",
+	 dev, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock);
+  printk(KERN_INFO
+"osst%d:    defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n",
+	 dev, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions,
+	 STp->scsi2_logical);
+  printk(KERN_INFO
+"osst%d:    sysv: %d\n", dev, STm->sysv);
+#if DEBUG
+  printk(KERN_INFO
+	 "osst%d:    debugging: %d\n",
+	 dev, debugging);
+#endif
+}
+
+
+static int osst_set_options(OS_Scsi_Tape *STp, long options)
+{
+  int value;
+  long code;
+  ST_mode *STm;
+  int dev = TAPE_NR(STp->devt);
+
+  STm = &(STp->modes[STp->current_mode]);
+  if (!STm->defined) {
+    memcpy(STm, &(STp->modes[0]), sizeof(ST_mode));
+    modes_defined = TRUE;
+#if DEBUG
+    if (debugging)
+      printk(OSST_DEB_MSG "osst%d: Initialized mode %d definition from mode 0\n",
+	     dev, STp->current_mode);
+#endif
+  }
+
+  code = options & MT_ST_OPTIONS;
+  if (code == MT_ST_BOOLEANS) {
+    STm->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0;
+    STm->do_async_writes  = (options & MT_ST_ASYNC_WRITES) != 0;
+    STm->defaults_for_writes = (options & MT_ST_DEF_WRITES) != 0;
+    STm->do_read_ahead    = (options & MT_ST_READ_AHEAD) != 0;
+    STp->two_fm		  = (options & MT_ST_TWO_FM) != 0;
+    STp->fast_mteom	  = (options & MT_ST_FAST_MTEOM) != 0;
+    STp->do_auto_lock     = (options & MT_ST_AUTO_LOCK) != 0;
+    STp->can_bsr          = (options & MT_ST_CAN_BSR) != 0;
+    STp->omit_blklims	  = (options & MT_ST_NO_BLKLIMS) != 0;
+    if ((STp->device)->scsi_level >= SCSI_2)
+      STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0;
+    STp->scsi2_logical    = (options & MT_ST_SCSI2LOGICAL) != 0;
+    STm->sysv		  = (options & MT_ST_SYSV) != 0;
+#if DEBUG
+    debugging = (options & MT_ST_DEBUGGING) != 0;
+#endif
+    osst_log_options(STp, STm, dev);
+  }
+  else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) {
+    value = (code == MT_ST_SETBOOLEANS);
+    if ((options & MT_ST_BUFFER_WRITES) != 0)
+      STm->do_buffer_writes = value;
+    if ((options & MT_ST_ASYNC_WRITES) != 0)
+      STm->do_async_writes = value;
+    if ((options & MT_ST_DEF_WRITES) != 0)
+      STm->defaults_for_writes = value;
+    if ((options & MT_ST_READ_AHEAD) != 0)
+      STm->do_read_ahead = value;
+    if ((options & MT_ST_TWO_FM) != 0)
+      STp->two_fm = value;
+    if ((options & MT_ST_FAST_MTEOM) != 0)
+      STp->fast_mteom = value;
+    if ((options & MT_ST_AUTO_LOCK) != 0)
+      STp->do_auto_lock = value;
+    if ((options & MT_ST_CAN_BSR) != 0)
+      STp->can_bsr = value;
+    if ((options & MT_ST_NO_BLKLIMS) != 0)
+      STp->omit_blklims = value;
+    if ((STp->device)->scsi_level >= SCSI_2 &&
+	(options & MT_ST_CAN_PARTITIONS) != 0)
+      STp->can_partitions = value;
+    if ((options & MT_ST_SCSI2LOGICAL) != 0)
+      STp->scsi2_logical = value;
+    if ((options & MT_ST_SYSV) != 0)
+      STm->sysv = value;
+#if DEBUG
+    if ((options & MT_ST_DEBUGGING) != 0)
+      debugging = value;
+#endif
+    osst_log_options(STp, STm, dev);
+  }
+  else if (code == MT_ST_WRITE_THRESHOLD) {
+    value = (options & ~MT_ST_OPTIONS) * ST_KILOBYTE;
+    if (value < 1 || value > osst_buffer_size) {
+      printk(KERN_WARNING "osst%d: Write threshold %d too small or too large.\n",
+	     dev, value);
+      return (-EIO);
+    }
+    STp->write_threshold = value;
+    printk(KERN_INFO "osst%d: Write threshold set to %d bytes.\n",
+	   dev, value);
+  }
+  else if (code == MT_ST_DEF_BLKSIZE) {
+    value = (options & ~MT_ST_OPTIONS);
+    if (value == ~MT_ST_OPTIONS) {
+      STm->default_blksize = (-1);
+      printk(KERN_INFO "osst%d: Default block size disabled.\n", dev);
+    }
+    else {
+      STm->default_blksize = value;
+      printk(KERN_INFO "osst%d: Default block size set to %d bytes.\n",
+	     dev, STm->default_blksize);
+    }
+  }
+  else if (code == MT_ST_TIMEOUTS) {
+    value = (options & ~MT_ST_OPTIONS);
+    if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) {
+      STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ;
+      printk(KERN_INFO "osst%d: Long timeout set to %d seconds.\n", dev,
+	     (value & ~MT_ST_SET_LONG_TIMEOUT));
+    }
+    else {
+      STp->timeout = value * HZ;
+      printk(KERN_INFO "osst%d: Normal timeout set to %d seconds.\n", dev,
+	     value);
+    }
+  }
+  else if (code == MT_ST_DEF_OPTIONS) {
+    code = (options & ~MT_ST_CLEAR_DEFAULT);
+    value = (options & MT_ST_CLEAR_DEFAULT);
+    if (code == MT_ST_DEF_DENSITY) {
+      if (value == MT_ST_CLEAR_DEFAULT) {
+	STm->default_density = (-1);
+	printk(KERN_INFO "osst%d: Density default disabled.\n", dev);
+      }
+      else {
+	STm->default_density = value & 0xff;
+	printk(KERN_INFO "osst%d: Density default set to %x\n",
+	       dev, STm->default_density);
+      }
+    }
+    else if (code == MT_ST_DEF_DRVBUFFER) {
+      if (value == MT_ST_CLEAR_DEFAULT) {
+	STp->default_drvbuffer = 0xff;
+	printk(KERN_INFO "osst%d: Drive buffer default disabled.\n", dev);
+      }
+      else {
+	STp->default_drvbuffer = value & 7;
+	printk(KERN_INFO "osst%d: Drive buffer default set to %x\n",
+	       dev, STp->default_drvbuffer);
+      }
+    }
+    else if (code == MT_ST_DEF_COMPRESSION) {
+      if (value == MT_ST_CLEAR_DEFAULT) {
+	STm->default_compression = ST_DONT_TOUCH;
+	printk(KERN_INFO "osst%d: Compression default disabled.\n", dev);
+      }
+      else {
+	STm->default_compression = (value & 1 ? ST_YES : ST_NO);
+	printk(KERN_INFO "osst%d: Compression default set to %x\n",
+	       dev, (value & 1));
+      }
+    }
+  }
+  else
+    return (-EIO);
+
+  return 0;
+}
+
+
+/* Internal ioctl function */
+static int osst_int_ioctl(OS_Scsi_Tape * STp, Scsi_Cmnd ** aSCpnt, unsigned int cmd_in, unsigned long arg)
+{
+   int timeout;
+   long ltmp;
+   int i, ioctl_result;
+   int chg_eof = TRUE;
+   unsigned char cmd[MAX_COMMAND_SIZE];
+   Scsi_Cmnd * SCpnt = *aSCpnt;
+   ST_partstat * STps;
+   int fileno, blkno, at_sm, datalen;
+   int logical_blk_num;
+   int dev = TAPE_NR(STp->devt);
+
+   if (STp->ready != ST_READY && cmd_in != MTLOAD) {
+     if (STp->ready == ST_NO_TAPE)
+       return (-ENOMEDIUM);
+     else
+       return (-EIO);
+   }
+   timeout = STp->long_timeout;
+   STps = &(STp->ps[STp->partition]);
+   fileno = STps->drv_file;
+   blkno = STps->drv_block;
+   at_sm = STps->at_sm;
+   logical_blk_num = STp->logical_blk_num;
+
+   memset(cmd, 0, MAX_COMMAND_SIZE);
+   datalen = 0;
+   switch (cmd_in) {
+     case MTFSFM:
+	chg_eof = FALSE; /* Changed from the FSF after this */
+     case MTFSF:
+	if (STp->raw)
+	   return (-EIO);
+	if (STp->linux_media)
+	   ioctl_result = osst_space_over_filemarks_forward_fast(STp, &SCpnt, cmd_in, arg);
+	else
+	   ioctl_result = osst_space_over_filemarks_forward_slow(STp, &SCpnt, cmd_in, arg);
+	logical_blk_num = STp->logical_blk_num;
+	if (fileno >= 0)
+	   fileno += arg;
+	blkno = 0;
+	at_sm &= (arg == 0);
+	goto os_bypass;
+
+     case MTBSF:
+	chg_eof = FALSE; /* Changed from the FSF after this */
+     case MTBSFM:
+	if (STp->raw)
+	   return (-EIO);
+	ioctl_result = osst_space_over_filemarks_backward(STp, &SCpnt, cmd_in, arg);
+	logical_blk_num = STp->logical_blk_num;
+	if (fileno >= 0)
+	   fileno -= arg;
+	blkno = (-1);  /* We can't know the block number */
+	at_sm &= (arg == 0);
+	goto os_bypass;
+
+     case MTFSR:
+     case MTBSR:
+#if DEBUG
+	if (debugging)
+	   printk(OSST_DEB_MSG "osst%i: Skipping %lu blocks %s from logical block %d\n",
+				dev, arg, cmd_in==MTFSR?"forward":"backward", logical_blk_num);
+#endif
+	if (cmd_in == MTFSR) {
+	   logical_blk_num += arg;
+	   if (blkno >= 0) blkno += arg;
+	}
+	else {
+	   logical_blk_num -= arg;
+	   if (blkno >= 0) blkno -= arg;
+	}
+	ioctl_result = osst_seek_logical_blk(STp, &SCpnt, logical_blk_num-1);
+	STp->logical_blk_in_buffer = 0;
+	at_sm &= (arg == 0);
+	goto os_bypass;
+
+     case MTFSS:
+       cmd[0] = SPACE;
+       cmd[1] = 0x04; /* Space Setmarks */   /* FIXME -- OS can't do this? */
+       cmd[2] = (arg >> 16);
+       cmd[3] = (arg >> 8);
+       cmd[4] = arg;
+#if DEBUG
+       if (debugging)
+	 printk(OSST_DEB_MSG "osst%d: Spacing tape forward %d setmarks.\n", dev,
+		cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
+#endif
+       if (arg != 0) {
+	 blkno = fileno = (-1);
+	 at_sm = 1;
+       }
+       break;
+     case MTBSS:
+       cmd[0] = SPACE;
+       cmd[1] = 0x04; /* Space Setmarks */   /* FIXME -- OS can't do this? */
+       ltmp = (-arg);
+       cmd[2] = (ltmp >> 16);
+       cmd[3] = (ltmp >> 8);
+       cmd[4] = ltmp;
+#if DEBUG
+       if (debugging) {
+	 if (cmd[2] & 0x80)
+	   ltmp = 0xff000000;
+	 ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
+	 printk(OSST_DEB_MSG "osst%d: Spacing tape backward %ld setmarks.\n",
+		dev, (-ltmp));
+       }
+#endif
+       if (arg != 0) {
+	 blkno = fileno = (-1);
+	 at_sm = 1;
+       }
+       break;
+     case MTWEOF:
+       if ( STps->rw == ST_WRITING && !(STp->device)->was_reset)
+         ioctl_result = osst_flush_write_buffer(STp, &SCpnt, 1);
+       else
+	 ioctl_result = 0;
+       for (i=0; i<arg; i++)
+         ioctl_result |= osst_write_filemark(STp, &SCpnt);
+       logical_blk_num = STp->logical_blk_num;
+       if (fileno >= 0) fileno += arg;
+       if (blkno  >= 0) blkno   = 0;
+       goto os_bypass;
+
+     case MTWSM:
+       if (STp->write_prot)
+	 return (-EACCES);
+       if (!STp->raw)
+	 return 0;
+       cmd[0] = WRITE_FILEMARKS;   /* FIXME -- need OS version */
+       if (cmd_in == MTWSM)
+	 cmd[1] = 2;
+       cmd[2] = (arg >> 16);
+       cmd[3] = (arg >> 8);
+       cmd[4] = arg;
+       timeout = STp->timeout;
+#if DEBUG
+       if (debugging) {
+	 if (cmd_in == MTWEOF)
+	   printk(OSST_DEB_MSG "osst%d: Writing %d filemarks.\n", dev,
+		  cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
+	 else
+	   printk(OSST_DEB_MSG "osst%d: Writing %d setmarks.\n", dev,
+		  cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
+       }
+#endif
+       if (fileno >= 0)
+	 fileno += arg;
+       blkno = 0;
+       at_sm = (cmd_in == MTWSM);
+       break;
+     case MTOFFL:
+     case MTLOAD:
+     case MTUNLOAD:
+     case MTRETEN:
+       cmd[0] = START_STOP;
+	 cmd[1] = 1;		/* Don't wait for completion */
+       if (cmd_in == MTLOAD)
+	 cmd[4] = 1;		/* load */
+       if (cmd_in == MTRETEN)
+	 cmd[4] = 3;		/* retension then mount */
+       if (cmd_in == MTOFFL)
+	 cmd[4] = 4;		/* rewind then eject */
+       timeout = STp->timeout;
+#if DEBUG
+       if (debugging) {
+	 switch (cmd_in) {
+	     case MTUNLOAD:
+		 printk(OSST_DEB_MSG "osst%d: Unloading tape.\n", dev);
+		 break;
+	     case MTLOAD:
+		 printk(OSST_DEB_MSG "osst%d: Loading tape.\n", dev);
+		 break;
+	     case MTRETEN:
+		 printk(OSST_DEB_MSG "osst%d: Retensioning tape.\n", dev);
+		 break;
+	     case MTOFFL:
+		 printk(OSST_DEB_MSG "osst%d: Ejecting tape.\n", dev);
+		 break;
+	 }
+       }
+#endif
+       fileno = blkno = at_sm = logical_blk_num = 0 ;
+       break;
+     case MTNOP:
+#if DEBUG
+       if (debugging)
+	 printk(OSST_DEB_MSG "osst%d: No op on tape.\n", dev);
+#endif
+       return 0;  /* Should do something ? */
+       break;
+     case MTEOM:
+#if DEBUG
+	if (debugging)
+	   printk(OSST_DEB_MSG "osst%d: Spacing to end of recorded medium.\n", dev);
+#endif
+	osst_set_frame_position(STp, &SCpnt, STp->eod_frame_ppos, 0);
+	if (osst_get_logical_blk(STp, &SCpnt, -1, 0) < 0) {
+	   ioctl_result = -EIO;
+	   goto os_bypass;
+	}
+	if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_EOD) {
+#if DEBUG
+	   printk(OSST_DEB_MSG "osst%d: No EOD frame found where expected.\n", dev);
+#endif
+     	   ioctl_result = -EIO;
+	   goto os_bypass;
+	}
+	ioctl_result = osst_set_frame_position(STp, &SCpnt, STp->eod_frame_ppos, 0);
+	logical_blk_num = STp->logical_blk_num;
+	fileno          = STp->filemark_cnt;
+	blkno  = at_sm  = 0;
+	goto os_bypass;
+
+     case MTERASE:
+	if (STp->write_prot)
+	   return (-EACCES);
+	ioctl_result = osst_reset_header(STp, &SCpnt);
+	i = osst_write_eod(STp, &SCpnt);
+	if (i < ioctl_result) ioctl_result = i;
+	i = osst_position_tape_and_confirm(STp, &SCpnt, STp->eod_frame_ppos);
+	if (i < ioctl_result) ioctl_result = i;
+	fileno = blkno = at_sm = logical_blk_num = 0 ;
+	goto os_bypass;
+
+     case MTREW:
+	cmd[0] = REZERO_UNIT; /* rewind */
+	cmd[1] = 1;
+#if DEBUG
+	if (debugging)
+	   printk(OSST_DEB_MSG "osst%d: Rewinding tape, Immed=%d.\n", dev, cmd[1]);
+#endif
+	fileno = blkno = at_sm = logical_blk_num = 0 ;
+	break;
+
+     case MTLOCK:
+	chg_eof = FALSE;
+	cmd[0] = ALLOW_MEDIUM_REMOVAL;
+	cmd[4] = SCSI_REMOVAL_PREVENT;
+#if DEBUG
+	if (debugging)
+	    printk(OSST_DEB_MSG "osst%d: Locking drive door.\n", dev);
+#endif;
+	break;
+
+     case MTUNLOCK:
+	chg_eof = FALSE;
+	cmd[0] = ALLOW_MEDIUM_REMOVAL;
+	cmd[4] = SCSI_REMOVAL_ALLOW;
+#if DEBUG
+	if (debugging)
+	   printk(OSST_DEB_MSG "osst%d: Unlocking drive door.\n", dev);
+#endif;
+	break;
+
+     case MTSETBLK:           /* Set block length */
+     case MTSETDENSITY:       /* Set tape density */
+     case MTSETDRVBUFFER:     /* Set drive buffering */
+     case SET_DENS_AND_BLK:   /* Set density and block size */
+       chg_eof = FALSE;
+       if (STp->dirty || (STp->buffer)->buffer_bytes != 0)
+	 return (-EIO);       /* Not allowed if data in buffer */
+       if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) &&
+	   (arg & MT_ST_BLKSIZE_MASK) != 0 &&
+	   ((arg & MT_ST_BLKSIZE_MASK) < STp->min_block ||
+	    (arg & MT_ST_BLKSIZE_MASK) > STp->max_block ||
+	    (arg & MT_ST_BLKSIZE_MASK) > osst_buffer_size)) {
+	 printk(KERN_WARNING "osst%d: Illegal block size.\n", dev);
+	 return (-EINVAL);
+       }
+       return 0;  /* silently ignore if block size didn't change */
+
+     default:
+	return (-ENOSYS);
+   }
+
+   SCpnt = osst_do_scsi(SCpnt, STp, cmd, datalen, timeout, MAX_RETRIES, TRUE);
+   if (!SCpnt) {
+#if DEBUG
+      printk(OSST_DEB_MSG "osst%d: Couldn't exec scsi cmd for IOCTL\n", dev);
+#endif
+      return (-EBUSY);
+   }
+
+   ioctl_result = (STp->buffer)->last_result_fatal;
+
+os_bypass:
+#if DEBUG
+   if (debugging)
+      printk(OSST_DEB_MSG "osst%d: IOCTL (%d) Result=%d\n", dev, cmd_in, ioctl_result);
+#endif
+
+   if (!ioctl_result) {  /* SCSI command successful */
+
+      if (cmd_in == MTFSFM) {
+	 fileno--;
+	 blkno--;
+      }
+      if (cmd_in == MTBSFM) {
+	 fileno++;
+	 blkno++;
+      }
+      STps->drv_block = blkno;
+      STps->drv_file = fileno;
+      STps->at_sm = at_sm;
+      STp->logical_blk_num = logical_blk_num;
+
+      if (cmd_in == MTLOCK)
+         STp->door_locked = ST_LOCKED_EXPLICIT;
+      else if (cmd_in == MTUNLOCK)
+         STp->door_locked = ST_UNLOCKED;
+
+      if (cmd_in == MTEOM)
+         STps->eof = ST_EOD;
+      else if (cmd_in == MTFSF)
+	 STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_FM;
+      else if (chg_eof)
+         STps->eof = ST_NOEOF;
+
+      if (cmd_in == MTOFFL || cmd_in == MTUNLOAD)
+         STp->rew_at_close = 0;
+      else if (cmd_in == MTLOAD) {
+/*       STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0;  FIXME */
+	 for (i=0; i < ST_NBR_PARTITIONS; i++) {
+	    STp->ps[i].rw = ST_IDLE;
+	    STp->ps[i].last_block_valid = FALSE;
+	 }
+	 STp->partition = 0;
+      }
+
+      if (cmd_in == MTREW) {
+	ioctl_result = osst_position_tape_and_confirm(STp, &SCpnt, STp->first_data_ppos); 
+        if (ioctl_result > 0)
+            ioctl_result = 0;
+      }
+
+   } else if (cmd_in == MTBSF || cmd_in == MTBSFM ) {
+      if (osst_position_tape_and_confirm(STp, &SCpnt, STp->first_data_ppos) < 0)
+	  STps->drv_file = STps->drv_block = -1;
+      else
+	  STps->drv_file = STps->drv_block = 0;
+      STps->eof = ST_NOEOF;
+   } else if (cmd_in == MTFSF || cmd_in == MTFSFM) {
+      if (osst_position_tape_and_confirm(STp, &SCpnt, STp->eod_frame_ppos) < 0)
+	  STps->drv_file = STps->drv_block = -1;
+      else {
+	  STps->drv_file  = STp->filemark_cnt;
+	  STps->drv_block = 0;
+      }
+      STps->eof = ST_EOD;
+   } else if (cmd_in == MTBSR || cmd_in == MTFSR || cmd_in == MTWEOF || cmd_in == MTEOM) {
+      STps->drv_file = STps->drv_block = (-1);
+      STps->eof = ST_NOEOF;
+      STp->header_ok = 0;
+   } else if (cmd_in == MTERASE) {
+      STp->header_ok = 0;
+   } else if (SCpnt) {  /* SCSI command was not completely successful. */
+      if (SCpnt->sense_buffer[2] & 0x40) {
+	 STps->eof = ST_EOM_OK;
+	 STps->drv_block = 0;
+      }
+      if (chg_eof)
+         STps->eof = ST_NOEOF;
+
+      if ((SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK)
+	 STps->eof = ST_EOD;
+
+      if (cmd_in == MTLOCK)
+	 STp->door_locked = ST_LOCK_FAILS;
+
+   }
+   *aSCpnt = SCpnt;
+
+   return ioctl_result;
+}
+
+
+/* Open the device */
+static int os_scsi_tape_open(struct inode * inode, struct file * filp)
+{
+    unsigned short flags;
+    int i, b_size, need_dma_buffer, new_session = FALSE;
+    unsigned char cmd[MAX_COMMAND_SIZE];
+    Scsi_Cmnd * SCpnt;
+    OS_Scsi_Tape * STp;
+    ST_mode * STm;
+    ST_partstat * STps;
+    int dev = TAPE_NR(inode->i_rdev);
+    int mode = TAPE_MODE(inode->i_rdev);
+
+    if (dev >= osst_template.dev_max || (STp = os_scsi_tapes[dev]) == NULL || !STp->device)
+      return (-ENXIO);
+
+    if( !scsi_block_when_processing_errors(STp->device) ) {
+        return -ENXIO;
+    }
+
+    if (STp->in_use) {
+#if DEBUG
+      printk(OSST_DEB_MSG "osst%d: Device already in use.\n", dev);
+#endif
+      return (-EBUSY);
+    }
+    STp->in_use       = 1;
+    STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0;
+
+    if (STp->device->host->hostt->module)
+       __MOD_INC_USE_COUNT(STp->device->host->hostt->module);
+    if (osst_template.module)
+       __MOD_INC_USE_COUNT(osst_template.module);
+
+    if (mode != STp->current_mode) {
+#if DEBUG
+      if (debugging)
+	printk(OSST_DEB_MSG "osst%d: Mode change from %d to %d.\n",
+	       dev, STp->current_mode, mode);
+#endif
+      new_session = TRUE;
+      STp->current_mode = mode;
+    }
+    STm = &(STp->modes[STp->current_mode]);
+
+    flags = filp->f_flags;
+    STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY);
+
+    STp->raw = (MINOR(inode->i_rdev) & 0x40) != 0;
+
+    /* Allocate a buffer for this user */
+    need_dma_buffer = STp->restr_dma;
+    for (i=0; i < osst_nbr_buffers; i++)
+      if (!osst_buffers[i]->in_use &&
+	  (!need_dma_buffer || osst_buffers[i]->dma))
+	break;
+    if (i >= osst_nbr_buffers) {
+      STp->buffer = new_tape_buffer(FALSE, need_dma_buffer);
+      if (STp->buffer == NULL) {
+	printk(KERN_WARNING "osst%d: Can't allocate tape buffer.\n", dev);
+	STp->in_use = 0;
+	if (STp->device->host->hostt->module)
+	    __MOD_DEC_USE_COUNT(STp->device->host->hostt->module);
+	if(osst_template.module)
+	    __MOD_DEC_USE_COUNT(osst_template.module);
+	return (-EBUSY);
+      }
+    }
+    else
+      STp->buffer = osst_buffers[i];
+    (STp->buffer)->in_use = 1;
+    (STp->buffer)->writing = 0;
+    (STp->buffer)->last_result_fatal = 0;
+    (STp->buffer)->use_sg = STp->device->host->sg_tablesize;
+
+    /* Compute the usable buffer size for this SCSI adapter */
+    if (!(STp->buffer)->use_sg)
+	(STp->buffer)->buffer_size = (STp->buffer)->sg[0].length;
+    else {
+	for (i=0, (STp->buffer)->buffer_size = 0; i < (STp->buffer)->use_sg &&
+		 i < (STp->buffer)->sg_segs; i++)
+	    (STp->buffer)->buffer_size += (STp->buffer)->sg[i].length;
+    }
+
+    STp->dirty = 0;
+    for (i=0; i < ST_NBR_PARTITIONS; i++) {
+	STps = &(STp->ps[i]);
+	STps->rw = ST_IDLE;
+    }
+    STp->ready = ST_READY;
+    STp->recover_count = 0;
+#if DEBUG
+    STp->nbr_waits = STp->nbr_finished = 0;
+#endif
+    memset (cmd, 0, MAX_COMMAND_SIZE);
+    cmd[0] = TEST_UNIT_READY;
+
+    SCpnt = osst_do_scsi(NULL, STp, cmd, 0, STp->timeout, MAX_READY_RETRIES, TRUE);
+    if (!SCpnt) {
+        STp->buffer->in_use = 0;
+        STp->buffer = NULL;
+        STp->in_use = 0;
+
+	if (STp->device->host->hostt->module)
+	    __MOD_DEC_USE_COUNT(STp->device->host->hostt->module);
+	if (osst_template.module)
+	    __MOD_DEC_USE_COUNT(osst_template.module);
+	return (-EBUSY);
+    }
+    if ((SCpnt->sense_buffer[0] & 0x70) == 0x70      &&
+	(SCpnt->sense_buffer[2] & 0x0f) == NOT_READY &&
+	 SCpnt->sense_buffer[12]        == 4         ) {
+#if DEBUG
+      printk(OSST_DEB_MSG "osst%d: Unit not ready, cause %x\n", dev, SCpnt->sense_buffer[13]);
+#endif
+      if (SCpnt->sense_buffer[13] == 2) {	/* initialize command required (LOAD) */
+	memset (cmd, 0, MAX_COMMAND_SIZE);
+        cmd[0] = START_STOP;
+	cmd[1] = 1;
+	cmd[4] = 1;
+        SCpnt = osst_do_scsi(SCpnt, STp, cmd, 0, STp->timeout, MAX_READY_RETRIES, TRUE);
+      }
+      osst_wait_ready(STp, &SCpnt, (SCpnt->sense_buffer[13]==1?15:3) * 60);
+    }
+    if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
+	(SCpnt->sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */
+#if DEBUG
+      printk(OSST_DEB_MSG "osst%d: Unit wants attention\n", dev);
+#endif
+      STp->header_ok = 0;
+
+      for (i=0; i < 10; i++) {
+
+        memset (cmd, 0, MAX_COMMAND_SIZE);
+        cmd[0] = TEST_UNIT_READY;
+
+        SCpnt = osst_do_scsi(SCpnt, STp, cmd, 0, STp->timeout, MAX_READY_RETRIES, TRUE);
+        if ((SCpnt->sense_buffer[0] & 0x70) != 0x70 ||
+            (SCpnt->sense_buffer[2] & 0x0f) != UNIT_ATTENTION)
+            break;
+      }
+
+      STp->device->was_reset = 0;
+      STp->partition = STp->new_partition = 0;
+      if (STp->can_partitions)
+	STp->nbr_partitions = 1;  /* This guess will be updated later if necessary */
+      for (i=0; i < ST_NBR_PARTITIONS; i++) {
+	  STps = &(STp->ps[i]);
+	  STps->rw = ST_IDLE;
+	  STps->eof = ST_NOEOF;
+	  STps->at_sm = 0;
+	  STps->last_block_valid = FALSE;
+	  STps->drv_block = 0;
+	  STps->drv_file = 0 ;
+      }
+      new_session = TRUE;
+    }
+    /*
+     * if we have valid headers from before, and the drive/tape seem untouched,
+     * open without reconfiguring and re-reading the headers
+     */
+    if (!STp->buffer->last_result_fatal && STp->header_ok &&
+        !SCpnt->result && SCpnt->sense_buffer[0] == 0       ) {
+
+      memset(cmd, 0, MAX_COMMAND_SIZE);
+      cmd[0] = MODE_SENSE;
+      cmd[1] = 8;
+      cmd[2] = VENDOR_IDENT_PAGE;
+      cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH;
+
+      SCpnt = osst_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE);
+
+      if (STp->buffer->last_result_fatal                     ||
+	  STp->buffer->b_data[MODE_HEADER_LENGTH + 2] != 'L' ||
+	  STp->buffer->b_data[MODE_HEADER_LENGTH + 3] != 'I' ||
+	  STp->buffer->b_data[MODE_HEADER_LENGTH + 4] != 'N' ||
+	  STp->buffer->b_data[MODE_HEADER_LENGTH + 5] != '4'  ) {
+#if DEBUG
+	printk(OSST_DEB_MSG "osst%d: signature was changed to %c%c%c%c\n", dev,
+			  STp->buffer->b_data[MODE_HEADER_LENGTH + 2],
+			  STp->buffer->b_data[MODE_HEADER_LENGTH + 3],
+			  STp->buffer->b_data[MODE_HEADER_LENGTH + 4],
+			  STp->buffer->b_data[MODE_HEADER_LENGTH + 5]);
+#endif
+	STp->header_ok = 0;
+      }
+      i = STp->first_frame_position;
+      if (STp->header_ok && i == osst_get_frame_position(STp, &SCpnt)) {
+	if (STp->door_locked == ST_UNLOCKED) {
+	  if (osst_int_ioctl(STp, &SCpnt, MTLOCK, 0))
+	    printk(KERN_WARNING "osst%d: Can't lock drive door\n", dev);
+	  else
+	    STp->door_locked = ST_LOCKED_AUTO;
+	}
+	STp->fast_open = TRUE;
+	scsi_release_command(SCpnt);
+	return 0;
+      }
+#if DEBUG
+      if (i != STp->first_frame_position)
+	printk(OSST_DEB_MSG "osst%d: tape position changed from %d to %d\n", dev, i, STp->first_frame_position);
+#endif
+      STp->header_ok = 0;
+    }
+    STp->fast_open = FALSE;
+
+    if ((STp->buffer)->last_result_fatal != 0 &&   /* in all error conditions except no medium */
+	(SCpnt->sense_buffer[2] != 2 || SCpnt->sense_buffer[12] != 0x3A) ) {
+
+      memset(cmd, 0, MAX_COMMAND_SIZE);
+      cmd[0] = MODE_SELECT;
+      cmd[1] = 0x10;
+      cmd[4] = 4 + MODE_HEADER_LENGTH;
+
+      (STp->buffer)->b_data[0] = cmd[4] - 1;
+      (STp->buffer)->b_data[1] = 0;			/* Medium Type - ignoring */
+      (STp->buffer)->b_data[2] = 0;			/* Reserved */
+      (STp->buffer)->b_data[3] = 0;			/* Block Descriptor Length */
+      (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = 0x3f;
+      (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 1;
+      (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 2;
+      (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 3;
+
+#if 1 //DEBUG
+      printk(OSST_DEB_MSG "osst%i: Applying soft reset\n", dev);
+#endif
+      SCpnt = osst_do_scsi(SCpnt, STp, cmd, cmd[4], STp->timeout, 0, TRUE);
+
+      STp->header_ok = 0;
+
+      for (i=0; i < 10; i++) {
+
+        memset (cmd, 0, MAX_COMMAND_SIZE);
+        cmd[0] = TEST_UNIT_READY;
+
+        SCpnt = osst_do_scsi(SCpnt, STp, cmd, 0, STp->timeout, MAX_READY_RETRIES, TRUE);
+        if ((SCpnt->sense_buffer[0] & 0x70) != 0x70 ||
+            (SCpnt->sense_buffer[2] & 0x0f) == NOT_READY)
+            break;
+
+	if ((SCpnt->sense_buffer[2] & 0x0f) == UNIT_ATTENTION) {
+	  STp->device->was_reset = 0;
+	  STp->partition = STp->new_partition = 0;
+	  if (STp->can_partitions)
+	    STp->nbr_partitions = 1;  /* This guess will be updated later if necessary */
+	  for (i=0; i < ST_NBR_PARTITIONS; i++) {
+	    STps = &(STp->ps[i]);
+	    STps->rw = ST_IDLE;
+	    STps->eof = ST_NOEOF;
+	    STps->at_sm = 0;
+	    STps->last_block_valid = FALSE;
+	    STps->drv_block = 0;
+	    STps->drv_file = 0 ;
+	  }
+	  new_session = TRUE;
+        }
+      }
+    }
+
+    if (osst_wait_ready(STp, &SCpnt,  3 * 60))		/* FIXME - not allowed with NOBLOCK */
+	printk(KERN_WARNING "osst%i: Device did not become Ready in open\n",dev);
+
+    if ((STp->buffer)->last_result_fatal != 0) {
+      if ((STp->device)->scsi_level >= SCSI_2 &&
+	  (SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
+	  (SCpnt->sense_buffer[2] & 0x0f) == NOT_READY &&
+	  SCpnt->sense_buffer[12] == 0x3a) { /* Check ASC */
+	STp->ready = ST_NO_TAPE;
+      } else
+	STp->ready = ST_NOT_READY;
+      scsi_release_command(SCpnt);
+      SCpnt = NULL;
+      STp->density = 0;   	/* Clear the erroneous "residue" */
+      STp->write_prot = 0;
+      STp->block_size = 0;
+      STp->ps[0].drv_file = STp->ps[0].drv_block = (-1);
+      STp->partition = STp->new_partition = 0;
+      STp->door_locked = ST_UNLOCKED;
+      return 0;
+    }
+
+    STp->min_block = STp->max_block = (-1);
+
+    osst_configure_onstream(STp, &SCpnt);
+
+/*	STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0; FIXME */
+
+    if (OS_FRAME_SIZE > (STp->buffer)->buffer_size &&
+	!enlarge_buffer(STp->buffer, OS_FRAME_SIZE, STp->restr_dma)) {
+      printk(KERN_NOTICE "osst%d: Framesize %d too large for buffer.\n", dev,
+	     OS_FRAME_SIZE);
+      scsi_release_command(SCpnt);
+      SCpnt = NULL;
+      STp->buffer->in_use = 0;
+      STp->buffer = NULL;
+      if (STp->device->host->hostt->module)
+	 __MOD_DEC_USE_COUNT(STp->device->host->hostt->module);
+      if (osst_template.module)
+	 __MOD_DEC_USE_COUNT(osst_template.module);
+      return (-EIO);
+    }
+
+    if ((STp->buffer)->buffer_size >= OS_FRAME_SIZE)
+    {
+      for (i = 0, b_size = 0; 
+           i < STp->buffer->sg_segs && (b_size + STp->buffer->sg[i].length) <= OS_DATA_SIZE; 
+           b_size += STp->buffer->sg[i++].length);
+      STp->buffer->aux = (os_aux_t *) (STp->buffer->sg[i].address + OS_DATA_SIZE - b_size);
+#if DEBUG
+      printk(OSST_DEB_MSG "osst%d: b_data points to %p in segment 0 at %p\n", dev,
+			STp->buffer->b_data, STp->buffer->sg[0].address);
+      printk(OSST_DEB_MSG "osst%d: AUX points to %p in segment %d at %p\n", dev,
+                         STp->buffer->aux, i, STp->buffer->sg[i].address);
+#endif
+    } else
+      STp->buffer->aux = NULL; /* this had better never happen! */
+
+    (STp->buffer)->buffer_blocks = 1;
+    (STp->buffer)->buffer_bytes  =
+    (STp->buffer)->read_pointer  =
+    STp->logical_blk_in_buffer   = 0;
+
+#if DEBUG
+    if (debugging)
+      printk(OSST_DEB_MSG "osst%d: Block size: %d, frame size: %d, buffer size: %d (%d blocks).\n",
+	     dev, STp->block_size, OS_FRAME_SIZE, (STp->buffer)->buffer_size,
+	     (STp->buffer)->buffer_blocks);
+#endif
+
+    if (STp->drv_write_prot) {
+      STp->write_prot = 1;
+#if DEBUG
+      if (debugging)
+	printk(OSST_DEB_MSG "osst%d: Write protected\n", dev);
+#endif
+      if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) {
+	(STp->buffer)->in_use = 0;
+	STp->buffer = NULL;
+	STp->in_use = 0;
+	STp->in_use = 0;
+	if (STp->device->host->hostt->module)
+	    __MOD_DEC_USE_COUNT(STp->device->host->hostt->module);
+	if(osst_template.module)
+	    __MOD_DEC_USE_COUNT(osst_template.module);
+        scsi_release_command(SCpnt);
+        SCpnt = NULL;
+	return (-EROFS);
+      }
+    }
+
+    if (new_session) {  /* Change the drive parameters for the new mode */
+#if DEBUG
+      if (debugging)
+	printk(OSST_DEB_MSG "osst%d: New Session\n", dev);
+#endif
+      STp->density_changed = STp->blksize_changed = FALSE;
+      STp->compression_changed = FALSE;
+    }
+
+    /*
+     * properly position the tape and check the ADR headers
+     */
+    if (STp->door_locked == ST_UNLOCKED) {
+       if (osst_int_ioctl(STp, &SCpnt, MTLOCK, 0))
+          printk(KERN_WARNING "osst%d: Can't lock drive door\n", dev);
+       else
+	  STp->door_locked = ST_LOCKED_AUTO;
+    }
+
+    osst_analyze_headers(STp, &SCpnt);
+
+    scsi_release_command(SCpnt);
+    SCpnt = NULL;
+
+    return 0;
+}
+
+
+/* Flush the tape buffer before close */
+static int os_scsi_tape_flush(struct file * filp)
+{
+    int result = 0, result2;
+    OS_Scsi_Tape * STp;
+    ST_mode * STm;
+    ST_partstat * STps;
+    Scsi_Cmnd *SCpnt = NULL;
+
+    struct inode *inode = filp->f_dentry->d_inode;
+    kdev_t devt = inode->i_rdev;
+    int dev;
+
+    if (filp->f_count > 1)
+	return 0;
+
+    dev = TAPE_NR(devt);
+    STp = os_scsi_tapes[dev];
+    STm = &(STp->modes[STp->current_mode]);
+    STps = &(STp->ps[STp->partition]);
+
+    if ( STps->rw == ST_WRITING && !(STp->device)->was_reset) {
+      result = osst_flush_write_buffer(STp, &SCpnt, 1);
+      if (result != 0 && result != (-ENOSPC))
+	  goto out;
+    }
+
+    if ( STps->rw == ST_WRITING && !(STp->device)->was_reset) {
+
+#if DEBUG
+      if (debugging) {
+	printk(OSST_DEB_MSG "osst%d: File length %ld bytes.\n",
+	       dev, (long)(filp->f_pos));
+	printk(OSST_DEB_MSG "osst%d: Async write waits %d, finished %d.\n",
+	       dev, STp->nbr_waits, STp->nbr_finished);
+      }
+#endif
+
+      result = osst_flush_drive_buffer(STp, &SCpnt);
+      if (result < 0) goto out;
+      result = osst_write_filemark(STp, &SCpnt);
+      if (result < 0) goto out;
+
+      if (STps->drv_file >= 0)
+	STps->drv_file++ ;
+      STps->drv_block = 0;
+//osst_report_stats();
+      result = osst_write_eod(STp, &SCpnt);
+      osst_write_header(STp, &SCpnt, !(STp->rew_at_close));
+
+      STps->eof = ST_FM;
+
+#if DEBUG
+      if (debugging)
+	printk(OSST_DEB_MSG "osst%d: Buffer flushed, %d EOF(s) written\n",
+	       dev, 1+STp->two_fm);
+#endif
+    }
+    else if (!STp->rew_at_close) {
+	STps = &(STp->ps[STp->partition]);
+	if (!STm->sysv || STps->rw != ST_READING) {
+	    if (STp->can_bsr)
+		result = osst_flush_buffer(STp, &SCpnt, 0);
+	    else if (STps->eof == ST_FM_HIT) {
+		result = cross_eof(STp, &SCpnt, FALSE);
+		if (result) {
+		    if (STps->drv_file >= 0)
+			STps->drv_file++;
+		    STps->drv_block = 0;
+		    STps->eof = ST_FM;
+		}
+		else
+		    STps->eof = ST_NOEOF;
+	    }
+	}
+	else if ((STps->eof == ST_NOEOF &&
+		  !(result = cross_eof(STp, &SCpnt, TRUE))) ||
+		 STps->eof == ST_FM_HIT) {
+	    if (STps->drv_file >= 0)
+		STps->drv_file++;
+	    STps->drv_block = 0;
+	    STps->eof = ST_FM;
+	}
+    }
+
+out:
+    if (STp->rew_at_close) {
+      result2 = osst_position_tape_and_confirm(STp, &SCpnt, STp->first_data_ppos);
+      STps->drv_file = STps->drv_block = STp->logical_blk_num = 0;
+      if (result == 0)
+	  result = result2;
+    }
+    if (SCpnt) scsi_release_command(SCpnt);
+
+    return result;
+}
+
+
+/* Close the device and release it */
+static int os_scsi_tape_close(struct inode * inode, struct file * filp)
+{
+    int result = 0;
+    OS_Scsi_Tape * STp;
+    Scsi_Cmnd *SCpnt = NULL;
+
+    kdev_t devt = inode->i_rdev;
+    int dev;
+
+    dev = TAPE_NR(devt);
+    STp = os_scsi_tapes[dev];
+
+    if (STp->door_locked == ST_LOCKED_AUTO)
+      osst_int_ioctl(STp, &SCpnt, MTUNLOCK, 0);
+    if (SCpnt) scsi_release_command(SCpnt);
+
+    if (STp->buffer != 0)
+      STp->buffer->in_use = 0;
+
+    STp->in_use = 0;
+    if (STp->device->host->hostt->module)
+	__MOD_DEC_USE_COUNT(STp->device->host->hostt->module);
+    if(osst_template.module)
+	__MOD_DEC_USE_COUNT(osst_template.module);
+
+    return result;
+}
+
+
+/* The ioctl command */
+static int osst_ioctl(struct inode * inode,struct file * file,
+	 unsigned int cmd_in, unsigned long arg)
+{
+   int i, cmd_nr, cmd_type;
+   unsigned int blk;
+   struct mtop mtc;
+   struct mtpos mt_pos;
+   OS_Scsi_Tape *STp;
+   ST_mode *STm;
+   ST_partstat *STps;
+   Scsi_Cmnd *SCpnt = NULL;
+   int dev = TAPE_NR(inode->i_rdev);
+
+   STp = os_scsi_tapes[dev];
+#if DEBUG
+   if (debugging && !STp->in_use) {
+     printk(OSST_DEB_MSG "osst%d: Incorrect device.\n", dev);
+     return (-EIO);
+   }
+#endif
+   STm = &(STp->modes[STp->current_mode]);
+   STps = &(STp->ps[STp->partition]);
+
+    /*
+     * If we are in the middle of error recovery, don't let anyone
+     * else try and use this device.  Also, if error recovery fails, it
+     * may try and take the device offline, in which case all further
+     * access to the device is prohibited.
+     */
+    if( !scsi_block_when_processing_errors(STp->device) ) {
+        return -ENXIO;
+    }
+
+   cmd_type = _IOC_TYPE(cmd_in);
+   cmd_nr   = _IOC_NR(cmd_in);
+
+   if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) {
+     if (_IOC_SIZE(cmd_in) != sizeof(mtc))
+       return (-EINVAL);
+
+     i = copy_from_user((char *) &mtc, (char *)arg, sizeof(struct mtop));
+     if (i)
+	 return (-EFAULT);
+
+     if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) {
+       printk(KERN_WARNING "osst%d: MTSETDRVBUFFER only allowed for root.\n", dev);
+       return (-EPERM);
+     }
+     if (!STm->defined &&
+	 (mtc.mt_op != MTSETDRVBUFFER && (mtc.mt_count & MT_ST_OPTIONS) == 0))
+       return (-ENXIO);
+
+     if (!(STp->device)->was_reset) {
+
+       if (STps->eof == ST_FM_HIT) {
+	 if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM|| mtc.mt_op == MTEOM) {
+	   mtc.mt_count -= 1;
+	   if (STps->drv_file >= 0)
+	     STps->drv_file += 1;
+	 }
+	 else if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM) {
+	   mtc.mt_count += 1;
+	   if (STps->drv_file >= 0)
+	     STps->drv_file += 1;
+	 }
+       }
+
+       if (mtc.mt_op == MTSEEK) {
+	   /* Old position must be restored if partition will be changed */
+	   i = !STp->can_partitions ||
+	       (STp->new_partition != STp->partition);
+       }
+       else {
+	   i = mtc.mt_op == MTREW || mtc.mt_op == MTOFFL ||
+	       mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM ||
+	       mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD ||
+	       mtc.mt_op == MTCOMPRESSION;
+       }
+       i = osst_flush_buffer(STp, &SCpnt, i);
+       if (SCpnt) scsi_release_command(SCpnt);
+       if (i < 0)
+	 return i;
+     }
+     else {
+       /*
+	* If there was a bus reset, block further access
+	* to this device.  If the user wants to rewind the tape,
+	* then reset the flag and allow access again.
+	*/
+       if(mtc.mt_op != MTREW &&
+	  mtc.mt_op != MTOFFL &&
+	  mtc.mt_op != MTRETEN &&
+	  mtc.mt_op != MTERASE &&
+	  mtc.mt_op != MTSEEK &&
+	  mtc.mt_op != MTEOM)
+	 return (-EIO);
+       STp->device->was_reset = 0;
+       if (STp->door_locked != ST_UNLOCKED &&
+	   STp->door_locked != ST_LOCK_FAILS) {
+	 if (osst_int_ioctl(STp, &SCpnt, MTLOCK, 0)) {
+	   printk(KERN_NOTICE "osst%d: Could not relock door after bus reset.\n",
+		  dev);
+	   STp->door_locked = ST_UNLOCKED;
+	 }
+       }
+     }
+
+     if (mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK &&
+	 mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTWSM &&
+	 mtc.mt_op != MTSETDRVBUFFER && mtc.mt_op != MTSETPART)
+       STps->rw = ST_IDLE;  /* Prevent automatic WEOF and fsf */
+
+     if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED)
+       osst_int_ioctl(STp, &SCpnt, MTUNLOCK, 0);  /* Ignore result! */
+     if (SCpnt) scsi_release_command(SCpnt);
+
+     if (mtc.mt_op == MTSETDRVBUFFER &&
+	 (mtc.mt_count & MT_ST_OPTIONS) != 0)
+       return osst_set_options(STp, mtc.mt_count);
+     if (mtc.mt_op == MTSETPART) {
+/*     if (!STp->can_partitions ||
+	   mtc.mt_count < 0 || mtc.mt_count >= ST_NBR_PARTITIONS)
+	 return (-EINVAL);
+       if (mtc.mt_count >= STp->nbr_partitions &&
+	   (STp->nbr_partitions = nbr_partitions(inode)) < 0)
+	 return (-EIO);*/
+       if (mtc.mt_count >= STp->nbr_partitions)
+	 return (-EINVAL);
+       STp->new_partition = mtc.mt_count;
+       return 0;
+     }
+     if (mtc.mt_op == MTMKPART) {
+       if (!STp->can_partitions)
+	 return (-EINVAL);
+       if ((i = osst_int_ioctl(STp, &SCpnt, MTREW, 0)) < 0 /*||
+	   (i = partition_tape(inode, mtc.mt_count)) < 0*/) {
+         if (SCpnt) scsi_release_command(SCpnt);
+	 return i;
+       }
+       for (i=0; i < ST_NBR_PARTITIONS; i++) {
+	 STp->ps[i].rw = ST_IDLE;
+	 STp->ps[i].at_sm = 0;
+	 STp->ps[i].last_block_valid = FALSE;
+       }
+       STp->partition = STp->new_partition = 0;
+       STp->nbr_partitions = 1;  /* Bad guess ?-) */
+       STps->drv_block = STps->drv_file = 0;
+       return 0;
+     }
+     if (mtc.mt_op == MTSEEK) {
+       i = osst_seek_frame(STp, &SCpnt, mtc.mt_count);
+       if (SCpnt) scsi_release_command(SCpnt);
+       if (!STp->can_partitions)
+	   STp->ps[0].rw = ST_IDLE;
+       return i;
+     }
+/*   if (STp->can_partitions && STp->ready == ST_READY &&
+	 (i = update_partition(inode)) < 0)
+       return i;*/
+     if (mtc.mt_op == MTCOMPRESSION)
+       return (-EINVAL)/*osst_compression(STp, (mtc.mt_count & 1))*/;
+     else {
+       i = osst_int_ioctl(STp, &SCpnt, mtc.mt_op, mtc.mt_count);
+       if (SCpnt) scsi_release_command(SCpnt);
+       return i;
+     }
+   }
+
+   if (!STm->defined)
+     return (-ENXIO);
+
+   i = osst_flush_buffer(STp, &SCpnt, FALSE);
+   if (SCpnt) scsi_release_command(SCpnt);
+   if (i < 0)
+     return i;
+/* if (STp->can_partitions &&
+       (i = update_partition(inode)) < 0)
+     return i;*/
+
+   if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) {
+     struct mtget mt_status;
+
+     if (_IOC_SIZE(cmd_in) != sizeof(struct mtget))
+       return (-EINVAL);
+
+     mt_status.mt_type = MT_ISONSTREAM_SC;
+     mt_status.mt_erreg = STp->recover_erreg << MT_ST_SOFTERR_SHIFT;
+     mt_status.mt_dsreg =
+       ((STp->block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK) |
+       ((STp->density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK);
+     mt_status.mt_blkno = STps->drv_block;
+     mt_status.mt_fileno = STps->drv_file;
+     if (STp->block_size != 0) {
+       if (STps->rw == ST_WRITING)
+	 mt_status.mt_blkno +=
+	   (STp->buffer)->buffer_bytes / STp->block_size;
+       else if (STps->rw == ST_READING)
+	 mt_status.mt_blkno -= ((STp->buffer)->buffer_bytes +
+	   STp->block_size - 1) / STp->block_size;
+     }
+
+     mt_status.mt_gstat = 0;
+     if (STp->drv_write_prot)
+       mt_status.mt_gstat |= GMT_WR_PROT(0xffffffff);
+     if (mt_status.mt_blkno == 0) {
+       if (mt_status.mt_fileno == 0)
+	 mt_status.mt_gstat |= GMT_BOT(0xffffffff);
+       else
+	 mt_status.mt_gstat |= GMT_EOF(0xffffffff);
+     }
+     mt_status.mt_resid = STp->partition;
+     if (STps->eof == ST_EOM_OK || STps->eof == ST_EOM_ERROR)
+       mt_status.mt_gstat |= GMT_EOT(0xffffffff);
+     else if (STps->eof >= ST_EOM_OK)
+       mt_status.mt_gstat |= GMT_EOD(0xffffffff);
+     if (STp->density == 1)
+       mt_status.mt_gstat |= GMT_D_800(0xffffffff);
+     else if (STp->density == 2)
+       mt_status.mt_gstat |= GMT_D_1600(0xffffffff);
+     else if (STp->density == 3)
+       mt_status.mt_gstat |= GMT_D_6250(0xffffffff);
+     if (STp->ready == ST_READY)
+       mt_status.mt_gstat |= GMT_ONLINE(0xffffffff);
+     if (STp->ready == ST_NO_TAPE)
+       mt_status.mt_gstat |= GMT_DR_OPEN(0xffffffff);
+     if (STps->at_sm)
+       mt_status.mt_gstat |= GMT_SM(0xffffffff);
+     if (STm->do_async_writes || (STm->do_buffer_writes && STp->block_size != 0) ||
+	 STp->drv_buffer != 0)
+       mt_status.mt_gstat |= GMT_IM_REP_EN(0xffffffff);
+
+     i = copy_to_user((char *)arg, (char *)&mt_status,
+		      sizeof(struct mtget));
+     if (i)
+	 return (-EFAULT);
+
+     STp->recover_erreg = 0;  /* Clear after read */
+     return 0;
+   } /* End of MTIOCGET */
+
+   if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) {
+     if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos))
+       return (-EINVAL);
+     blk = osst_get_frame_position(STp, &SCpnt);
+     if (SCpnt) scsi_release_command(SCpnt);
+     if (blk < 0)
+       return blk;
+     mt_pos.mt_blkno = blk;
+     i = copy_to_user((char *)arg, (char *) (&mt_pos), sizeof(struct mtpos));
+     if (i)
+	 return (-EFAULT);
+     return 0;
+   }
+
+   return scsi_ioctl(STp->device, cmd_in, (void *) arg);
+}
+
+
+/* Memory handling routines */
+
+/* Try to allocate a new tape buffer */
+static OSST_buffer * new_tape_buffer( int from_initialization, int need_dma )
+{
+  int i, priority, b_size, order, got = 0, segs = 0;
+  OSST_buffer *tb;
+
+  if (osst_nbr_buffers >= osst_template.dev_max)
+    return NULL;  /* Should never happen */
+
+  if (from_initialization)
+    priority = GFP_ATOMIC;
+  else
+    priority = GFP_KERNEL;
+
+  i = sizeof(OSST_buffer) + (osst_max_sg_segs - 1) * sizeof(struct scatterlist);
+  tb = (OSST_buffer *)kmalloc(i, priority);
+  if (tb) {
+//    tb->this_size = i;
+    if (need_dma)
+      priority |= GFP_DMA;
+
+    /* Try to allocate the first segment up to OSST_FIRST_ORDER and the
+       others big enough to reach the goal */
+    for (b_size = PAGE_SIZE,          order = 0;
+	 b_size < osst_buffer_size && order < OSST_FIRST_ORDER;
+	 b_size *= 2,                 order++ );
+
+    for ( ; b_size >= PAGE_SIZE; order--, b_size /= 2) {
+	tb->sg[0].address =
+	    (unsigned char *)__get_free_pages(priority, order);
+	if (tb->sg[0].address != NULL) {
+	    tb->sg[0].alt_address = NULL;
+	    tb->sg[0].length = b_size;
+	    break;
+	}
+    }
+    if (tb->sg[segs].address == NULL) {
+	kfree(tb);
+	tb = NULL;
+    }
+    else {  /* Got something, continue */
+
+	for (b_size = PAGE_SIZE, order = 0;
+	     osst_buffer_size > tb->sg[0].length + (OSST_FIRST_SG - 1) * b_size;
+	     b_size *= 2, order++ );
+
+	for (segs=1, got=tb->sg[0].length;
+	     got < osst_buffer_size && segs < OSST_FIRST_SG; ) {
+	    tb->sg[segs].address =
+		(unsigned char *)__get_free_pages(priority, order);
+	    if (tb->sg[segs].address == NULL) {
+		if (osst_buffer_size - got <=
+		    (OSST_FIRST_SG - segs) * b_size / 2) {
+		    b_size /= 2; /* Large enough for the rest of the buffers */
+		    order--;
+		    continue;
+		}
+		tb->sg_segs = segs;
+		tb->orig_sg_segs = 0;
+#if DEBUG
+		tb->buffer_size = got;
+#endif
+		normalize_buffer(tb);
+		kfree(tb);
+		tb = NULL;
+		break;
+	    }
+	    tb->sg[segs].alt_address = NULL;
+	    tb->sg[segs].length = b_size;
+	    got += b_size;
+	    segs++;
+	}
+    }
+  }
+  if (!tb) {
+    printk(KERN_NOTICE "osst: Can't allocate new tape buffer (nbr %d).\n",
+	   osst_nbr_buffers);
+    return NULL;
+  }
+  tb->sg_segs = tb->orig_sg_segs = segs;
+  tb->b_data = tb->sg[0].address;
+
+#if DEBUG
+  if (debugging) {
+    printk(OSST_DEB_MSG
+    "osst: Allocated tape buffer %d (%d bytes, %d segments, dma: %d, a: %p).\n",
+	   osst_nbr_buffers, got, tb->sg_segs, need_dma, tb->b_data);
+    printk(OSST_DEB_MSG
+	   "osst: segment sizes: first %d, last %d bytes.\n",
+	   tb->sg[0].length, tb->sg[segs-1].length);
+  }
+#endif
+  tb->in_use = 0;
+  tb->dma = need_dma;
+  tb->buffer_size = got;
+  tb->writing = 0;
+  osst_buffers[osst_nbr_buffers++] = tb;
+
+  return tb;
+}
+
+
+/* Try to allocate a temporary enlarged tape buffer */
+static int enlarge_buffer(OSST_buffer *STbuffer, int new_size, int need_dma)
+{
+  int segs, nbr, max_segs, b_size, priority, order, got;
+
+  normalize_buffer(STbuffer);
+
+  max_segs = STbuffer->use_sg;
+  if (max_segs > osst_max_sg_segs)
+      max_segs = osst_max_sg_segs;
+  nbr = max_segs - STbuffer->sg_segs;
+  if (nbr <= 0)
+      return FALSE;
+
+  priority = GFP_KERNEL;
+  if (need_dma)
+    priority |= GFP_DMA;
+  for (b_size = PAGE_SIZE, order = 0;
+       b_size * nbr < new_size - STbuffer->buffer_size;
+       b_size *= 2, order++);
+
+  for (segs=STbuffer->sg_segs, got=STbuffer->buffer_size;
+       segs < max_segs && got < new_size; ) {
+      STbuffer->sg[segs].address =
+	  (unsigned char *)__get_free_pages(priority, order);
+      if (STbuffer->sg[segs].address == NULL) {
+	  if (new_size - got <= (max_segs - segs) * b_size / 2) {
+	      b_size /= 2;  /* Large enough for the rest of the buffers */
+	      order--;
+	      continue;
+	  }
+	  printk(KERN_NOTICE "osst: Failed to enlarge buffer to %d bytes.\n",
+		 new_size);
+#if DEBUG
+	  STbuffer->buffer_size = got;
+#endif
+	  normalize_buffer(STbuffer);
+	  return FALSE;
+      }
+      STbuffer->sg[segs].alt_address = NULL;
+      STbuffer->sg[segs].length = b_size;
+      STbuffer->sg_segs += 1;
+      got += b_size;
+      STbuffer->buffer_size = got;
+      segs++;
+  }
+#if DEBUG
+  if (debugging) {
+    for (nbr=0; osst_buffers[nbr] != STbuffer && nbr < osst_nbr_buffers; nbr++);
+    printk(OSST_DEB_MSG
+    "osst: Expanded tape buffer %d (%d bytes, %d->%d segments, dma: %d, a: %p).\n",
+	   nbr, got, STbuffer->orig_sg_segs, STbuffer->sg_segs, need_dma, STbuffer->b_data);
+    printk(OSST_DEB_MSG
+	   "osst: segment sizes: first %d, last %d bytes.\n",
+	   STbuffer->sg[0].length, STbuffer->sg[segs-1].length);
+  }
+#endif
+
+  return TRUE;
+}
+
+
+/* Release the extra buffer */
+static void normalize_buffer(OSST_buffer *STbuffer)
+{
+  int i, order, b_size;
+
+  for (i=STbuffer->orig_sg_segs; i < STbuffer->sg_segs; i++) {
+
+      for (b_size = PAGE_SIZE, order = 0;
+	   b_size < STbuffer->sg[i].length;
+	   b_size *= 2, order++);
+
+      free_pages((unsigned long)STbuffer->sg[i].address, order);
+      STbuffer->buffer_size -= STbuffer->sg[i].length;
+  }
+#if DEBUG
+  if (debugging && STbuffer->orig_sg_segs < STbuffer->sg_segs)
+      printk(OSST_DEB_MSG "osst: Buffer at %p normalized to %d bytes (segs %d).\n",
+	     STbuffer->b_data, STbuffer->buffer_size, STbuffer->sg_segs);
+#endif
+  STbuffer->sg_segs = STbuffer->orig_sg_segs;
+}
+
+
+/* Move data from the user buffer to the tape buffer. Returns zero (success) or
+   negative error code. */
+static int append_to_buffer(const char *ubp, OSST_buffer *st_bp, int do_count)
+{
+    int i, cnt, res, offset;
+
+    for (i=0, offset=st_bp->buffer_bytes;
+	 i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
+	offset -= st_bp->sg[i].length;
+    if (i == st_bp->sg_segs) {  /* Should never happen */
+	printk(KERN_WARNING "osst: Append_to_buffer offset overflow.\n");
+	return (-EIO);
+    }
+    for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
+	cnt = st_bp->sg[i].length - offset < do_count ?
+	    st_bp->sg[i].length - offset : do_count;
+	res = copy_from_user(st_bp->sg[i].address + offset, ubp, cnt);
+	if (res)
+	    return (-EFAULT);
+	do_count -= cnt;
+	st_bp->buffer_bytes += cnt;
+	ubp += cnt;
+	offset = 0;
+    }
+    if (do_count) {  /* Should never happen */
+	printk(KERN_WARNING "osst: Append_to_buffer overflow (left %d).\n",
+	       do_count);
+	return (-EIO);
+    }
+    return 0;
+}
+
+
+/* Move data from the tape buffer to the user buffer. Returns zero (success) or
+   negative error code. */
+static int from_buffer(OSST_buffer *st_bp, char *ubp, int do_count)
+{
+    int i, cnt, res, offset;
+
+    for (i=0, offset=st_bp->read_pointer;
+	 i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
+	offset -= st_bp->sg[i].length;
+    if (i == st_bp->sg_segs) {  /* Should never happen */
+	printk(KERN_WARNING "osst: From_buffer offset overflow.\n");
+	return (-EIO);
+    }
+    for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
+	cnt = st_bp->sg[i].length - offset < do_count ?
+	    st_bp->sg[i].length - offset : do_count;
+	res = copy_to_user(ubp, st_bp->sg[i].address + offset, cnt);
+	if (res)
+	    return (-EFAULT);
+	do_count -= cnt;
+	st_bp->buffer_bytes -= cnt;
+	st_bp->read_pointer += cnt;
+	ubp += cnt;
+	offset = 0;
+    }
+    if (do_count) {  /* Should never happen */
+	printk(KERN_WARNING "osst: From_buffer overflow (left %d).\n",
+	       do_count);
+	return (-EIO);
+    }
+    return 0;
+}
+
+/* Sets the tail of the buffer after fill point to zero.
+   Returns zero (success) or negative error code.        */
+static int osst_zero_buffer_tail(OSST_buffer *st_bp)
+{
+	int	i, offset, do_count, cnt;
+
+	for (i = 0, offset = st_bp->buffer_bytes;
+	     i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
+		offset -= st_bp->sg[i].length;
+	if (i == st_bp->sg_segs) {  /* Should never happen */
+		printk(KERN_WARNING "osst: Zero_buffer offset overflow.\n");
+		return (-EIO);
+	}
+	for (do_count = OS_DATA_SIZE - st_bp->read_pointer;
+	     i < st_bp->sg_segs && do_count > 0; i++) {
+		cnt = st_bp->sg[i].length - offset < do_count ?
+		      st_bp->sg[i].length - offset : do_count ;
+		memset(st_bp->sg[i].address + offset, 0, cnt);
+		do_count -= cnt;
+		offset = 0;
+	}
+	if (do_count) {  /* Should never happen */
+		printk(KERN_WARNING "osst: Zero_buffer overflow (left %d).\n", do_count);
+		return (-EIO);
+	}
+	return 0;
+}
+
+/* Copy a osst 32K block of memory into the buffer.
+   Returns zero (success) or negative error code.  */
+static int osst_copy_to_buffer(OSST_buffer *st_bp, unsigned char *ptr)
+{
+	int	i, cnt, do_count = OS_DATA_SIZE;
+
+	for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) {
+		cnt = st_bp->sg[i].length < do_count ?
+		      st_bp->sg[i].length : do_count ;
+		memcpy(st_bp->sg[i].address, ptr, cnt);
+		do_count -= cnt;
+		ptr      += cnt;
+	}
+	if (do_count || i != st_bp->sg_segs-1) {  /* Should never happen */
+		printk(KERN_WARNING "osst: Copy_to_buffer overflow (left %d at sg %d).\n",
+					 do_count, i);
+		return (-EIO);
+	}
+	return 0;
+}
+
+/* Copy a osst 32K block of memory from the buffer.
+   Returns zero (success) or negative error code.  */
+static int osst_copy_from_buffer(OSST_buffer *st_bp, unsigned char *ptr)
+{
+	int	i, cnt, do_count = OS_DATA_SIZE;
+
+	for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) {
+		cnt = st_bp->sg[i].length < do_count ?
+		      st_bp->sg[i].length : do_count ;
+		memcpy(ptr, st_bp->sg[i].address, cnt);
+		do_count -= cnt;
+		ptr      += cnt;
+	}
+	if (do_count || i != st_bp->sg_segs-1) {  /* Should never happen */
+		printk(KERN_WARNING "osst: Copy_from_buffer overflow (left %d at sg %d).\n",
+					 do_count, i);
+		return (-EIO);
+	}
+	return 0;
+}
+
+
+/* Module housekeeping */
+
+#ifndef MODULE
+/* Set the boot options. Syntax: st=xxx,yyy
+   where xxx is buffer size in 1024 byte blocks and yyy is write threshold
+   in 1024 byte blocks. */
+__initfunc( void osst_setup(char *str, int *ints))
+{
+  if (ints[0] > 0 && ints[1] > 0)
+    osst_buffer_size = ints[1] * ST_KILOBYTE;
+  if (ints[0] > 1 && ints[2] > 0) {
+    osst_write_threshold = ints[2] * ST_KILOBYTE;
+    if (osst_write_threshold > osst_buffer_size)
+      osst_write_threshold = osst_buffer_size;
+  }
+  if (ints[0] > 2 && ints[3] > 0)
+    osst_max_buffers = ints[3];
+}
+#endif
+
+
+static struct file_operations osst_fops = {
+   NULL,            /* lseek - default */
+   osst_read,         /* read - general block-dev read */
+   osst_write,        /* write - general block-dev write */
+   NULL,            /* readdir - bad */
+   NULL,            /* select */
+   osst_ioctl,        /* ioctl */
+   NULL,            /* mmap */
+   os_scsi_tape_open,  /* open */
+   os_scsi_tape_flush, /* flush */
+   os_scsi_tape_close, /* release */
+   NULL		    /* fsync */
+};
+
+
+static int osst_attach(Scsi_Device * SDp){
+   OS_Scsi_Tape * tpnt;
+   ST_mode * STm;
+   ST_partstat * STps;
+   int i;
+#ifdef CONFIG_DEVFS_FS
+   int mode;
+#endif
+
+   if (SDp->type != TYPE_TAPE || !OSST_SUPPORTS(SDp))
+       return 1;
+
+   if (osst_template.nr_dev >= osst_template.dev_max) {
+       SDp->attached--;
+       return 1;
+   }
+	
+   /* find a free minor number */
+   for (i=0; os_scsi_tapes[i] && i<osst_template.dev_max; i++);
+   if(i >= osst_template.dev_max) panic ("Scsi_devices corrupt (osst)");
+
+   /* allocate a OS_Scsi_Tape for this device */
+   tpnt = (OS_Scsi_Tape *)kmalloc(sizeof(OS_Scsi_Tape), GFP_ATOMIC);
+   if (tpnt == NULL) {
+       SDp->attached--;
+       printk(KERN_ERR "osst: Can't allocate device descriptor.\n");
+       return 1;
+   }
+   memset(tpnt, 0, sizeof(OS_Scsi_Tape));
+   os_scsi_tapes[i] = tpnt;
+   tpnt->capacity = 0xfffff;
+
+   /* allocate a buffer for this device */
+   if (!new_tape_buffer(TRUE, TRUE)) 
+       printk(KERN_ERR "osst: Unable to allocate a tape buffer.\n");
+
+#ifdef CONFIG_DEVFS_FS
+   for (mode = 0; mode < ST_NBR_MODES; ++mode) {
+       char name[8];
+       static char *formats[ST_NBR_MODES] ={"", "l", "m", "a"};
+
+       /*  Rewind entry  */
+       sprintf (name, "mt%s", formats[mode]);
+       tpnt->de_r[mode] =
+	   devfs_register (SDp->de, name, 0, DEVFS_FL_DEFAULT,
+			   MAJOR_NR, i + (mode << 5),
+			   S_IFCHR | S_IRUGO | S_IWUGO,
+			   0, 0, &osst_fops, NULL);
+       /*  No-rewind entry  */
+       sprintf (name, "mt%sn", formats[mode]);
+       tpnt->de_n[mode] =
+	   devfs_register (SDp->de, name, 0, DEVFS_FL_DEFAULT,
+			   MAJOR_NR, i + (mode << 5) + 128,
+			   S_IFCHR | S_IRUGO | S_IWUGO,
+			   0, 0, &osst_fops, NULL);
+   }
+   devfs_register_tape (tpnt->de_r[0]);
+#endif
+
+   tpnt->device = SDp;
+   tpnt->devt = MKDEV(MAJOR_NR, i);
+   tpnt->dirty = 0;
+   tpnt->in_use = 0;
+   tpnt->drv_buffer = 1;  /* Try buffering if no mode sense */
+   tpnt->restr_dma = (SDp->host)->unchecked_isa_dma;
+   tpnt->density = 0;
+   tpnt->do_auto_lock = OSST_AUTO_LOCK;
+   tpnt->can_bsr = OSST_IN_FILE_POS;
+   tpnt->can_partitions = 0;
+   tpnt->two_fm = OSST_TWO_FM;
+   tpnt->fast_mteom = OSST_FAST_MTEOM;
+   tpnt->scsi2_logical = OSST_SCSI2LOGICAL; /* FIXME */
+   tpnt->write_threshold = osst_write_threshold;
+   tpnt->default_drvbuffer = 0xff; /* No forced buffering */
+   tpnt->partition = 0;
+   tpnt->new_partition = 0;
+   tpnt->nbr_partitions = 0;
+   tpnt->timeout = OSST_TIMEOUT;
+   tpnt->long_timeout = OSST_LONG_TIMEOUT;
+
+   /* Recognize OnStream tapes */
+   printk ("osst%i: Tape driver with OnStream support osst %s\nosst%i: %s\n",
+	       i, osst_version, i, cvsid);
+   /* We don't need to test for OnStream, as this has been done in detect () */
+   tpnt->os_fw_rev = osst_parse_firmware_rev (SDp->rev);
+#if DEBUG
+   printk ("osst%i: OnStream tape drive recognized, Model %s\n", i, SDp->model);
+#endif
+   tpnt->omit_blklims = 1;
+
+   tpnt->poll = (strncmp(SDp->model, "DI-", 3) == 0) || OSST_FW_NEED_POLL(tpnt->os_fw_rev,SDp);
+   tpnt->logical_blk_in_buffer = 0;
+   tpnt->header_ok = 0;
+   tpnt->linux_media = 0;
+   tpnt->header_cache = NULL;
+
+   for (i=0; i < ST_NBR_MODES; i++) {
+     STm = &(tpnt->modes[i]);
+     STm->defined = FALSE;
+     STm->sysv = OSST_SYSV;
+     STm->defaults_for_writes = 0;
+     STm->do_async_writes = OSST_ASYNC_WRITES;
+     STm->do_buffer_writes = OSST_BUFFER_WRITES;
+     STm->do_read_ahead = OSST_READ_AHEAD;
+     STm->default_compression = ST_DONT_TOUCH;
+     STm->default_blksize = 32 * ST_KILOBYTE;  /* No forced size */
+     STm->default_density = (-1);  /* No forced density */
+   }
+
+   for (i=0; i < ST_NBR_PARTITIONS; i++) {
+     STps = &(tpnt->ps[i]);
+     STps->rw = ST_IDLE;
+     STps->eof = ST_NOEOF;
+     STps->at_sm = 0;
+     STps->last_block_valid = FALSE;
+     STps->drv_block = (-1);
+     STps->drv_file = (-1);
+   }
+
+   tpnt->current_mode = 0;
+   tpnt->modes[0].defined = TRUE;
+
+   tpnt->density_changed = tpnt->compression_changed =
+     tpnt->blksize_changed = FALSE;
+
+   osst_template.nr_dev++;
+   return 0;
+};
+
+static int osst_detect(Scsi_Device * SDp)
+{
+  if (SDp->type != TYPE_TAPE) return 0;
+  /* We are willing to drive OnStream SC-x0 as well as the
+   * IDE, ParPort, USB variants, if accessible by emulation
+   * layer (ide-scsi, usb-storage, ...) */
+  if (!OSST_SUPPORTS(SDp)) return 0;
+
+  printk(KERN_WARNING
+	 "Detected OnStream scsi tape osst%d at scsi%d, channel %d, id %d, lun %d\n",
+	 osst_template.dev_noticed++,
+	 SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
+
+  return 1;
+}
+
+static int osst_registered = 0;
+
+/* Driver initialization (not __initfunc because may be called later) */
+static int osst_init()
+{
+  int i;
+
+  if (osst_template.dev_noticed == 0) return 0;
+
+  if(!osst_registered) {
+#ifdef CONFIG_DEVFS_FS
+    if (devfs_register_chrdev(MAJOR_NR,"osst",&osst_fops)) {
+#else
+    if (register_chrdev(MAJOR_NR,"osst",&osst_fops)) {
+#endif
+      printk(KERN_ERR "osst: Unable to get major %d for OnStream tapes\n",MAJOR_NR);
+      return 1;
+    }
+    osst_registered++;
+  }
+
+  if (os_scsi_tapes) return 0;
+  osst_template.dev_max = OSST_MAX_TAPES;
+  if (osst_template.dev_max > 128 / ST_NBR_MODES)
+    printk(KERN_INFO "osst: Only %d tapes accessible.\n", 128 / ST_NBR_MODES);
+  os_scsi_tapes =
+    (OS_Scsi_Tape **)kmalloc(osst_template.dev_max * sizeof(OS_Scsi_Tape *),
+				   GFP_ATOMIC);
+  if (os_scsi_tapes == NULL) {
+    printk(KERN_ERR "osst: Unable to allocate array for OnStream SCSI tapes.\n");
+#ifdef CONFIG_DEVFS_FS
+    devfs_unregister_chrdev(MAJOR_NR, "osst");
+#else
+    unregister_chrdev(MAJOR_NR, "osst");
+#endif
+    return 1;
+  }
+
+  for (i=0; i < osst_template.dev_max; ++i) os_scsi_tapes[i] = NULL;
+
+  /* Allocate the buffer pointers */
+  osst_buffers =
+    (OSST_buffer **)kmalloc(osst_template.dev_max * sizeof(OSST_buffer *),
+				    GFP_ATOMIC);
+  if (osst_buffers == NULL) {
+    printk(KERN_ERR "osst: Unable to allocate tape buffer pointers.\n");
+#ifdef CONFIG_DEVFS_FS
+    devfs_unregister_chrdev(MAJOR_NR, "osst");
+#else
+    unregister_chrdev(MAJOR_NR, "osst");
+#endif
+    kfree(os_scsi_tapes);
+    return 1;
+  }
+  osst_nbr_buffers = 0;
+
+#if DEBUG
+  printk(OSST_DEB_MSG "osst: Buffer size %d bytes, write threshold %d bytes.\n",
+	 osst_buffer_size, osst_write_threshold);
+#endif
+  return 0;
+}
+
+
+static void osst_detach(Scsi_Device * SDp)
+{
+  OS_Scsi_Tape * tpnt;
+  int i;
+#ifdef CONFIG_DEVFS_FS
+  int mode;
+#endif
+
+  for(i=0; i<osst_template.dev_max; i++) {
+    tpnt = os_scsi_tapes[i];
+    if(tpnt != NULL && tpnt->device == SDp) {
+      tpnt->device = NULL;
+#ifdef CONFIG_DEVFS_FS
+      for (mode = 0; mode < ST_NBR_MODES; ++mode) {
+	  devfs_unregister (tpnt->de_r[mode]);
+	  tpnt->de_r[mode] = NULL;
+	  devfs_unregister (tpnt->de_n[mode]);
+	  tpnt->de_n[mode] = NULL;
+      }
+#endif
+      kfree(tpnt);
+      os_scsi_tapes[i] = NULL;
+      SDp->attached--;
+      osst_template.nr_dev--;
+      osst_template.dev_noticed--;
+      return;
+    }
+  }
+  return;
+}
+
+
+#ifdef MODULE
+
+int init_module(void) {
+  int result;
+
+  if (buffer_kbs > 0)
+      osst_buffer_size = buffer_kbs * ST_KILOBYTE;
+  if (write_threshold_kbs > 0)
+      osst_write_threshold = write_threshold_kbs * ST_KILOBYTE;
+  if (osst_write_threshold > osst_buffer_size)
+      osst_write_threshold = osst_buffer_size;
+  if (max_buffers > 0)
+      osst_max_buffers = max_buffers;
+  if (max_sg_segs >= OSST_FIRST_SG)
+      osst_max_sg_segs = max_sg_segs;
+  printk(KERN_INFO "osst: bufsize %d, wrt %d, max buffers %d, s/g segs %d.\n",
+	 osst_buffer_size, osst_write_threshold, osst_max_buffers, osst_max_sg_segs);
+//printk(OSST_DEB_MSG "osst: sizeof(header) = %d (%s)\n",sizeof(os_header_t),sizeof(os_header_t)==OS_DATA_SIZE?"ok":"error");
+  osst_template.module = &__this_module;
+  result = scsi_register_module(MODULE_SCSI_DEV, &osst_template);
+  if (result)
+      return result;
+
+  return 0;
+}
+
+void cleanup_module( void)
+{
+  int i;
+  OS_Scsi_Tape * STp;
+
+  scsi_unregister_module(MODULE_SCSI_DEV, &osst_template);
+#ifdef CONFIG_DEVFS_FS
+  devfs_unregister_chrdev(MAJOR_NR, "osst");
+#else
+  unregister_chrdev(MAJOR_NR, "osst");
+#endif
+  osst_registered--;
+  if(os_scsi_tapes != NULL) {
+    for (i=0; i < osst_template.dev_max; ++i) {
+      if ((STp = os_scsi_tapes[i])) {
+	if (STp->header_cache != NULL) vfree(STp->header_cache);
+	kfree(STp);
+      }
+    }
+    kfree(os_scsi_tapes);
+
+    if (osst_buffers != NULL) {
+      for (i=0; i < osst_nbr_buffers; i++)
+	if (osst_buffers[i] != NULL) {
+	  osst_buffers[i]->orig_sg_segs = 0;
+	  normalize_buffer(osst_buffers[i]);
+	  kfree(osst_buffers[i]);
+	}
+
+      kfree(osst_buffers);
+    }
+  }
+  osst_template.dev_max = 0;
+  printk(KERN_INFO "osst: Unloaded.\n");
+}
+#endif /* MODULE */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/osst.h linux.19p18/drivers/scsi/osst.h
--- linux.vanilla/drivers/scsi/osst.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/scsi/osst.h	Sun Feb 25 23:37:01 2001
@@ -0,0 +1,514 @@
+/*
+ *	$Header: /home/cvsroot/Driver/osst.h,v 1.5.2.2 2000/10/08 03:07:33 riede Exp $
+ */
+
+#include <linux/config.h>
+#ifdef CONFIG_DEVFS_FS
+#include <linux/devfs_fs_kernel.h>
+#endif
+
+/*	FIXME - rename and use the following two types or delete them!
+ *              and the types really should go to st.h anyway...
+ *	INQUIRY packet command - Data Format (From Table 6-8 of QIC-157C)
+ */
+typedef struct {
+	unsigned	device_type	:5;	/* Peripheral Device Type */
+	unsigned	reserved0_765	:3;	/* Peripheral Qualifier - Reserved */
+	unsigned	reserved1_6t0	:7;	/* Reserved */
+	unsigned	rmb		:1;	/* Removable Medium Bit */
+	unsigned	ansi_version	:3;	/* ANSI Version */
+	unsigned	ecma_version	:3;	/* ECMA Version */
+	unsigned	iso_version	:2;	/* ISO Version */
+	unsigned	response_format :4;	/* Response Data Format */
+	unsigned	reserved3_45	:2;	/* Reserved */
+	unsigned	reserved3_6	:1;	/* TrmIOP - Reserved */
+	unsigned	reserved3_7	:1;	/* AENC - Reserved */
+	u8		additional_length;	/* Additional Length (total_length-4) */
+	u8		rsv5, rsv6, rsv7;	/* Reserved */
+	u8		vendor_id[8];		/* Vendor Identification */
+	u8		product_id[16];		/* Product Identification */
+	u8		revision_level[4];	/* Revision Level */
+	u8		vendor_specific[20];	/* Vendor Specific - Optional */
+	u8		reserved56t95[40];	/* Reserved - Optional */
+						/* Additional information may be returned */
+} idetape_inquiry_result_t;
+
+/*
+ *	READ POSITION packet command - Data Format (From Table 6-57)
+ */
+typedef struct {
+	unsigned	reserved0_10	:2;	/* Reserved */
+	unsigned	bpu		:1;	/* Block Position Unknown */	
+	unsigned	reserved0_543	:3;	/* Reserved */
+	unsigned	eop		:1;	/* End Of Partition */
+	unsigned	bop		:1;	/* Beginning Of Partition */
+	u8		partition;		/* Partition Number */
+	u8		reserved2, reserved3;	/* Reserved */
+	u32		first_block;		/* First Block Location */
+	u32		last_block;		/* Last Block Location (Optional) */
+	u8		reserved12;		/* Reserved */
+	u8		blocks_in_buffer[3];	/* Blocks In Buffer - (Optional) */
+	u32		bytes_in_buffer;	/* Bytes In Buffer (Optional) */
+} idetape_read_position_result_t;
+
+/*
+ *      Follows structures which are related to the SELECT SENSE / MODE SENSE
+ *      packet commands. 
+ */
+#define COMPRESSION_PAGE           0x0f
+#define COMPRESSION_PAGE_LENGTH    16
+
+#define CAPABILITIES_PAGE          0x2a
+#define CAPABILITIES_PAGE_LENGTH   20
+
+#define TAPE_PARAMTR_PAGE          0x2b
+#define TAPE_PARAMTR_PAGE_LENGTH   16
+
+#define NUMBER_RETRIES_PAGE        0x2f
+#define NUMBER_RETRIES_PAGE_LENGTH 4
+
+#define BLOCK_SIZE_PAGE            0x30
+#define BLOCK_SIZE_PAGE_LENGTH     4
+
+#define BUFFER_FILLING_PAGE        0x33
+#define BUFFER_FILLING_PAGE_LENGTH 
+
+#define VENDOR_IDENT_PAGE          0x36
+#define VENDOR_IDENT_PAGE_LENGTH   8
+
+#define LOCATE_STATUS_PAGE         0x37
+#define LOCATE_STATUS_PAGE_LENGTH  0
+
+#define MODE_HEADER_LENGTH         4
+
+
+/*
+ *	REQUEST SENSE packet command result - Data Format.
+ */
+typedef struct {
+	unsigned	error_code	:7;	/* Current of deferred errors */
+	unsigned	valid		:1;	/* The information field conforms to QIC-157C */
+	u8		reserved1	:8;	/* Segment Number - Reserved */
+	unsigned	sense_key	:4;	/* Sense Key */
+	unsigned	reserved2_4	:1;	/* Reserved */
+	unsigned	ili		:1;	/* Incorrect Length Indicator */
+	unsigned	eom		:1;	/* End Of Medium */
+	unsigned	filemark 	:1;	/* Filemark */
+	u32		information __attribute__ ((packed));
+	u8		asl;			/* Additional sense length (n-7) */
+	u32		command_specific;	/* Additional command specific information */
+	u8		asc;			/* Additional Sense Code */
+	u8		ascq;			/* Additional Sense Code Qualifier */
+	u8		replaceable_unit_code;	/* Field Replaceable Unit Code */
+	unsigned	sk_specific1 	:7;	/* Sense Key Specific */
+	unsigned	sksv		:1;	/* Sense Key Specific information is valid */
+	u8		sk_specific2;		/* Sense Key Specific */
+	u8		sk_specific3;		/* Sense Key Specific */
+	u8		pad[2];			/* Padding to 20 bytes */
+} idetape_request_sense_result_t;
+
+/*
+ *      Mode Parameter Header for the MODE SENSE packet command
+ */
+typedef struct {
+        u8              mode_data_length;       /* Length of the following data transfer */
+        u8              medium_type;            /* Medium Type */
+        u8              dsp;                    /* Device Specific Parameter */
+        u8              bdl;                    /* Block Descriptor Length */
+} osst_mode_parameter_header_t;
+
+/*
+ *      Mode Parameter Block Descriptor the MODE SENSE packet command
+ *
+ *      Support for block descriptors is optional.
+ */
+typedef struct {
+        u8              density_code;           /* Medium density code */
+        u8              blocks[3];              /* Number of blocks */
+        u8              reserved4;              /* Reserved */
+        u8              length[3];              /* Block Length */
+} osst_parameter_block_descriptor_t;
+
+/*
+ *      The Data Compression Page, as returned by the MODE SENSE packet command.
+ */
+typedef struct {
+        unsigned        page_code       :6;     /* Page Code - Should be 0xf */
+        unsigned        reserved0       :1;     /* Reserved */
+        unsigned        ps              :1;
+        u8              page_length;            /* Page Length - Should be 14 */
+        unsigned        reserved2       :6;     /* Reserved */
+        unsigned        dcc             :1;     /* Data Compression Capable */
+        unsigned        dce             :1;     /* Data Compression Enable */
+        unsigned        reserved3       :5;     /* Reserved */
+        unsigned        red             :2;     /* Report Exception on Decompression */
+        unsigned        dde             :1;     /* Data Decompression Enable */
+        u32             ca;                     /* Compression Algorithm */
+        u32             da;                     /* Decompression Algorithm */
+        u8              reserved[4];            /* Reserved */
+} osst_data_compression_page_t;
+
+/*
+ *      The Medium Partition Page, as returned by the MODE SENSE packet command.
+ */
+typedef struct {
+        unsigned        page_code       :6;     /* Page Code - Should be 0x11 */
+        unsigned        reserved1_6     :1;     /* Reserved */
+        unsigned        ps              :1;
+        u8              page_length;            /* Page Length - Should be 6 */
+        u8              map;                    /* Maximum Additional Partitions - Should be 0 */
+        u8              apd;                    /* Additional Partitions Defined - Should be 0 */
+        unsigned        reserved4_012   :3;     /* Reserved */
+        unsigned        psum            :2;     /* Should be 0 */
+        unsigned        idp             :1;     /* Should be 0 */
+        unsigned        sdp             :1;     /* Should be 0 */
+        unsigned        fdp             :1;     /* Fixed Data Partitions */
+        u8              mfr;                    /* Medium Format Recognition */
+        u8              reserved[2];            /* Reserved */
+} osst_medium_partition_page_t;
+
+/*
+ *      Capabilities and Mechanical Status Page
+ */
+typedef struct {
+        unsigned        page_code       :6;     /* Page code - Should be 0x2a */
+        unsigned        reserved1_67    :2;
+        u8              page_length;            /* Page Length - Should be 0x12 */
+        u8              reserved2, reserved3;
+        unsigned        ro              :1;     /* Read Only Mode */
+        unsigned        reserved4_1234  :4;
+        unsigned        sprev           :1;     /* Supports SPACE in the reverse direction */
+        unsigned        reserved4_67    :2;
+        unsigned        reserved5_012   :3;
+        unsigned        efmt            :1;     /* Supports ERASE command initiated formatting */
+        unsigned        reserved5_4     :1;
+        unsigned        qfa             :1;     /* Supports the QFA two partition formats */
+        unsigned        reserved5_67    :2;
+        unsigned        lock            :1;     /* Supports locking the volume */
+        unsigned        locked          :1;     /* The volume is locked */
+        unsigned        prevent         :1;     /* The device defaults in the prevent state after power up */
+        unsigned        eject           :1;     /* The device can eject the volume */
+	unsigned        reserved6_45    :2;     /* Reserved */  
+        unsigned        ecc             :1;     /* Supports error correction */
+        unsigned        cmprs           :1;     /* Supports data compression */
+        unsigned        reserved7_0     :1;
+        unsigned        blk512          :1;     /* Supports 512 bytes block size */
+        unsigned        blk1024         :1;     /* Supports 1024 bytes block size */
+        unsigned        reserved7_3_6   :4;
+        unsigned        blk32768        :1;     /* slowb - the device restricts the byte count for PIO */
+                                                /* transfers for slow buffer memory ??? */
+                                                /* Also 32768 block size in some cases */
+        u16             max_speed;              /* Maximum speed supported in KBps */
+        u8              reserved10, reserved11;
+        u16             ctl;                    /* Continuous Transfer Limit in blocks */
+        u16             speed;                  /* Current Speed, in KBps */
+        u16             buffer_size;            /* Buffer Size, in 512 bytes */
+        u8              reserved18, reserved19;
+} osst_capabilities_page_t;
+
+/*
+ *      Block Size Page
+ */
+typedef struct {
+        unsigned        page_code       :6;     /* Page code - Should be 0x30 */
+        unsigned        reserved1_6     :1;
+        unsigned        ps              :1;
+        u8              page_length;            /* Page Length - Should be 2 */
+        u8              reserved2;
+        unsigned        play32          :1;
+        unsigned        play32_5        :1;
+        unsigned        reserved2_23    :2;
+        unsigned        record32        :1;
+        unsigned        record32_5      :1;
+        unsigned        reserved2_6     :1;
+        unsigned        one             :1;
+} osst_block_size_page_t;
+
+/*
+ *	Tape Parameters Page
+ */
+typedef struct {
+        unsigned        page_code       :6;     /* Page code - Should be 0x2b */
+        unsigned        reserved1_6     :1;
+        unsigned        ps              :1;
+	u8		reserved2;
+	u8		density;
+	u8		reserved3,reserved4;
+	u16		segtrk;
+	u16		trks;
+	u8		reserved5,reserved6,reserved7,reserved8,reserved9,reserved10;
+} osst_tape_paramtr_page_t;
+
+/* OnStream definitions */
+
+#define OS_CONFIG_PARTITION     (0xff)
+#define OS_DATA_PARTITION       (0)
+#define OS_PARTITION_VERSION    (1)
+
+/*
+ * partition
+ */
+typedef struct os_partition_s {
+        __u8    partition_num;
+        __u8    par_desc_ver;
+        __u16   wrt_pass_cntr;
+        __u32   first_frame_ppos;
+        __u32   last_frame_ppos;
+        __u32   eod_frame_ppos;
+} os_partition_t;
+
+/*
+ * DAT entry
+ */
+typedef struct os_dat_entry_s {
+        __u32   blk_sz;
+        __u16   blk_cnt;
+        __u8    flags;
+        __u8    reserved;
+} os_dat_entry_t;
+
+/*
+ * DAT
+ */
+#define OS_DAT_FLAGS_DATA       (0xc)
+#define OS_DAT_FLAGS_MARK       (0x1)
+
+typedef struct os_dat_s {
+        __u8            dat_sz;
+        __u8            reserved1;
+        __u8            entry_cnt;
+        __u8            reserved3;
+        os_dat_entry_t  dat_list[16];
+} os_dat_t;
+
+/*
+ * Frame types
+ */
+#define OS_FRAME_TYPE_FILL      (0)
+#define OS_FRAME_TYPE_EOD       (1 << 0)
+#define OS_FRAME_TYPE_MARKER    (1 << 1)
+#define OS_FRAME_TYPE_HEADER    (1 << 3)
+#define OS_FRAME_TYPE_DATA      (1 << 7)
+
+/*
+ * AUX
+ */
+typedef struct os_aux_s {
+        __u32           format_id;              /* hardware compability AUX is based on */
+        char            application_sig[4];     /* driver used to write this media */
+        __u32           hdwr;                   /* reserved */
+        __u32           update_frame_cntr;      /* for configuration frame */
+        __u8            frame_type;
+        __u8            frame_type_reserved;
+        __u8            reserved_18_19[2];
+        os_partition_t  partition;
+        __u8            reserved_36_43[8];
+        __u32           frame_seq_num;
+        __u32           logical_blk_num_high;
+        __u32           logical_blk_num;
+        os_dat_t        dat;
+        __u8            reserved188_191[4];
+        __u32           filemark_cnt;
+        __u32           phys_fm;
+        __u32           last_mark_ppos;
+        __u8            reserved204_223[20];
+
+        /*
+         * __u8         app_specific[32];
+         *
+         * Linux specific fields:
+         */
+         __u32          next_mark_ppos;         /* when known, points to next marker */
+         __u8           linux_specific[28];
+
+        __u8            reserved_256_511[256];
+} os_aux_t;
+
+#define OS_FM_TAB_MAX 1024
+
+typedef struct os_fm_tab_s {
+	__u8		fm_part_num;
+	__u8		reserved_1;
+	__u8		fm_tab_ent_sz;
+	__u8		reserved_3;
+	__u16		fm_tab_ent_cnt;
+	__u8		reserved6_15[10];
+	__u32		fm_tab_ent[OS_FM_TAB_MAX];
+} os_fm_tab_t;
+
+typedef struct os_ext_trk_ey_s {
+	__u8		et_part_num;
+	__u8		fmt;
+	__u16		fm_tab_off;
+	__u8		reserved4_7[4];
+	__u32		last_hlb_hi;
+	__u32		last_hlb;
+	__u32		last_pp;
+	__u8		reserved20_31[12];
+} os_ext_trk_ey_t;
+
+typedef struct os_ext_trk_tb_s {
+	__u8		nr_stream_part;
+	__u8		reserved_1;
+	__u8		et_ent_sz;
+	__u8		reserved3_15[13];
+	os_ext_trk_ey_t	dat_ext_trk_ey;
+	os_ext_trk_ey_t	qfa_ext_trk_ey;
+} os_ext_trk_tb_t;
+
+typedef struct os_header_s {
+        char            ident_str[8];
+        __u8            major_rev;
+        __u8            minor_rev;
+	__u16		ext_trk_tb_off;
+        __u8            reserved12_15[4];
+        __u8            pt_par_num;
+        __u8            pt_reserved1_3[3];
+        os_partition_t  partition[16];
+	__u32		cfg_col_width;
+	__u32		dat_col_width;
+	__u32		qfa_col_width;
+	__u8		cartridge[16];
+	__u8		reserved304_511[208];
+	__u32		old_filemark_list[16680/4];		/* in ADR 1.4 __u8 track_table[16680] */
+	os_ext_trk_tb_t	ext_track_tb;
+	__u8		reserved17272_17735[464];
+	os_fm_tab_t	dat_fm_tab;
+	os_fm_tab_t	qfa_fm_tab;
+	__u8		reserved25960_32767[6808];
+} os_header_t;
+
+
+/*
+ * OnStream ADRL frame
+ */
+#define OS_FRAME_SIZE   (32 * 1024 + 512)
+#define OS_DATA_SIZE    (32 * 1024)
+#define OS_AUX_SIZE     (512)
+//#define OSST_MAX_SG      2
+
+/* The tape buffer descriptor. */
+typedef struct {
+  unsigned char in_use;
+  unsigned char dma;	/* DMA-able buffer */
+  int this_size;        /* allocated size of the structure */
+  int buffer_size;
+  int buffer_blocks;
+  int buffer_bytes;
+  int read_pointer;
+  int writing;
+  int last_result;
+  int last_result_fatal;
+  Scsi_Cmnd *last_SCpnt;
+  unsigned char *b_data;
+  os_aux_t *aux;               /* onstream AUX structure at end of each block */
+  unsigned short use_sg;       /* zero or number of segments for this adapter */
+  unsigned short sg_segs;      /* total number of allocated segments */
+  unsigned short orig_sg_segs; /* number of segments allocated at first try */
+  struct scatterlist sg[1];    /* MUST BE last item */
+} OSST_buffer;
+
+/* The tape drive descriptor */
+typedef struct {
+  kdev_t devt;
+  unsigned capacity;
+  Scsi_Device* device;
+  struct semaphore sem;
+  OSST_buffer * buffer;
+
+  /* Drive characteristics */
+  unsigned char omit_blklims;
+  unsigned char do_auto_lock;
+  unsigned char can_bsr;
+  unsigned char can_partitions;
+  unsigned char two_fm;
+  unsigned char fast_mteom;
+  unsigned char restr_dma;
+  unsigned char scsi2_logical;
+  unsigned char default_drvbuffer;  /* 0xff = don't touch, value 3 bits */
+  int write_threshold;
+  int timeout;			/* timeout for normal commands */
+  int long_timeout;		/* timeout for commands known to take long time*/
+
+  /* Mode characteristics */
+  ST_mode modes[ST_NBR_MODES];
+  int current_mode;
+#ifdef CONFIG_DEVFS_FS
+  devfs_handle_t de_r[ST_NBR_MODES];  /*  Rewind entries     */
+  devfs_handle_t de_n[ST_NBR_MODES];  /*  No-rewind entries  */
+#endif
+
+  /* Status variables */
+  int partition;
+  int new_partition;
+  int nbr_partitions;    /* zero until partition support enabled */
+  ST_partstat ps[ST_NBR_PARTITIONS];
+  unsigned char dirty;
+  unsigned char ready;
+  unsigned char write_prot;
+  unsigned char drv_write_prot;
+  unsigned char in_use;
+  unsigned char blksize_changed;
+  unsigned char density_changed;
+  unsigned char compression_changed;
+  unsigned char drv_buffer;
+  unsigned char density;
+  unsigned char door_locked;
+  unsigned char rew_at_close;
+  int block_size;
+  int min_block;
+  int max_block;
+  int recover_count;            /* from tape opening */
+  int recover_erreg;            /* from last status call */
+  /*
+   * OnStream specific data
+   */
+  int	   os_fw_rev;			       /* the firmware revision * 10000 */
+  unsigned char  raw;                          /* flag OnStream raw access (32.5KB block size) */
+  unsigned char  poll;                         /* flag that this drive needs polling (IDE|firmware) */
+  unsigned char  logical_blk_in_buffer;	       /* flag that the block as per logical_blk_num
+						* has been read into STp->buffer and is valid */
+  int      logical_blk_num;                    /* logical block number */
+  unsigned first_frame_position;               /* physical frame to be transfered to/from host */
+  unsigned last_frame_position;                /* physical frame to be transferd to/from tape */
+  int      cur_frames;                         /* current number of frames in internal buffer */
+  int      max_frames;                         /* max number of frames in internal buffer */
+  char     application_sig[5];                 /* application signature */
+  unsigned char  fast_open;                    /* flag that reminds us we didn't check headers at open */
+  unsigned short wrt_pass_cntr;                /* write pass counter */
+  int      update_frame_cntr;                  /* update frame counter */
+  int      onstream_write_error;               /* write error recovery active */
+  int      header_ok;                          /* header frame verified ok */
+  int      linux_media;                        /* reading linux-specifc media */
+  int      linux_media_version;
+  os_header_t * header_cache;		       /* cache is kept for filemark positions */
+  int      filemark_cnt;
+  int      first_mark_ppos;
+  int      last_mark_ppos;
+  int      first_data_ppos;
+  int      eod_frame_ppos;
+  int      eod_frame_lfa;
+  int      write_type;				/* used in write error recovery */
+  int      read_error_frame;			/* used in read error recovery */
+  unsigned long cmd_start_time;
+  unsigned long max_cmd_time;
+
+#if DEBUG
+  unsigned char write_pending;
+  int nbr_finished;
+  int nbr_waits;
+  unsigned char last_cmnd[6];
+  unsigned char last_sense[16];
+#endif
+} OS_Scsi_Tape;
+
+extern Scsi_Tape * scsi_tapes;
+
+/* Values of write_type */
+#define OS_WRITE_DATA      0
+#define OS_WRITE_EOD       1
+#define OS_WRITE_NEW_MARK  2
+#define OS_WRITE_LAST_MARK 3
+#define OS_WRITE_HEADER    4
+#define OS_WRITE_FILLER    5
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/osst_detect.h linux.19p18/drivers/scsi/osst_detect.h
--- linux.vanilla/drivers/scsi/osst_detect.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/scsi/osst_detect.h	Wed Dec 13 21:31:48 2000
@@ -0,0 +1,5 @@
+#define OSST_SUPPORTS(SDp) (! ( memcmp (SDp->vendor, "OnStream", 8) || \
+			     ( memcmp (SDp->model, "SC-", 3) && \
+			       memcmp (SDp->model, "DI-", 3) && \
+			       memcmp (SDp->model, "DP-", 3) && \
+			       memcmp (SDp->model, "USB", 3) ) ) )
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/osst_options.h linux.19p18/drivers/scsi/osst_options.h
--- linux.vanilla/drivers/scsi/osst_options.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/scsi/osst_options.h	Wed Dec 13 21:31:48 2000
@@ -0,0 +1,100 @@
+/*
+   The compile-time configurable defaults for the Linux SCSI tape driver.
+
+   Copyright 1995 Kai Makisara.
+   
+   Last modified: Wed Sep  2 21:24:07 1998 by root@home
+   
+   Changed (and renamed) for OnStream SCSI drives garloff@suse.de
+   2000-06-21
+
+   $Header: /home/cvsroot/Driver/osst_options.h,v 1.4 2000/06/26 01:44:01 riede Exp $
+*/
+
+#ifndef _OSST_OPTIONS_H
+#define _OSST_OPTIONS_H
+
+/* The minimum limit for the number of SCSI tape devices is determined by
+   OSST_MAX_TAPES. If the number of tape devices and the "slack" defined by
+   OSST_EXTRA_DEVS exceeds OSST_MAX_TAPES, the large number is used. */
+#define OSST_MAX_TAPES 4
+
+/* If OSST_IN_FILE_POS is nonzero, the driver positions the tape after the
+   record been read by the user program even if the tape has moved further
+   because of buffered reads. Should be set to zero to support also drives
+   that can't space backwards over records. NOTE: The tape will be
+   spaced backwards over an "accidentally" crossed filemark in any case. */
+#define OSST_IN_FILE_POS 0
+
+/* The tape driver buffer size in kilobytes. */
+/* Don't change, as this is the HW blocksize */
+#define OSST_BUFFER_BLOCKS 32
+
+/* The number of kilobytes of data in the buffer that triggers an
+   asynchronous write in fixed block mode. See also OSST_ASYNC_WRITES
+   below. */
+#define OSST_WRITE_THRESHOLD_BLOCKS 30
+
+/* The maximum number of tape buffers the driver allocates. The number
+   is also constrained by the number of drives detected. Determines the
+   maximum number of concurrently active tape drives. */
+#define OSST_MAX_BUFFERS OSST_MAX_TAPES 
+
+/* Maximum number of scatter/gather segments */
+/* Fit one buffer in pages and add one for the AUX header */
+#define OSST_MAX_SG      (((OSST_BUFFER_BLOCKS*1024) / PAGE_SIZE) + 1)
+
+/* The number of scatter/gather segments to allocate at first try (must be
+   smaller or equal to the maximum). */
+#define OSST_FIRST_SG    ((OSST_BUFFER_BLOCKS*1024) / PAGE_SIZE)
+
+/* The size of the first scatter/gather segments (determines the maximum block
+   size for SCSI adapters not supporting scatter/gather). The default is set
+   to try to allocate the buffer as one chunk. */
+#define OSST_FIRST_ORDER  5
+
+
+/* The following lines define defaults for properties that can be set
+   separately for each drive using the MTSTOPTIONS ioctl. */
+
+/* If OSST_TWO_FM is non-zero, the driver writes two filemarks after a
+   file being written. Some drives can't handle two filemarks at the
+   end of data. */
+#define OSST_TWO_FM 0
+
+/* If OSST_BUFFER_WRITES is non-zero, writes in fixed block mode are
+   buffered until the driver buffer is full or asynchronous write is
+   triggered. May make detection of End-Of-Medium early enough fail. */
+#define OSST_BUFFER_WRITES 1
+
+/* If OSST_ASYNC_WRITES is non-zero, the SCSI write command may be started
+   without waiting for it to finish. May cause problems in multiple
+   tape backups. */
+#define OSST_ASYNC_WRITES 1
+
+/* If OSST_READ_AHEAD is non-zero, blocks are read ahead in fixed block
+   mode. */
+#define OSST_READ_AHEAD 1
+
+/* If OSST_AUTO_LOCK is non-zero, the drive door is locked at the first
+   read or write command after the device is opened. The door is opened
+   when the device is closed. */
+#define OSST_AUTO_LOCK 0
+
+/* If OSST_FAST_MTEOM is non-zero, the MTEOM ioctl is done using the
+   direct SCSI command. The file number status is lost but this method
+   is fast with some drives. Otherwise MTEOM is done by spacing over
+   files and the file number status is retained. */
+#define OSST_FAST_MTEOM 0
+
+/* If OSST_SCSI2LOGICAL is nonzero, the logical block addresses are used for
+   MTIOCPOS and MTSEEK by default. Vendor addresses are used if OSST_SCSI2LOGICAL
+   is zero. */
+#define OSST_SCSI2LOGICAL 0
+
+/* If OSST_SYSV is non-zero, the tape behaves according to the SYS V semantics.
+   The default is BSD semantics. */
+#define OSST_SYSV 0
+
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/ppa.c linux.19p18/drivers/scsi/ppa.c
--- linux.vanilla/drivers/scsi/ppa.c	Mon Dec 11 22:12:54 2000
+++ linux.19p18/drivers/scsi/ppa.c	Wed Jan  3 00:57:16 2001
@@ -31,6 +31,7 @@
     Scsi_Cmnd *cur_cmd;		/* Current queued command       */
     struct tq_struct ppa_tq;	/* Polling interupt stuff       */
     unsigned long jstart;	/* Jiffies at start             */
+    unsigned long recon_tmo;    /* How many usecs to wait for reconnection (6th bit) */
     unsigned int failed:1;	/* Failure flag                 */
     unsigned int p_busy:1;	/* Parport sharing busy flag    */
 } ppa_struct;
@@ -43,6 +44,7 @@
 	cur_cmd:	NULL,		\
 	ppa_tq:		{0, 0, ppa_interrupt, NULL},	\
 	jstart:		0,		\
+	recon_tmo:      PPA_RECON_TMO,	\
 	failed:		0,		\
 	p_busy:		0		\
 }
@@ -236,6 +238,12 @@
 	ppa_hosts[hostno].mode = x;
 	return length;
     }
+    if ((length > 10) && (strncmp(buffer, "recon_tmo=", 10) == 0)) {
+	x = simple_strtoul(buffer + 10, NULL, 0);
+	ppa_hosts[hostno].recon_tmo = x;
+        printk("ppa: recon_tmo set to %ld\n", x);
+	return length;
+    }
     printk("ppa /proc: invalid variable\n");
     return (-EINVAL);
 }
@@ -256,6 +264,9 @@
     len += sprintf(buffer + len, "Version : %s\n", PPA_VERSION);
     len += sprintf(buffer + len, "Parport : %s\n", ppa_hosts[i].dev->port->name);
     len += sprintf(buffer + len, "Mode    : %s\n", PPA_MODE_STRING[ppa_hosts[i].mode]);
+#if PPA_DEBUG > 0
+    len += sprintf(buffer + len, "recon_tmo : %lu\n", ppa_hosts[i].recon_tmo);
+#endif
 
     /* Request for beyond end of buffer */
     if (offset > length)
@@ -299,12 +310,11 @@
     unsigned char r;
 
     k = PPA_SPIN_TMO;
-    do {
-	r = r_str(ppb);
-	k--;
-	udelay(1);
+    /* Wait for bit 6 and 7 - PJC */
+    for (r = r_str (ppb); ((r & 0xc0)!=0xc0) && (k); k--) {
+	    udelay (1);
+	    r = r_str (ppb);
     }
-    while (!(r & 0x80) && (k));
 
     /*
      * return some status information.
@@ -545,6 +555,7 @@
     k = PPA_SELECT_TMO;
     do {
 	k--;
+	udelay(1);
     } while ((r_str(ppb) & 0x40) && (k));
     if (!k)
 	return 0;
@@ -558,6 +569,7 @@
     k = PPA_SELECT_TMO;
     do {
 	k--;
+	udelay(1);
     }
     while (!(r_str(ppb) & 0x40) && (k));
     if (!k)
@@ -667,12 +679,36 @@
 	if (time_after(jiffies, start_jiffies + 1))
 	    return 0;
 
-	if (((r & 0xc0) != 0xc0) || (cmd->SCp.this_residual <= 0)) {
+	if ((cmd->SCp.this_residual <= 0)) {
 	    ppa_fail(host_no, DID_ERROR);
 	    return -1;		/* ERROR_RETURN */
 	}
-	/* determine if we should use burst I/O */ fast = (bulk && (cmd->SCp.this_residual >= PPA_BURST_SIZE))
-	    ? PPA_BURST_SIZE : 1;
+
+	/* On some hardware we have SCSI disconnected (6th bit low)
+	 * for about 100usecs. It is too expensive to wait a 
+	 * tick on every loop so we busy wait for no more than
+	 * 500usecs to give the drive a chance first. We do not 
+	 * change things for "normal" hardware since generally 
+	 * the 6th bit is always high.
+	 * This makes the CPU load higher on some hardware 
+	 * but otherwise we can not get more then 50K/secs 
+	 * on this problem hardware.
+	 */
+	if ((r & 0xc0) != 0xc0) {
+	   /* Wait for reconnection should be no more than 
+	    * jiffy/2 = 5ms = 5000 loops
+	    */
+	   unsigned long k = ppa_hosts[host_no].recon_tmo; 
+	   for (; k && ((r = (r_str(ppb) & 0xf0)) & 0xc0) != 0xc0; k--)
+	     udelay(1);
+
+	   if(!k) 
+	     return 0;
+	}	   
+
+	/* determine if we should use burst I/O */ 
+	fast = (bulk && (cmd->SCp.this_residual >= PPA_BURST_SIZE)) 
+	     ? PPA_BURST_SIZE : 1;
 
 	if (r == (unsigned char) 0xc0)
 	    status = ppa_out(host_no, cmd->SCp.ptr, fast);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/ppa.h linux.19p18/drivers/scsi/ppa.h
--- linux.vanilla/drivers/scsi/ppa.h	Sat Sep  9 18:42:41 2000
+++ linux.19p18/drivers/scsi/ppa.h	Sat Mar 10 23:30:12 2001
@@ -10,7 +10,7 @@
 #ifndef _PPA_H
 #define _PPA_H
 
-#define   PPA_VERSION   "2.03 (for Linux 2.2.x)"
+#define   PPA_VERSION   "2.07 (for Linux 2.2.x)"
 
 /* 
  * this driver has been hacked by Matteo Frigo (athena@theory.lcs.mit.edu)
@@ -51,6 +51,17 @@
  *    CONFIG_SCSI_PPA_HAVE_PEDANTIC => CONFIG_SCSI_IZIP_EPP16
  *    added CONFIG_SCSI_IZIP_SLOW_CTR option
  *                                                      [2.03]
+ *
+ * Use ppa_wait() to check for ready AND connected status bits
+ * Busy wait for connected status bit in ppa_completion()
+ *  in order to cope with some hardware that has this bit low
+ *  for short periods of time.
+ * Add udelay() to ppa_select()
+ *  by Dr. Peter Cherriman and
+ *     Oleg Makarenko <omakarenko@cyberplat.ru>
+ *                                                      [2.04a]
+ *
+ * Fix kernel panic on scsi timeout, 2000-08-18		[2.07]
  */
 /* ------ END OF USER CONFIGURABLE PARAMETERS ----- */
 
@@ -106,6 +117,7 @@
 #define PPA_BURST_SIZE	512	/* data burst size */
 #define PPA_SELECT_TMO  5000	/* how long to wait for target ? */
 #define PPA_SPIN_TMO    50000	/* ppa_wait loop limiter */
+#define PPA_RECON_TMO   500	/* scsi reconnection loop limiter */
 #define PPA_DEBUG	0	/* debuging option */
 #define IN_EPP_MODE(x) (x == PPA_EPP_8 || x == PPA_EPP_16 || x == PPA_EPP_32)
 
@@ -166,6 +178,7 @@
 		eh_device_reset_handler:	NULL,			\
 		eh_bus_reset_handler:		ppa_reset,		\
 		eh_host_reset_handler:		ppa_reset,		\
+		use_new_eh_code:		1,			\
 		bios_param:			ppa_biosparam,		\
 		this_id:			-1,			\
 		sg_tablesize:			SG_ALL,			\
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/scsi.h linux.19p18/drivers/scsi/scsi.h
--- linux.vanilla/drivers/scsi/scsi.h	Fri Apr 21 23:20:05 2000
+++ linux.19p18/drivers/scsi/scsi.h	Sat Mar  3 22:43:56 2001
@@ -634,7 +634,7 @@
 extern int scsi_mlqueue_finish(struct Scsi_Host * host, Scsi_Device * device);
 
 
-#if defined(MAJOR_NR) && (MAJOR_NR != SCSI_TAPE_MAJOR)
+#if defined(MAJOR_NR) && (MAJOR_NR != SCSI_TAPE_MAJOR) && (MAJOR_NR != OSST_MAJOR)
 #include "hosts.h"
 
 static Scsi_Cmnd * end_scsi_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/scsiiom.c linux.19p18/drivers/scsi/scsiiom.c
--- linux.vanilla/drivers/scsi/scsiiom.c	Fri Apr 21 12:46:31 2000
+++ linux.19p18/drivers/scsi/scsiiom.c	Sat Dec 30 19:46:46 2000
@@ -4,16 +4,40 @@
  *	Description: Device Driver for Tekram DC-390 (T) PCI SCSI      *
  *		     Bus Master Host Adapter			       *
  ***********************************************************************/
-/* $Id: scsiiom.c,v 2.15 1998/12/25 17:33:27 garloff Exp $ */
+/* $Id: scsiiom.c,v 2.55.2.17 2000/12/20 00:39:37 garloff Exp $ */
+
+static void __inline__
+dc390_freetag (PDCB pDCB, PSRB pSRB)
+{
+	if (pSRB->TagNumber < 255) {
+		pDCB->TagMask &= ~(1 << pSRB->TagNumber);   /* free tag mask */
+		pSRB->TagNumber = 255;
+	}
+};
+
 
 UCHAR
 dc390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB )
 {
-    USHORT wlval;
-    UCHAR  bval, bval1;
+    UCHAR cmd; UCHAR  disc_allowed, try_sync_nego;
+
+    pSRB->ScsiPhase = SCSI_NOP0;
 
-    pSRB->TagNumber = 31;
-    DC390_write8 (Scsi_Dest_ID, pDCB->UnitSCSIID);
+    if (pACB->Connected)
+    {
+	// Should not happen normally
+	printk (KERN_WARNING "DC390: Can't select when connected! (%08x,%02x)\n",
+		pSRB->SRBState, pSRB->SRBFlag);
+	pSRB->SRBState = SRB_READY;
+	pACB->SelConn++;
+	return 1;
+    }
+    if (time_before (jiffies, pACB->pScsiHost->last_reset))
+    {
+	DEBUG0(printk ("DC390: We were just reset and don't accept commands yet!\n");)
+	return 1;
+    }
+    DC390_write8 (Scsi_Dest_ID, pDCB->TargetID);
     DC390_write8 (Sync_Period, pDCB->SyncPeriod);
     DC390_write8 (Sync_Offset, pDCB->SyncOffset);
     DC390_write8 (CtrlReg1, pDCB->CtrlR1);
@@ -21,151 +45,105 @@
     DC390_write8 (CtrlReg4, pDCB->CtrlR4);
     DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);		/* Flush FIFO */
     DEBUG1(printk (KERN_INFO "DC390: Start SCSI command: %02x (Sync:%02x)\n",\
-	    pSRB->CmdBlock[0], pDCB->SyncMode);)
-    pSRB->ScsiPhase = SCSI_NOP0;
-    //pSRB->MsgOutBuf[0] = MSG_NOP;
-    //pSRB->MsgCnt = 0;
-    bval = pDCB->IdentifyMsg;
-    if( !(pDCB->SyncMode & EN_ATN_STOP) )	/* Don't always try send Extended messages on arbitration */
-    {
-	if( (pSRB->CmdBlock[0] == INQUIRY) ||
-	    (pSRB->CmdBlock[0] == REQUEST_SENSE) ||
-	    (pSRB->SRBFlag & AUTO_REQSENSE) )
-	{
-	    bval &= 0xBF;	/* No DisConn */
-	    DC390_write8 (ScsiFifo, bval);
-	    bval1 = SEL_W_ATN;
-	    pSRB->SRBState = SRB_START_;
-	    DEBUG1(printk (KERN_DEBUG "DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1);)
-	    if( pDCB->SyncMode & SYNC_ENABLE )
-		{
-		if( !(pDCB->IdentifyMsg & 7) ||		/* LUN == 0 || Cmd != INQUIRY */
-		    (pSRB->CmdBlock[0] != INQUIRY) )
-		{
-		    bval1 = SEL_W_ATN_STOP;	/* Try to establish SYNC nego */
-		    pSRB->SRBState = SRB_MSGOUT;
-		}
-	    }
-	}
-	else	/* TagQ ? */
-	{
-	    DC390_write8 (ScsiFifo, bval);
-	    if(pDCB->SyncMode & EN_TAG_QUEUEING)
-	    {
-	        DC390_write8 (ScsiFifo, MSG_SIMPLE_QTAG);
-		DEBUG1(printk (KERN_DEBUG "DC390: %sDisCn, TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, SEL_W_ATN3, pDCB->TagMask);)
-	        bval = 0; wlval = 1;
-	        while (wlval & pDCB->TagMask)
-		  { bval++; wlval <<= 1; };
-		pDCB->TagMask |= wlval;
-	        DC390_write8 (ScsiFifo, bval);
-		pSRB->TagNumber = bval;
-		DEBUG1(printk (KERN_DEBUG "DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval);)
-		bval1 = SEL_W_ATN3;
-		pSRB->SRBState = SRB_START_;
-	    }
-	    else	/* No TagQ */
-	    {
-		bval1 = SEL_W_ATN;
-		DEBUG1(printk (KERN_DEBUG "DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, bval1, pDCB->TagMask);)
-		pSRB->SRBState = SRB_START_;
-	    }
-	}
+	    pSRB->pcmd->cmnd[0], pDCB->SyncMode);)
+    disc_allowed = pDCB->DevMode & EN_DISCONNECT_; try_sync_nego = 0;
+    /* Don't disconnect on AUTO_REQSENSE, cause it might be an
+     * Contingent Allegiance Condition (6.6), where no tags should be used.
+     * All other have to be allowed to disconnect to prevent Incorrect 
+     * Initiator Connection (6.8.2/6.5.2) */
+    /* Changed KG, 99/06/06 */
+    if( /*(((pSRB->pcmd->cmnd[0] == INQUIRY) || (pSRB->pcmd->cmnd[0] == REQUEST_SENSE) ||
+	 * (pSRB->pcmd->cmnd[0] == TEST_UNIT_READY)) && pACB->scan_devices)
+		||*/ (pSRB->SRBFlag & AUTO_REQSENSE) ) 
+      disc_allowed = 0;
+    if ( (pDCB->SyncMode & SYNC_ENABLE) && (pDCB->TargetLUN == 0) && (pDCB->Inquiry7 & 0x10) &&
+	( ( ( (pSRB->pcmd->cmnd[0] == REQUEST_SENSE) || (pSRB->SRBFlag & AUTO_REQSENSE) )
+	  && !(pDCB->SyncMode & SYNC_NEGO_DONE) ) || (pSRB->pcmd->cmnd[0] == INQUIRY) ) )
+      try_sync_nego = 1;
+
+    pSRB->MsgCnt = 0; cmd = SEL_W_ATN;
+    DC390_write8 (ScsiFifo, IDENTIFY(disc_allowed, pDCB->TargetLUN));
+    /* Change 99/05/31: Don't use tags when not disconnecting (BUSY) */
+    if ((pDCB->SyncMode & EN_TAG_QUEUEING) && disc_allowed)
+      {
+	UCHAR tag_no = 0;
+	while ((1 << tag_no) & pDCB->TagMask) tag_no++;
+	if (tag_no >= sizeof (pDCB->TagMask)*8 || tag_no >= pDCB->MaxCommand) { 
+		printk (KERN_WARNING "DC390: Out of tags for Dev. %02x %02x\n", pDCB->TargetID, pDCB->TargetLUN); 
+		return 1;
+		//goto no_tag;
+	};
+	DC390_write8 (ScsiFifo, SIMPLE_QUEUE_TAG);
+	pDCB->TagMask |= (1 << tag_no); pSRB->TagNumber = tag_no;
+	DC390_write8 (ScsiFifo, tag_no);
+	DEBUG1(printk (KERN_DEBUG "DC390: Select w/DisCn for Cmd %li (SRB %p), Using Tag %02x\n", pSRB->pcmd->pid, pSRB, tag_no);)
+	cmd = SEL_W_ATN3;
+      }
+    else	/* No TagQ */
+      {
+//      no_tag:
+	DEBUG1(printk (KERN_DEBUG "DC390: Select w%s/DisCn for Cmd %li (SRB %p), No TagQ\n", (disc_allowed?"":"o"), pSRB->pcmd->pid, pSRB);) 
+      };
 
-    }
-    else	/* ATN_STOP: Always try to establish Sync nego */
-    {
-	if( (pSRB->CmdBlock[0] == INQUIRY) ||
-	    (pSRB->CmdBlock[0] == REQUEST_SENSE) ||
-	    (pSRB->SRBFlag & AUTO_REQSENSE) )
-	{
-	    bval &= 0xBF;	/* No DisConn */
-	    DC390_write8 (ScsiFifo, bval);
-	    bval1 = SEL_W_ATN;
-	    DEBUG1(printk (KERN_DEBUG "DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1);)
-	    pSRB->SRBState = SRB_START_;
-	      /* ??? */
-	    if( pDCB->SyncMode & SYNC_ENABLE )
-	    {
-		if( !(pDCB->IdentifyMsg & 7) ||		/* LUN == 0 || Cmd != INQUIRY */
-		    (pSRB->CmdBlock[0] != INQUIRY) )
-		{
-		    bval1 = SEL_W_ATN_STOP;	/* Try to establish Sync nego */
-		    pSRB->SRBState = SRB_MSGOUT;
-		}
-	    }
-	}
-	else	/* TagQ ? */
-	{
-	    DC390_write8 (ScsiFifo, bval);
-	    if(pDCB->SyncMode & EN_TAG_QUEUEING)
-	    {
-		pSRB->MsgOutBuf[0] = MSG_SIMPLE_QTAG;
-		DEBUG1(printk (KERN_DEBUG "DC390: %sDisCn, TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, SEL_W_ATN_STOP, pDCB->TagMask);)
-		bval = 0; wlval = 1;
-	        while (wlval & pDCB->TagMask)
-		  { bval++; wlval <<= 1; };
-		pDCB->TagMask |= wlval;
-		pSRB->TagNumber = bval;
-		DEBUG1(printk (KERN_DEBUG "DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval);)
-		pSRB->MsgOutBuf[1] = bval;
-		pSRB->MsgCnt = 2;
-		bval1 = SEL_W_ATN_STOP;
-		pSRB->SRBState = SRB_START_;	/* ?? */
-	    }
-	    else	/* No TagQ */
-	    {
-		pSRB->MsgOutBuf[0] = MSG_NOP;
-		pSRB->MsgCnt = 1;
-		pSRB->SRBState = SRB_START_;
-		bval1 = SEL_W_ATN_STOP;
-		DEBUG1(printk (KERN_DEBUG "DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, bval1, pDCB->TagMask);)
-	    };
-	}
-    }
-    if (bval1 != SEL_W_ATN_STOP)
-      {	/* Command is written in CommandPhase, if SEL_W_ATN_STOP ... */
+    pSRB->SRBState = SRB_START_;
+
+    if (try_sync_nego)
+      { 
+	UCHAR Sync_Off = pDCB->SyncOffset;
+        DEBUG0(printk (KERN_INFO "DC390: NEW Sync Nego code triggered (%i %i)\n", pDCB->TargetID, pDCB->TargetLUN);)
+	pSRB->MsgOutBuf[0] = EXTENDED_MESSAGE;
+	pSRB->MsgOutBuf[1] = 3;
+	pSRB->MsgOutBuf[2] = EXTENDED_SDTR;
+	pSRB->MsgOutBuf[3] = pDCB->NegoPeriod;
+	if (!(Sync_Off & 0x0f)) Sync_Off = SYNC_NEGO_OFFSET;
+	pSRB->MsgOutBuf[4] = Sync_Off;
+	pSRB->MsgCnt = 5;
+	//pSRB->SRBState = SRB_MSGOUT_;
+	pSRB->SRBState |= DO_SYNC_NEGO;
+	cmd = SEL_W_ATN_STOP;
+      };
+
+    /* Command is written in CommandPhase, if SEL_W_ATN_STOP ... */
+    if (cmd != SEL_W_ATN_STOP)
+      {
 	if( pSRB->SRBFlag & AUTO_REQSENSE )
 	  {
-	    bval = 0;
 	    DC390_write8 (ScsiFifo, REQUEST_SENSE);
-	    DC390_write8 (ScsiFifo, pDCB->IdentifyMsg << 5);
-	    DC390_write8 (ScsiFifo, bval);
-	    DC390_write8 (ScsiFifo, bval);
+	    DC390_write8 (ScsiFifo, pDCB->TargetLUN << 5);
+	    DC390_write8 (ScsiFifo, 0);
+	    DC390_write8 (ScsiFifo, 0);
 	    DC390_write8 (ScsiFifo, sizeof(pSRB->pcmd->sense_buffer));
-	    DC390_write8 (ScsiFifo, bval);
+	    DC390_write8 (ScsiFifo, 0);
 	    DEBUG1(printk (KERN_DEBUG "DC390: AutoReqSense !\n");)
 	  }
 	else	/* write cmnd to bus */ 
 	  {
 	    PUCHAR ptr; UCHAR i;
-	    ptr = (PUCHAR) pSRB->CmdBlock;
-	    for (i=0; i<pSRB->ScsiCmdLen; i++)
+	    ptr = (PUCHAR) pSRB->pcmd->cmnd;
+	    for (i=0; i<pSRB->pcmd->cmd_len; i++)
 	      DC390_write8 (ScsiFifo, *(ptr++));
 	  };
       }
-
-    /* Check if we can't win arbitration */
+    DEBUG0(if (pACB->pActiveDCB)	\
+	   printk (KERN_WARNING "DC390: ActiveDCB != 0\n");)
+    DEBUG0(if (pDCB->pActiveSRB)	\
+	   printk (KERN_WARNING "DC390: ActiveSRB != 0\n");)
+    //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
     if (DC390_read8 (Scsi_Status) & INTERRUPT)
     {
+	dc390_freetag (pDCB, pSRB);
+	DEBUG0(printk ("DC390: Interrupt during Start SCSI (pid %li, target %02i-%02i)\n",
+		pSRB->pcmd->pid, pSRB->pcmd->target, pSRB->pcmd->lun);)
 	pSRB->SRBState = SRB_READY;
-	pDCB->TagMask &= ~( 1 << pSRB->TagNumber );
-	DEBUG0(printk (KERN_WARNING "DC390: Interrupt during StartSCSI!\n");)
+	//DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+	pACB->SelLost++;
 	return 1;
-    }
-    else
-    {
-	pSRB->ScsiPhase = SCSI_NOP1;
-	DEBUG0(if (pACB->pActiveDCB)	\
-		    printk (KERN_WARNING "DC390: ActiveDCB != 0\n");)
-	DEBUG0(if (pDCB->pActiveSRB)	\
-		    printk (KERN_WARNING "DC390: ActiveSRB != 0\n");)
-	pACB->pActiveDCB = pDCB;
-	pDCB->pActiveSRB = pSRB;
-	//DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
-	DC390_write8 (ScsiCmd, bval1);
-	return 0;
-    }
+    };
+    DC390_write8 (ScsiCmd, cmd);
+    pACB->pActiveDCB = pDCB; pDCB->pActiveSRB = pSRB;
+    pACB->Connected = 1;
+    pSRB->ScsiPhase = SCSI_NOP1;
+    return 0;
 }
 
 //#define DMA_INT EN_DMA_INT /*| EN_PAGE_INT*/
@@ -198,7 +176,7 @@
     };
   if (dstate & DMA_XFER_DONE)
     {
-	ULONG residual, xferCnt; int ctr = 5000000;
+	UINT residual, xferCnt; int ctr = 6000000;
 	if (! (DC390_read8 (DMA_Cmd) & READ_DIRECTION))
 	  {
 	    do
@@ -236,47 +214,34 @@
 void __inline__
 DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs)
 {
-    PACB   pACB;
+    PACB   pACB, pACB2;
     PDCB   pDCB;
     PSRB   pSRB;
     UCHAR  sstatus=0;
-    UCHAR  phase, i;
+    UCHAR  phase;
     void   (*stateV)( PACB, PSRB, PUCHAR );
     UCHAR  istate, istatus;
 #if DMA_INT
     UCHAR  dstatus;
 #endif
-    DC390_AFLAGS DC390_IFLAGS DC390_DFLAGS
-
-    pACB = dc390_pACB_start;
+    DC390_AFLAGS DC390_IFLAGS //DC390_DFLAGS
 
-    if (pACB == 0)
+    pACB = (PACB)dev_id;
+    for (pACB2 = dc390_pACB_start; (pACB2 && pACB2 != pACB); pACB2 = pACB2->pNextACB);
+    if (!pACB2)
     {
-	printk(KERN_WARNING "DC390: Interrupt on uninitialized adapter!\n");
+	printk ("DC390: IRQ called with foreign dev_id %p!\n", pACB);
 	return;
     }
-    DC390_LOCK_DRV;
+    
+    //DC390_LOCK_DRV;
 
-    for( i=0; i < dc390_adapterCnt; i++ )
-    {
-	if( pACB->IRQLevel == (UCHAR) irq )
-	{
-	     sstatus = DC390_read8 (Scsi_Status);
-	     if( sstatus & INTERRUPT )
-		 break;
-	     else
-		pACB = pACB->pNextACB;
-	}
-	else
-	{
-	    pACB = pACB->pNextACB;
-	}
-    }
+    sstatus = DC390_read8 (Scsi_Status);
+    if( !(sstatus & INTERRUPT) )
+	{ /*DC390_UNLOCK_DRV;*/ return; };
 
     DEBUG1(printk (KERN_DEBUG "sstatus=%02x,", sstatus);)
 
-    if( !pACB ) { DC390_UNLOCK_DRV; return; };
-
 #if DMA_INT
     DC390_LOCK_IO;
     DC390_LOCK_ACB;
@@ -288,7 +253,7 @@
     if (! (dstatus & SCSI_INTERRUPT))
       {
 	DEBUG0(printk (KERN_WARNING "DC390 Int w/o SCSI actions (only DMA?)\n");)
-	DC390_UNLOCK_DRV;
+	//DC390_UNLOCK_DRV;
 	return;
       };
 #else
@@ -299,7 +264,7 @@
 
     DC390_LOCK_IO;
     DC390_LOCK_ACB;
-    DC390_UNLOCK_DRV_NI; /* Allow _other_ CPUs to process IRQ (useful for shared IRQs) */
+    //DC390_UNLOCK_DRV_NI; /* Allow _other_ CPUs to process IRQ (useful for shared IRQs) */
 
     istate = DC390_read8 (Intern_State);
     istatus = DC390_read8 (INT_Status); /* This clears Scsi_Status, Intern_State and INT_Status ! */
@@ -310,23 +275,42 @@
 
     if (sstatus & ILLEGAL_OP_ERR)
     {
-	printk ("DC390: Illegal Operation detected (%08lx)!\n", dc390_laststatus);
+	printk ("DC390: Illegal Operation detected (%08x)!\n", dc390_laststatus);
 	dc390_dumpinfo (pACB, pACB->pActiveDCB, pACB->pActiveDCB->pActiveSRB);
-    };
+    }
 	
-    if(istatus &  DISCONNECTED)
+    else if (istatus &  INVALID_CMD)
+    {
+	printk ("DC390: Invalid Command detected (%08x)!\n", dc390_laststatus);
+	dc390_InvalidCmd( pACB );
+	goto unlock;
+    }
+
+    if (istatus &  SCSI_RESET)
+    {
+	dc390_ScsiRstDetect( pACB );
+	goto unlock;
+    }
+
+    if (istatus &  DISCONNECTED)
     {
 	dc390_Disconnect( pACB );
 	goto unlock;
     }
 
-    if(istatus &  RESELECTED)
+    if (istatus &  RESELECTED)
     {
 	dc390_Reselect( pACB );
 	goto unlock;
     }
 
-    if( istatus & (SUCCESSFUL_OP|SERVICE_REQUEST) )
+    else if (istatus & (SELECTED | SEL_ATTENTION))
+    {
+	printk (KERN_ERR "DC390: Target mode not supported!\n");
+	goto unlock;
+    }
+
+    if (istatus & (SUCCESSFUL_OP|SERVICE_REQUEST) )
     {
 	pDCB = pACB->pActiveDCB;
 	if (!pDCB)
@@ -351,23 +335,11 @@
 	goto unlock;
     }
 
-    if(istatus &  INVALID_CMD)
-    {
-	dc390_InvalidCmd( pACB );
-	goto unlock;
-    }
-
-    if(istatus &  SCSI_RESET)
-    {
-	dc390_ScsiRstDetect( pACB );
-	goto unlock;
-    }
-
  unlock:
-    DC390_LOCK_DRV_NI;
+    //DC390_LOCK_DRV_NI;
     DC390_UNLOCK_ACB;
     DC390_UNLOCK_IO;
-    DC390_UNLOCK_DRV; /* Restore initial flags */
+    //DC390_UNLOCK_DRV; /* Restore initial flags */
 }
 
 void
@@ -384,7 +356,7 @@
 {
     UCHAR   sstatus;
     PSGL    psgl;
-    ULONG   ResidCnt, xferCnt;
+    UINT    ResidCnt, xferCnt;
     UCHAR   dstate = 0;
 
     sstatus = *psstatus;
@@ -396,7 +368,7 @@
 
 	if( sstatus & COUNT_2_ZERO )
 	{
-	    int ctr = 5000000; /* only try for about a tenth of a second */
+	    int ctr = 6000000; /* only try for about a second */
 	    while( --ctr && !((dstate = DC390_read8 (DMA_Status)) & DMA_XFER_DONE) && pSRB->SGToBeXferLen );
 	    if (!ctr) printk (KERN_CRIT "DC390: Deadlock in DataOut_0: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32 (DMA_Wk_ByteCntr));
 	    dc390_laststatus &= ~0xff000000; dc390_laststatus |= dstate << 24;
@@ -415,10 +387,10 @@
 	}
 	else
 	{
-	    ResidCnt = (ULONG) DC390_read8 (Current_Fifo) & 0x1f;
-	    ResidCnt |= (ULONG) DC390_read8 (CtcReg_High) << 16;
-	    ResidCnt |= (ULONG) DC390_read8 (CtcReg_Mid) << 8; 
-	    ResidCnt += (ULONG) DC390_read8 (CtcReg_Low);
+	    ResidCnt  = (UINT) DC390_read8 (Current_Fifo) & 0x1f;
+	    ResidCnt |= (UINT) DC390_read8 (CtcReg_High) << 16;
+	    ResidCnt |= (UINT) DC390_read8 (CtcReg_Mid) << 8; 
+	    ResidCnt += (UINT) DC390_read8 (CtcReg_Low);
 
 	    xferCnt = pSRB->SGToBeXferLen - ResidCnt;
 	    pSRB->SGBusAddr += xferCnt;
@@ -426,7 +398,11 @@
 	    pSRB->SGToBeXferLen = ResidCnt;
 	}
     }
-    DC390_write8 (DMA_Cmd, WRITE_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
+    if ((*psstatus & 7) != SCSI_DATA_OUT)
+    {
+	    DC390_write8 (DMA_Cmd, WRITE_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
+	    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+    }	    
 }
 
 void
@@ -434,7 +410,8 @@
 {
     UCHAR   sstatus, residual, bval;
     PSGL    psgl;
-    ULONG   ResidCnt, xferCnt, i;
+    UINT    ResidCnt, i;
+    ULONG   xferCnt;
     PUCHAR  ptr;
 
     sstatus = *psstatus;
@@ -446,7 +423,7 @@
 
 	if( sstatus & COUNT_2_ZERO )
 	{
-	    int ctr = 5000000; /* only try for about a tenth of a second */
+	    int ctr = 6000000; /* only try for about a second */
 	    int dstate = 0;
 	    while( --ctr && !((dstate = DC390_read8 (DMA_Status)) & DMA_XFER_DONE) && pSRB->SGToBeXferLen );
 	    if (!ctr) printk (KERN_CRIT "DC390: Deadlock in DataIn_0: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32 (DMA_Wk_ByteCntr));
@@ -455,7 +432,7 @@
 	    DEBUG1(ResidCnt = ((ULONG) DC390_read8 (CtcReg_High) << 16)	\
 		+ ((ULONG) DC390_read8 (CtcReg_Mid) << 8)		\
 		+ ((ULONG) DC390_read8 (CtcReg_Low));)
-	    DEBUG1(printk (KERN_DEBUG "Count_2_Zero (ResidCnt=%li,ToBeXfer=%li),", ResidCnt, pSRB->SGToBeXferLen);)
+	    DEBUG1(printk (KERN_DEBUG "Count_2_Zero (ResidCnt=%i,ToBeXfer=%li),", ResidCnt, pSRB->SGToBeXferLen);)
 
 	    DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
 
@@ -509,12 +486,12 @@
 	    //DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
 	    dc390_laststatus &= ~0xff000000; dc390_laststatus |= bval << 24;
 
-	    DEBUG1(printk (KERN_DEBUG "Blast: Read %li times DMA_Status %02x", 0xa000-i, bval);)
-	    ResidCnt = (ULONG) DC390_read8 (CtcReg_High);
+	    DEBUG1(printk (KERN_DEBUG "Blast: Read %i times DMA_Status %02x", 0xa000-i, bval);)
+	    ResidCnt = (UINT) DC390_read8 (CtcReg_High);
 	    ResidCnt <<= 8;
-	    ResidCnt |= (ULONG) DC390_read8 (CtcReg_Mid);
+	    ResidCnt |= (UINT) DC390_read8 (CtcReg_Mid);
 	    ResidCnt <<= 8;
-	    ResidCnt |= (ULONG) DC390_read8 (CtcReg_Low);
+	    ResidCnt |= (UINT) DC390_read8 (CtcReg_Low);
 
 	    xferCnt = pSRB->SGToBeXferLen - ResidCnt;
 	    pSRB->SGBusAddr += xferCnt;
@@ -535,6 +512,11 @@
 
 	}
     }
+    if ((*psstatus & 7) != SCSI_DATA_IN)
+    {
+	    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+	    DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
+    }	    
 }
 
 static void
@@ -593,7 +575,7 @@
 static void __inline__
 dc390_MsgIn_reject (PACB pACB, PSRB pSRB)
 {
-  pSRB->MsgOutBuf[0] = MSG_REJECT_;
+  pSRB->MsgOutBuf[0] = MESSAGE_REJECT;
   pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT;
   DEBUG0 (printk (KERN_INFO "DC390: Reject message\n");)
 }
@@ -602,7 +584,7 @@
 static void __inline__
 dc390_EnableMsgOut_Abort ( PACB pACB, PSRB pSRB )
 {
-    pSRB->MsgOutBuf[0] = MSG_ABORT; 
+    pSRB->MsgOutBuf[0] = ABORT; 
     pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT;
     pSRB->pSRBDCB->DCBFlag &= ~ABORT_DEV_;
 }
@@ -640,7 +622,7 @@
       pSRB = pACB->pTmpSRB;
       pSRB->SRBState = SRB_UNEXPECT_RESEL;
       pDCB->pActiveSRB = pSRB;
-      pSRB->MsgOutBuf[0] = MSG_ABORT_TAG;
+      pSRB->MsgOutBuf[0] = ABORT_TAG;
       pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT;
     }
   return pSRB;
@@ -653,7 +635,7 @@
 {
   PDCB pDCB = pSRB->pSRBDCB;
   if (!(pSRB->SRBState & DO_SYNC_NEGO)) 
-    printk ("DC390: Target %i initiates Non-Sync?\n", pDCB->UnitSCSIID);
+    printk (KERN_INFO "DC390: Target %i initiates Non-Sync?\n", pDCB->TargetID);
   pSRB->SRBState &= ~DO_SYNC_NEGO;
   pDCB->SyncMode &= ~(SYNC_ENABLE+SYNC_NEGO_DONE);
   pDCB->SyncPeriod = 0;
@@ -677,8 +659,8 @@
   
   if (!(pSRB->SRBState & DO_SYNC_NEGO))
     {
-      printk ("DC390: Target %i initiates Sync: %ins %i ... answer ...\n", 
-	      pDCB->UnitSCSIID, pSRB->MsgInBuf[3]<<2, pSRB->MsgInBuf[4]);
+      printk (KERN_INFO "DC390: Target %i initiates Sync: %ins %i ... answer ...\n", 
+	      pDCB->TargetID, pSRB->MsgInBuf[3]<<2, pSRB->MsgInBuf[4]);
 
       /* reject */
       //dc390_MsgIn_reject (pACB, pSRB);
@@ -687,12 +669,12 @@
       /* Reply with corrected SDTR Message */
       if (pSRB->MsgInBuf[4] > 15)
 	{ 
-	  printk ("DC390: Lower Sync Offset to 15\n");
+	  printk (KERN_INFO "DC390: Lower Sync Offset to 15\n");
 	  pSRB->MsgInBuf[4] = 15;
 	}
       if (pSRB->MsgInBuf[3] < pDCB->NegoPeriod)
 	{
-	  printk ("DC390: Set sync nego period to %ins\n", pDCB->NegoPeriod << 2);
+	  printk (KERN_INFO "DC390: Set sync nego period to %ins\n", pDCB->NegoPeriod << 2);
 	  pSRB->MsgInBuf[3] = pDCB->NegoPeriod;
 	};
       memcpy (pSRB->MsgOutBuf, pSRB->MsgInBuf, 5);
@@ -728,10 +710,10 @@
   pDCB->CtrlR3 = bval;
   pDCB->SyncPeriod = (UCHAR)wval1;
   
-  if ((oldsyncperiod != wval1 || oldsyncoffset != pDCB->SyncOffset) && pDCB->UnitSCSILUN == 0)
+  if ((oldsyncperiod != wval1 || oldsyncoffset != pDCB->SyncOffset) && pDCB->TargetLUN == 0)
     {
       if (! (bval & FAST_SCSI)) wval1++;
-      printk ("DC390: Target %i: Sync transfer %i.%1i MHz, Offset %i\n", pDCB->UnitSCSIID, 
+      printk (KERN_INFO "DC390: Target %i: Sync transfer %i.%1i MHz, Offset %i\n", pDCB->TargetID, 
 	      40/wval1, ((40%wval1)*10+wval1/2)/wval1, pDCB->SyncOffset & 0x0f);
     }
   
@@ -739,6 +721,56 @@
 };
 
 
+/* handle RESTORE_PTR */
+static void 
+dc390_restore_ptr (PACB pACB, PSRB pSRB)
+{
+  PSGL psgl;
+  pSRB->TotalXferredLen = 0;
+  pSRB->SGIndex = 0;
+  if( pSRB->pcmd->use_sg )
+    {
+      pSRB->SGcount = (UCHAR) pSRB->pcmd->use_sg;
+      pSRB->pSegmentList = (PSGL) pSRB->pcmd->request_buffer;
+      psgl = pSRB->pSegmentList;
+      while (pSRB->TotalXferredLen + (ULONG) psgl->length < pSRB->Saved_Ptr)
+	{
+	  pSRB->TotalXferredLen += (ULONG) psgl->length;
+	  pSRB->SGIndex++;
+	  if( pSRB->SGIndex < pSRB->SGcount )
+	    {
+	      pSRB->pSegmentList++;
+	      psgl = pSRB->pSegmentList;
+	      
+	      pSRB->SGBusAddr = virt_to_bus( psgl->address );
+	      pSRB->SGToBeXferLen = (ULONG) psgl->length;
+	    }
+	  else
+	    pSRB->SGToBeXferLen = 0;
+	}
+      pSRB->SGToBeXferLen -= (pSRB->Saved_Ptr - pSRB->TotalXferredLen);
+      pSRB->SGBusAddr += (pSRB->Saved_Ptr - pSRB->TotalXferredLen);
+      printk (KERN_INFO "DC390: Pointer restored. Segment %i, Total %li, Bus %08lx\n", pSRB->SGIndex, pSRB->Saved_Ptr, pSRB->SGBusAddr);
+    }
+    else if( pSRB->pcmd->request_buffer )
+    {
+	pSRB->SGcount = 1;
+	pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
+	pSRB->Segmentx.address = (PUCHAR) pSRB->pcmd->request_buffer + pSRB->Saved_Ptr;
+	pSRB->Segmentx.length = pSRB->pcmd->request_bufflen - pSRB->Saved_Ptr;
+	printk (KERN_INFO "DC390: Pointer restored. Total %li, Bus %p\n",
+		pSRB->Saved_Ptr, pSRB->Segmentx.address);
+    }
+     else
+       {
+	 pSRB->SGcount = 0;
+	 printk (KERN_INFO "DC390: RESTORE_PTR message for Transfer without Scatter-Gather ??\n");
+       };
+
+  pSRB->TotalXferredLen = pSRB->Saved_Ptr;
+};
+
+
 /* According to the docs, the AM53C974 reads the message and 
  * generates a Succesful Operation IRQ before asserting ACK for
  * the last byte (how does it know whether it's the last ?) */
@@ -749,15 +781,15 @@
 
 /* Check if the message is complete */
 static UCHAR __inline__
-dc390_MsgIn_complete (UCHAR *msgbuf, ULONG len)
+dc390_MsgIn_complete (UCHAR *msgbuf, UINT len)
 { 
-  if (*msgbuf == MSG_EXTENDED)
-    {
-      if (len < 2) return 0;
-      if (len < msgbuf[1] + 2) return 0;
-    }
+  if (*msgbuf == EXTENDED_MESSAGE)
+  {
+	if (len < 2) return 0;
+	if (len < msgbuf[1] + 2) return 0;
+  }
   else if (*msgbuf >= 0x20 && *msgbuf <= 0x2f) // two byte messages
-    if (len < 2) return 0;
+	if (len < 2) return 0;
   return 1;
 }
 
@@ -781,23 +813,23 @@
 	/* Now eval the msg */
 	switch (pSRB->MsgInBuf[0]) 
 	  {
-	  case MSG_DISCONNECT: 
+	  case DISCONNECT: 
 	    pSRB->SRBState = SRB_DISCONNECT; break;
 	    
-	  case MSG_SIMPLE_QTAG:
-	  case MSG_HEAD_QTAG:
-	  case MSG_ORDER_QTAG:
+	  case SIMPLE_QUEUE_TAG:
+	  case HEAD_OF_QUEUE_TAG:
+	  case ORDERED_QUEUE_TAG:
 	    pSRB = dc390_MsgIn_QTag (pACB, pDCB, pSRB->MsgInBuf[1]);
 	    break;
 	    
-	  case MSG_REJECT_: 
+	  case MESSAGE_REJECT: 
 	    DC390_write8 (ScsiCmd, RESET_ATN_CMD);
 	    pDCB->NegoPeriod = 50; /* 200ns <=> 5 MHz */
 	    if( pSRB->SRBState & DO_SYNC_NEGO)
 	      dc390_MsgIn_set_async (pACB, pSRB);
 	    break;
 	    
-	  case MSG_EXTENDED:
+	  case EXTENDED_MESSAGE:
 	    /* reject every extended msg but SDTR */
 	    if (pSRB->MsgInBuf[1] != 3 || pSRB->MsgInBuf[2] != EXTENDED_SDTR)
 	      dc390_MsgIn_reject (pACB, pSRB);
@@ -810,15 +842,18 @@
 	      };
 	    
 	    // nothing has to be done
-	  case MSG_COMPLETE: break;
+	  case COMMAND_COMPLETE: break;
 	    
-	    // SAVE POINTER my be ignored as we have the PSRB associated with the
+	    // SAVE POINTER may be ignored as we have the PSRB associated with the
 	    // scsi command. Thanks, Gerard, for pointing it out.
-	  case MSG_SAVE_PTR: break;
+	  case SAVE_POINTERS: 
+	    pSRB->Saved_Ptr = pSRB->TotalXferredLen;
+	    break;
 	    // The device might want to restart transfer with a RESTORE
-	  case MSG_RESTORE_PTR: 
-	    printk ("DC390: RESTORE POINTER message received ... reject\n");
-	    // fall through
+	  case RESTORE_POINTERS:
+	    DEBUG0(printk ("DC390: RESTORE POINTER message received ... try to handle\n");)
+	    dc390_restore_ptr (pACB, pSRB);
+	    break;
 
 	    // reject unknown messages
 	  default: dc390_MsgIn_reject (pACB, pSRB);
@@ -840,6 +875,17 @@
 {
     PSGL   psgl;
     ULONG  lval;
+    PDCB   pDCB = pACB->pActiveDCB;
+
+    if (pSRB == pACB->pTmpSRB)
+    {
+	if (pDCB) printk (KERN_ERR "DC390: pSRB == pTmpSRB! (TagQ Error?) (%02i-%i)\n",
+			  pDCB->TargetID, pDCB->TargetLUN);
+	else printk (KERN_ERR "DC390: pSRB == pTmpSRB! (TagQ Error?) (DCB 0!)\n");
+	dc390_EnableMsgOut_Abort (pACB, pSRB);
+	if (pDCB) pDCB->DCBFlag |= ABORT_DEV;
+	return;
+    }
 
     if( pSRB->SGIndex < pSRB->SGcount )
     {
@@ -852,7 +898,7 @@
 	    DEBUG1(printk (KERN_DEBUG " DC390: Next SG segment.");)
 	}
 	lval = pSRB->SGToBeXferLen;
-	DEBUG1(printk (KERN_DEBUG " DC390: Transfer %li bytes (address %08lx)\n", lval, pSRB->SGBusAddr);)
+	DEBUG1(printk (KERN_DEBUG " DC390: Start transfer: %li bytes (address %08lx)\n", lval, pSRB->SGBusAddr);)
 	DC390_write8 (CtcReg_Low, (UCHAR) lval);
 	lval >>= 8;
 	DC390_write8 (CtcReg_Mid, (UCHAR) lval);
@@ -918,8 +964,8 @@
     DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
     if( !(pSRB->SRBFlag & AUTO_REQSENSE) )
     {
-	cnt = (UCHAR) pSRB->ScsiCmdLen;
-	ptr = (PUCHAR) pSRB->CmdBlock;
+	cnt = (UCHAR) pSRB->pcmd->cmd_len;
+	ptr = (PUCHAR) pSRB->pcmd->cmnd;
 	for(i=0; i < cnt; i++)
 	    DC390_write8 (ScsiFifo, *(ptr++));
     }
@@ -928,11 +974,12 @@
 	UCHAR bval = 0;
 	DC390_write8 (ScsiFifo, REQUEST_SENSE);
 	pDCB = pACB->pActiveDCB;
-	DC390_write8 (ScsiFifo, pDCB->IdentifyMsg << 5);
+	DC390_write8 (ScsiFifo, pDCB->TargetLUN << 5);
 	DC390_write8 (ScsiFifo, bval);
 	DC390_write8 (ScsiFifo, bval);
 	DC390_write8 (ScsiFifo, sizeof(pSRB->pcmd->sense_buffer));
 	DC390_write8 (ScsiFifo, bval);
+	DEBUG0(printk(KERN_DEBUG "DC390: AutoReqSense (CmndPhase)!\n");)
     }
     pSRB->SRBState = SRB_COMMAND;
     DC390_write8 (ScsiCmd, INFO_XFER_CMD);
@@ -966,14 +1013,14 @@
 		DC390_write8 (ScsiFifo, *(ptr++));
 	    pSRB->MsgCnt = 0;
 	    if( (pDCB->DCBFlag & ABORT_DEV_) &&
-		(pSRB->MsgOutBuf[0] == MSG_ABORT) )
+		(pSRB->MsgOutBuf[0] == ABORT) )
 		pSRB->SRBState = SRB_ABORT_SENT;
 	}
 	else
 	{
-	    bval = MSG_ABORT;	/* ??? MSG_NOP */
-	    if( (pSRB->CmdBlock[0] == INQUIRY ) ||
-		(pSRB->CmdBlock[0] == REQUEST_SENSE) ||
+	    bval = ABORT;	/* ??? MSG_NOP */
+	    if( (pSRB->pcmd->cmnd[0] == INQUIRY ) ||
+		(pSRB->pcmd->cmnd[0] == REQUEST_SENSE) ||
 		(pSRB->SRBFlag & AUTO_REQSENSE) )
 	    {
 		if( pDCB->SyncMode & SYNC_ENABLE )
@@ -986,8 +1033,8 @@
     else
     {
 mop1:
-	//printk ("DC390: Send SDTR message to %i %i ... \n", pDCB->UnitSCSIID, pDCB->UnitSCSILUN);
-	DC390_write8 (ScsiFifo, MSG_EXTENDED);
+        printk (KERN_ERR "DC390: OLD Sync Nego code triggered! (%i %i)\n", pDCB->TargetID, pDCB->TargetLUN);
+	DC390_write8 (ScsiFifo, EXTENDED_MESSAGE);
 	DC390_write8 (ScsiFifo, 3);	/*    ;length of extended msg */
 	DC390_write8 (ScsiFifo, EXTENDED_SDTR);	/*    ; sync nego */
 	DC390_write8 (ScsiFifo, pDCB->NegoPeriod);
@@ -1030,20 +1077,16 @@
     UCHAR  bval, i, cnt;
     PDCB   ptr;
 
-    if( !(pDCB->IdentifyMsg & 0x07) )
+    if( !(pDCB->TargetLUN) )
     {
-	if( pACB->scan_devices )
-	{
-	    dc390_CurrSyncOffset = pDCB->SyncOffset;
-	}
-	else
+	if( !pACB->scan_devices )
 	{
 	    ptr = pACB->pLinkDCB;
 	    cnt = pACB->DCBCnt;
-	    bval = pDCB->UnitSCSIID;
+	    bval = pDCB->TargetID;
 	    for(i=0; i<cnt; i++)
 	    {
-		if( ptr->UnitSCSIID == bval )
+		if( ptr->TargetID == bval )
 		{
 		    ptr->SyncPeriod = pDCB->SyncPeriod;
 		    ptr->SyncOffset = pDCB->SyncOffset;
@@ -1068,25 +1111,27 @@
 
     DEBUG0(printk(KERN_INFO "DISC,");)
 
+    if (!pACB->Connected) printk(KERN_ERR "DC390: Disconnect not-connected bus?\n");
+    pACB->Connected = 0;
     pDCB = pACB->pActiveDCB;
     if (!pDCB)
      {
 	int j = 400;
-	DEBUG0(printk(KERN_WARNING "ACB:%08lx->ActiveDCB:%08lx IOPort:%04x IRQ:%02x !\n",\
-	       (ULONG)pACB,(ULONG)pDCB,pACB->IOPortBase,pACB->IRQLevel);)
+	DEBUG0(printk(KERN_ERR "ACB:%p->ActiveDCB:%p IOPort:%04x IRQ:%02x !\n",\
+	       pACB, pDCB, pACB->IOPortBase, pACB->IRQLevel);)
 	while (--j) udelay (1000);
 	DC390_read8 (INT_Status);	/* Reset Pending INT */
 	DC390_write8 (ScsiCmd, EN_SEL_RESEL);
 	return;
      }
+    DC390_write8 (ScsiCmd, EN_SEL_RESEL);
     pSRB = pDCB->pActiveSRB;
     pACB->pActiveDCB = 0;
     pSRB->ScsiPhase = SCSI_NOP0;
-    DC390_write8 (ScsiCmd, EN_SEL_RESEL);
     if( pSRB->SRBState & SRB_UNEXPECT_RESEL )
     {
 	pSRB->SRBState = 0;
-	dc390_DoWaitingSRB( pACB );
+	dc390_Waiting_process ( pACB );
     }
     else if( pSRB->SRBState & SRB_ABORT_SENT )
     {
@@ -1098,22 +1143,24 @@
 	for( i=0; i < cnt; i++)
 	{
 	    psrb = pSRB->pNextSRB;
-	    pSRB->pNextSRB = pACB->pFreeSRB;
-	    pACB->pFreeSRB = pSRB;
+	    dc390_Free_insert (pACB, pSRB);
 	    pSRB = psrb;
 	}
 	pDCB->pGoingSRB = 0;
-	dc390_DoWaitingSRB( pACB );
+	dc390_Query_to_Waiting (pACB);
+	dc390_Waiting_process (pACB);
     }
     else
     {
 	if( (pSRB->SRBState & (SRB_START_+SRB_MSGOUT)) ||
 	   !(pSRB->SRBState & (SRB_DISCONNECT+SRB_COMPLETED)) )
 	{	/* Selection time out */
-	    if( !(pACB->scan_devices) )
+	    if( !(1/*pACB->scan_devices*/) )
 	    {
 		pSRB->SRBState = SRB_READY;
-		dc390_RewaitSRB( pDCB, pSRB);
+		dc390_freetag (pDCB, pSRB);
+		dc390_Going_to_Waiting (pDCB, pSRB);
+		dc390_waiting_timer (pACB, HZ/5);
 	    }
 	    else
 	    {
@@ -1123,15 +1170,12 @@
 	}
 	else if( pSRB->SRBState & SRB_DISCONNECT )
 	{
-	    dc390_DoWaitingSRB( pACB );
+	    dc390_Waiting_process ( pACB );
 	}
 	else if( pSRB->SRBState & SRB_COMPLETED )
 	{
 disc1:
-	    if(pDCB->MaxCommand > 1)
-	    {
-	       pDCB->TagMask &= (~(1 << pSRB->TagNumber));   /* free tag mask */
-	    }
+	    dc390_freetag (pDCB, pSRB);
 	    pDCB->pActiveSRB = 0;
 	    pSRB->SRBState = SRB_FREE;
 	    dc390_SRBdone( pACB, pDCB, pSRB);
@@ -1146,43 +1190,48 @@
 {
     PDCB   pDCB;
     PSRB   pSRB;
-    USHORT wval;
-    UCHAR  bval;
+    UCHAR  id, lun;
 
     DEBUG0(printk(KERN_INFO "RSEL,");)
+    pACB->Connected = 1;
     pDCB = pACB->pActiveDCB;
     if( pDCB )
     {	/* Arbitration lost but Reselection won */
-	DEBUG0(printk ("(ActiveDCB != 0)");)
+	DEBUG0(printk ("DC390: (ActiveDCB != 0: Arb. lost but resel. won)!\n");)
 	pSRB = pDCB->pActiveSRB;
 	if( !( pACB->scan_devices ) )
 	{
 	    pSRB->SRBState = SRB_READY;
-	    dc390_RewaitSRB( pDCB, pSRB);
+	    dc390_freetag (pDCB, pSRB);
+	    dc390_Going_to_Waiting ( pDCB, pSRB);
+	    dc390_waiting_timer (pACB, HZ/5);
 	}
     }
-    bval = DC390_read8 (ScsiFifo);	/* get ID */
-    DEBUG0(printk ("Dev %02x,", bval);)
-    bval ^= 1 << pACB->pScsiHost->this_id; /* Mask AdapterID */
-    wval = 0;
-    while (bval >>= 1) wval++;
-    wval |=  ( (USHORT) DC390_read8 (ScsiFifo) & 7) << 8;  /* get LUN */
-    DEBUG0(printk ("(ID %02x, LUN %02x),", wval & 0xff, (wval & 0xff00) >> 8);)
-    pDCB = pACB->pLinkDCB;
-    while( wval != *((PUSHORT) &pDCB->UnitSCSIID) )
+    /* Get ID */
+    lun = DC390_read8 (ScsiFifo);
+    DEBUG0(printk ("Dev %02x,", lun);)
+    if (!(lun & (1 << pACB->pScsiHost->this_id)))
+      printk (KERN_ERR "DC390: Reselection must select host adapter: %02x!\n", lun);
+    else
+      lun ^= 1 << pACB->pScsiHost->this_id; /* Mask AdapterID */
+    id = 0; while (lun >>= 1) id++;
+    /* Get LUN */
+    lun = DC390_read8 (ScsiFifo);
+    if (!(lun & IDENTIFY_BASE)) printk (KERN_ERR "DC390: Resel: Expect identify message!\n");
+    lun &= 7;
+    DEBUG0(printk ("(%02i-%i),", id, lun);)
+    pDCB = dc390_findDCB (pACB, id, lun);
+    if (!pDCB)
     {
-	pDCB = pDCB->pNextDCB;
-	if( pDCB == pACB->pLinkDCB )
-	 {
-	    printk (KERN_ERR "DC390: Reselect from non existing device (ID %02x, LUN %02x)\n",
-		    wval & 0xff, (wval & 0xff00) >> 8);
-	    return;
-	 }
+	printk (KERN_ERR "DC390: Reselect from non existing device (%02i-%i)\n",
+		    id, lun);
+	return;
     }
     pACB->pActiveDCB = pDCB;
+    /* TagQ: We expect a message soon, so never mind the exact SRB */
     if( pDCB->SyncMode & EN_TAG_QUEUEING )
     {
-	pSRB = pACB->pTmpSRB; /* ?? */
+	pSRB = pACB->pTmpSRB;
 	pDCB->pActiveSRB = pSRB;
     }
     else
@@ -1192,8 +1241,8 @@
 	{
 	    pSRB= pACB->pTmpSRB;
 	    pSRB->SRBState = SRB_UNEXPECT_RESEL;
-	    printk (KERN_ERR "DC390: Reselect without outstanding cmnd (ID %02x, LUN %02x)\n",
-		    wval & 0xff, (wval & 0xff00) >> 8);
+	    printk (KERN_ERR "DC390: Reselect without outstanding cmnd (%02i-%i)\n",
+		    id, lun);
 	    pDCB->pActiveSRB = pSRB;
 	    dc390_EnableMsgOut_Abort ( pACB, pSRB );
 	}
@@ -1202,8 +1251,8 @@
 	    if( pDCB->DCBFlag & ABORT_DEV_ )
 	    {
 		pSRB->SRBState = SRB_ABORT_SENT;
-		printk (KERN_INFO "DC390: Reselect: Abort (ID %02x, LUN %02x)\n",
-			wval & 0xff, (wval & 0xff00) >> 8);
+		printk (KERN_INFO "DC390: Reselect: Abort (%02i-%i)\n",
+			id, lun);
 		dc390_EnableMsgOut_Abort( pACB, pSRB );
 	    }
 	    else
@@ -1213,7 +1262,7 @@
 
     DEBUG1(printk (KERN_DEBUG "Resel SRB(%p): TagNum (%02x)\n", pSRB, pSRB->TagNumber);)
     pSRB->ScsiPhase = SCSI_NOP0;
-    DC390_write8 (Scsi_Dest_ID, pDCB->UnitSCSIID);
+    DC390_write8 (Scsi_Dest_ID, pDCB->TargetID);
     DC390_write8 (Sync_Period, pDCB->SyncPeriod);
     DC390_write8 (Sync_Offset, pDCB->SyncOffset);
     DC390_write8 (CtrlReg1, pDCB->CtrlR1);
@@ -1228,30 +1277,36 @@
 {
    PDCB pPrevDCB = pACB->pLinkDCB;
 
-   pACB->DCBmap[pDCB->UnitSCSIID] &= ~(1 << pDCB->UnitSCSILUN);
    if (pDCB->GoingSRBCnt > 1)
      {
 	DCBDEBUG(printk (KERN_INFO "DC390: Driver won't free DCB (ID %i, LUN %i): 0x%08x because of SRBCnt %i\n",\
-		pDCB->UnitSCSIID, pDCB->UnitSCSILUN, (int)pDCB, pDCB->GoingSRBCnt);)
+		pDCB->TargetID, pDCB->TargetLUN, (int)pDCB, pDCB->GoingSRBCnt);)
 	return;
      };
+   pACB->DCBmap[pDCB->TargetID] &= ~(1 << pDCB->TargetLUN);
    
+   // The first one
    if (pDCB == pACB->pLinkDCB) 
-     {
-	if (pDCB->pNextDCB == pDCB) pDCB->pNextDCB = 0;
+   {
+	// The last one
+	if (pACB->pLastDCB == pDCB) {
+		pDCB->pNextDCB = 0; pACB->pLastDCB = 0;
+	}
 	pACB->pLinkDCB = pDCB->pNextDCB;
-	pACB->pLastDCB->pNextDCB = pDCB->pNextDCB;
-     }
+   }
    else
-     {
+   {
 	while (pPrevDCB->pNextDCB != pDCB) pPrevDCB = pPrevDCB->pNextDCB;
 	pPrevDCB->pNextDCB = pDCB->pNextDCB;
 	if (pDCB == pACB->pLastDCB) pACB->pLastDCB = pPrevDCB;
-     }
+   }
 
-   DCBDEBUG(printk (KERN_INFO "DC390: Driver about to free DCB (ID %i, LUN %i): 0x%08x\n",\
-	   pDCB->UnitSCSIID, pDCB->UnitSCSILUN, (int)pDCB);)
-   kfree (pDCB); if (pDCB == pACB->pActiveDCB) pACB->pActiveDCB = 0;
+   DCBDEBUG(printk (KERN_INFO "DC390: Driver about to free DCB (ID %i, LUN %i): %p\n",\
+	   pDCB->TargetID, pDCB->TargetLUN, pDCB);)
+   if (pDCB == pACB->pActiveDCB) pACB->pActiveDCB = 0;
+   if (pDCB == pACB->pLinkDCB) pACB->pLinkDCB = pDCB->pNextDCB;
+   if (pDCB == pACB->pDCBRunRobin) pACB->pDCBRunRobin = pDCB->pNextDCB;
+   kfree (pDCB); 
    pACB->DCBCnt--;
    /* pACB->DeviceCnt--; */
 };
@@ -1280,21 +1335,12 @@
 		|| (pDCB->DevType == TYPE_MOD)) &&*/
 	    !dc390_tagq_blacklist (((char*)ptr)+8) )
 	  {
-	     pDCB->MaxCommand = pDCB->pDCBACB->TagMaxNum;
+	     if (pDCB->MaxCommand ==1) pDCB->MaxCommand = pDCB->pDCBACB->TagMaxNum;
 	     pDCB->SyncMode |= EN_TAG_QUEUEING /* | EN_ATN_STOP */;
-	     pDCB->TagMask = 0;
+	     //pDCB->TagMask = 0;
 	  }
 	else
-	  {
-	     /* Do we really need to check for DevType here ? */
-	     if ( 0 /*(pDCB->DevMode & EN_DISCONNECT_)*/
-		 /* && ((pDCB->DevType == TYPE_DISK) 
-		     || (pDCB->DevType == TYPE_MOD))*/ )
-		pDCB->SyncMode |= EN_ATN_STOP;
-	     else
-	       //pDCB->SyncMode &= ~EN_ATN_STOP;
-	       pDCB->SyncMode &= ~0;
-	  }
+	     pDCB->MaxCommand = 1;
      }
 };
 
@@ -1312,60 +1358,62 @@
 void
 dc390_SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB )
 {
-    PSRB   psrb;
-    UCHAR  bval, status, i;
+    UCHAR  bval, status, i, DCB_removed;
     PSCSICMD pcmd;
     PSCSI_INQDATA  ptr;
     PSGL   ptr2;
     ULONG  swlval;
 
-    pcmd = pSRB->pcmd;
+    pcmd = pSRB->pcmd; DCB_removed = 0;
     status = pSRB->TargetStatus;
+    ptr = (PSCSI_INQDATA) (pcmd->request_buffer);
+    if( pcmd->use_sg )
+	ptr = (PSCSI_INQDATA) (((PSGL) ptr)->address);
+	
     DEBUG0(printk (" SRBdone (%02x,%08x), SRB %p, pid %li\n", status, pcmd->result,\
 		pSRB, pcmd->pid);)
     if(pSRB->SRBFlag & AUTO_REQSENSE)
     {	/* Last command was a Request Sense */
 	pSRB->SRBFlag &= ~AUTO_REQSENSE;
 	pSRB->AdaptStatus = 0;
-	pSRB->TargetStatus = SCSI_STAT_CHECKCOND;
+	pSRB->TargetStatus = CHECK_CONDITION << 1;
 #ifdef DC390_REMOVABLEDEBUG
 	switch (pcmd->sense_buffer[2] & 0x0f)
 	{	    
 	 case NOT_READY: printk (KERN_INFO "DC390: ReqSense: NOT_READY (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n",
-				 pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN,
+				 pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN,
 				 status, pACB->scan_devices); break;
 	 case UNIT_ATTENTION: printk (KERN_INFO "DC390: ReqSense: UNIT_ATTENTION (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n",
-				      pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN,
+				      pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN,
 				      status, pACB->scan_devices); break;
 	 case ILLEGAL_REQUEST: printk (KERN_INFO "DC390: ReqSense: ILLEGAL_REQUEST (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n",
-				       pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN,
+				       pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN,
 				       status, pACB->scan_devices); break;
 	 case MEDIUM_ERROR: printk (KERN_INFO "DC390: ReqSense: MEDIUM_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n",
-				    pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN,
+				    pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN,
 				    status, pACB->scan_devices); break;
 	 case HARDWARE_ERROR: printk (KERN_INFO "DC390: ReqSense: HARDWARE_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n",
-				      pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN,
+				      pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN,
 				      status, pACB->scan_devices); break;
 	}
 #endif
-	//pcmd->result = DRIVER_SENSE << 24 | DID_OK << 16 | status;
-	if(status == SCSI_STAT_CHECKCOND)
+	//pcmd->result = MK_RES(DRIVER_SENSE,DID_OK,0,status);
+	if (status == (CHECK_CONDITION << 1))
 	{
-	    pcmd->result = DID_BAD_TARGET << 16;
+	    pcmd->result = MK_RES_LNX(0,DID_BAD_TARGET,0,/*CHECK_CONDITION*/0);
 	    goto ckc_e;
 	}
 	if(pSRB->RetryCnt == 0)
 	{
-	    (ULONG)(pSRB->CmdBlock[0]) = pSRB->Segment0[0];
-	    pSRB->TotalXferredLen = pSRB->Segment1[1];
+	    //(UINT)(pSRB->pcmd->cmnd[0]) = pSRB->Segment0[0];
+	    pSRB->TotalXferredLen = pSRB->SavedTotXLen;
 	    if( (pSRB->TotalXferredLen) &&
 		(pSRB->TotalXferredLen >= pcmd->underflow) )
-		pcmd->result |= (DID_OK << 16);
+		  SET_RES_DID(pcmd->result,DID_OK)
 	    else
-		pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) |
-				SCSI_STAT_CHECKCOND;
-	    REMOVABLEDEBUG(printk(KERN_INFO "Cmd=%02x,Result=%08x,XferL=%08x\n",pSRB->CmdBlock[0],\
-		(UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);)
+		  pcmd->result = MK_RES_LNX(DRIVER_SENSE,DID_OK,0,CHECK_CONDITION);
+		  REMOVABLEDEBUG(printk(KERN_INFO "Cmd=%02x,Result=%08x,XferL=%08x\n",pSRB->pcmd->cmnd[0],\
+			(UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);)
 	    goto ckc_e;
 	}
 	else /* Retry */
@@ -1373,20 +1421,20 @@
 	    pSRB->RetryCnt--;
 	    pSRB->AdaptStatus = 0;
 	    pSRB->TargetStatus = 0;
-	    *((PULONG) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0];
-	    *((PULONG) &(pSRB->CmdBlock[4])) = pSRB->Segment0[1];
+	    //*((PUINT) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0];
+	    //*((PUINT) &(pSRB->CmdBlock[4])) = pSRB->Segment0[1];
 	    /* Don't retry on TEST_UNIT_READY */
-	    if( pSRB->CmdBlock[0] == TEST_UNIT_READY /* || pSRB->CmdBlock[0] == START_STOP */)
+	    if( pSRB->pcmd->cmnd[0] == TEST_UNIT_READY /* || pSRB->pcmd->cmnd[0] == START_STOP */)
 	    {
-		pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) 
-			    | SCSI_STAT_CHECKCOND;
-		REMOVABLEDEBUG(printk(KERN_INFO "Cmd=%02x, Result=%08x, XferL=%08x\n",pSRB->CmdBlock[0],\
+		pcmd->result = MK_RES_LNX(DRIVER_SENSE,DID_OK,0,CHECK_CONDITION);
+		REMOVABLEDEBUG(printk(KERN_INFO "Cmd=%02x, Result=%08x, XferL=%08x\n",pSRB->pcmd->cmnd[0],\
 		       (UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);)
 		goto ckc_e;
 	    }
-	    pcmd->result |= (DRIVER_SENSE << 24);
-	    pSRB->SGcount	 = (UCHAR) pSRB->Segment1[0];
-	    pSRB->ScsiCmdLen	 = (UCHAR) (pSRB->Segment1[0] >> 8);
+	    SET_RES_DRV(pcmd->result,DRIVER_SENSE);
+	    pSRB->SGcount	 = (UCHAR) pSRB->SavedSGCount;
+	    //pSRB->ScsiCmdLen	 = (UCHAR) (pSRB->Segment1[0] >> 8);
+	    DEBUG0 (printk ("DC390: RETRY pid %li (%02x), target %02i-%02i\n", pcmd->pid, pcmd->cmnd[0], pcmd->target, pcmd->lun);)
 	    pSRB->SGIndex = 0;
 	    pSRB->TotalXferredLen = 0;
 	    pSRB->SGToBeXferLen = 0;
@@ -1398,17 +1446,19 @@
 		pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
 		pSRB->Segmentx.length = pcmd->request_bufflen;
 	    }
-	    if( dc390_StartSCSI( pACB, pDCB, pSRB ) )
-		dc390_RewaitSRB( pDCB, pSRB );
+	    if( dc390_StartSCSI( pACB, pDCB, pSRB ) ) {
+		dc390_Going_to_Waiting ( pDCB, pSRB );
+		dc390_waiting_timer (pACB, HZ/5);
+	    }
 	    return;
 	}
     }
     if( status )
     {
-	if( status == SCSI_STAT_CHECKCOND)
+	if( status_byte(status) == CHECK_CONDITION )
 	{
-	    REMOVABLEDEBUG(printk (KERN_INFO "DC390: Scsi_Stat_CheckCond (Cmd %02x, Id %02x, LUN %02x)\n",\
-		    pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN);)
+	    REMOVABLEDEBUG(printk (KERN_INFO "DC390: Check_Condition (Cmd %02x, Id %02x, LUN %02x)\n",\
+		    pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN);)
 	    if( (pSRB->SGIndex < pSRB->SGcount) && (pSRB->SGcount) && (pSRB->SGToBeXferLen) )
 	    {
 		bval = pSRB->SGcount;
@@ -1425,12 +1475,14 @@
 	    dc390_RequestSense( pACB, pDCB, pSRB );
 	    return;
 	}
-	else if( status == SCSI_STAT_QUEUEFULL )
+	else if( status_byte(status) == QUEUE_FULL )
 	{
 	    bval = (UCHAR) pDCB->GoingSRBCnt;
 	    bval--;
 	    pDCB->MaxCommand = bval;
-	    dc390_RewaitSRB( pDCB, pSRB );
+	    dc390_freetag (pDCB, pSRB);
+	    dc390_Going_to_Waiting ( pDCB, pSRB );
+	    dc390_waiting_timer (pACB, HZ/5);
 	    pSRB->AdaptStatus = 0;
 	    pSRB->TargetStatus = 0;
 	    return;
@@ -1439,23 +1491,23 @@
 	{
 	    pSRB->AdaptStatus = H_SEL_TIMEOUT;
 	    pSRB->TargetStatus = 0;
-	    pcmd->result = DID_BAD_TARGET << 16;
+	    pcmd->result = MK_RES(0,DID_NO_CONNECT,0,0);
 	    /* Devices are removed below ... */
 	}
-	else if (status == SCSI_STAT_BUSY && 
-		 (pSRB->CmdBlock[0] == TEST_UNIT_READY || pSRB->CmdBlock[0] == INQUIRY) &&
+	else if (status_byte(status) == BUSY && 
+		 (pcmd->cmnd[0] == TEST_UNIT_READY || pcmd->cmnd[0] == INQUIRY) &&
 		 pACB->scan_devices)
 	{
 	    pSRB->AdaptStatus = 0;
 	    pSRB->TargetStatus = status;
-	    pcmd->result = (ULONG) (pSRB->EndMessage << 8)
-				/* | (ULONG) status */;
+	    pcmd->result = MK_RES(0,0,pSRB->EndMessage,/*status*/0);
 	}
 	else
 	{   /* Another error */
 	    pSRB->AdaptStatus = 0;
 	    if( pSRB->RetryCnt )
 	    {	/* Retry */
+		//printk ("DC390: retry\n");
 		pSRB->RetryCnt--;
 		pSRB->TargetStatus = 0;
 		pSRB->SGIndex = 0;
@@ -1469,14 +1521,18 @@
 		    pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer;
 		    pSRB->Segmentx.length = pcmd->request_bufflen;
 		}
-		if( dc390_StartSCSI( pACB, pDCB, pSRB ) )
-		    dc390_RewaitSRB( pDCB, pSRB );
-		return;
+		if( dc390_StartSCSI( pACB, pDCB, pSRB ) ) {
+		    dc390_Going_to_Waiting ( pDCB, pSRB );
+		    dc390_waiting_timer (pACB, HZ/5);
+		}
+      		return;
 	    }
 	    else
 	    {	/* Report error */
-		pcmd->result |= (DID_ERROR << 16) | (ULONG) (pSRB->EndMessage << 8) |
-			       (ULONG) status;
+	      //pcmd->result = MK_RES(0, DID_ERROR, pSRB->EndMessage, status);
+	      SET_RES_DID(pcmd->result,DID_ERROR);
+	      SET_RES_MSG(pcmd->result,pSRB->EndMessage);
+	      SET_RES_TARGET(pcmd->result,status);
 	    }
 	}
     }
@@ -1486,38 +1542,52 @@
 	if(status & H_OVER_UNDER_RUN)
 	{
 	    pSRB->TargetStatus = 0;
-	    pcmd->result |= (DID_OK << 16) | (pSRB->EndMessage << 8);
+	    SET_RES_DID(pcmd->result,DID_OK);
+	    SET_RES_MSG(pcmd->result,pSRB->EndMessage);
 	}
 	else if( pSRB->SRBStatus & PARITY_ERROR)
 	{
-	    pcmd->result |= (DID_PARITY << 16) | (pSRB->EndMessage << 8);
+	    //pcmd->result = MK_RES(0,DID_PARITY,pSRB->EndMessage,0);
+	    SET_RES_DID(pcmd->result,DID_PARITY);
+	    SET_RES_MSG(pcmd->result,pSRB->EndMessage);
 	}
 	else		       /* No error */
 	{
 	    pSRB->AdaptStatus = 0;
 	    pSRB->TargetStatus = 0;
-	    pcmd->result |= (DID_OK << 16);
+	    SET_RES_DID(pcmd->result,DID_OK);
 	}
     }
+    if ((pcmd->result & RES_DID) == 0 &&
+	pcmd->cmnd[0] == INQUIRY && 
+	pcmd->cmnd[2] == 0 &&
+	pcmd->request_bufflen >= 8 &&
+	ptr &&
+	(ptr->Vers & 0x07) >= 2)
+	    pDCB->Inquiry7 = ptr->Flags;
 
 ckc_e:
     if( pACB->scan_devices )
     {
-	if( pSRB->CmdBlock[0] == TEST_UNIT_READY )
+	if( pcmd->cmnd[0] == TEST_UNIT_READY ||
+	    pcmd->cmnd[0] == INQUIRY)
 	{
 #ifdef DC390_DEBUG0
-	    printk (KERN_INFO "DC390: Test_Unit_Ready: result: %08x", pcmd->result);
-	    if (pcmd->result & DRIVER_SENSE << 24) printk (" (sense: %02x %02x %02x %02x)\n",
+	    printk (KERN_INFO "DC390: %s: result: %08x", 
+		    (pcmd->cmnd[0] == INQUIRY? "INQUIRY": "TEST_UNIT_READY"),
+		    pcmd->result);
+	    if (pcmd->result & (DRIVER_SENSE << 24)) printk (" (sense: %02x %02x %02x %02x)\n",
 				   pcmd->sense_buffer[0], pcmd->sense_buffer[1],
 				   pcmd->sense_buffer[2], pcmd->sense_buffer[3]);
 	    else printk ("\n");
 #endif
-	    if((pcmd->result != (DID_OK << 16) && !(pcmd->result & SCSI_STAT_CHECKCOND) && !(pcmd->result & SCSI_STAT_BUSY)) ||
-	       ((pcmd->result & DRIVER_SENSE << 24) && (pcmd->sense_buffer[0] & 0x70) == 0x70 &&
-		(pcmd->sense_buffer[2] & 0xf) == ILLEGAL_REQUEST) || pcmd->result & DID_ERROR << 16)
+	    if( (host_byte(pcmd->result) != DID_OK && !(status_byte(pcmd->result) & CHECK_CONDITION) && !(status_byte(pcmd->result) & BUSY)) ||
+	       ((driver_byte(pcmd->result) & DRIVER_SENSE) && (pcmd->sense_buffer[0] & 0x70) == 0x70 &&
+		(pcmd->sense_buffer[2] & 0xf) == ILLEGAL_REQUEST) || host_byte(pcmd->result) & DID_ERROR )
 	    {
 	       /* device not present: remove */ 
-	       dc390_remove_dev (pACB, pDCB);
+	       //dc390_Going_remove (pDCB, pSRB);
+	       dc390_remove_dev (pACB, pDCB); DCB_removed = 1;
 	       
 	       if( (pcmd->target == pACB->pScsiHost->max_id - 1) &&
 		  ((pcmd->lun == 0) || (pcmd->lun == pACB->pScsiHost->max_lun - 1)) )
@@ -1534,16 +1604,17 @@
 	}
     }
    
-   if( pSRB->CmdBlock[0] == INQUIRY && 
-      (pcmd->result == DID_OK << 16 || pcmd->result & SCSI_STAT_CHECKCOND) )
+    //if( pSRB->pcmd->cmnd[0] == INQUIRY && 
+    //  (host_byte(pcmd->result) == DID_OK || status_byte(pcmd->result) & CHECK_CONDITION) )
+    if( pcmd->cmnd[0] == INQUIRY && 
+	(pcmd->result == (DID_OK << 16) || status_byte(pcmd->result) & CHECK_CONDITION) )
      {
-	ptr = (PSCSI_INQDATA) (pcmd->request_buffer);
-	if( pcmd->use_sg )
-	  ptr = (PSCSI_INQDATA) (((PSGL) ptr)->address);
-	if ((ptr->DevType & SCSI_DEVTYPE) == TYPE_NODEV)
+	if ((ptr->DevType & SCSI_DEVTYPE) == TYPE_NODEV && !DCB_removed)
 	  {
+	     //printk ("DC390: Type = nodev! (%02i-%i)\n", pcmd->target, pcmd->lun);
 	     /* device not present: remove */
-	     dc390_remove_dev (pACB, pDCB);
+	     //dc390_Going_remove (pDCB, pSRB);
+	     dc390_remove_dev (pACB, pDCB); DCB_removed = 1;
 	  }
 	else
 	  {
@@ -1555,40 +1626,29 @@
 	    (pcmd->lun == pACB->pScsiHost->max_lun - 1) )
 	  pACB->scan_devices = 0;
      };
-/*  dc390_ReleaseSRB( pDCB, pSRB ); */
 
-    if(pSRB == pDCB->pGoingSRB )
-    {
-	pDCB->pGoingSRB = pSRB->pNextSRB;
-    }
-    else
-    {
-	psrb = pDCB->pGoingSRB;
-	while( psrb->pNextSRB != pSRB )
-	    psrb = psrb->pNextSRB;
-	psrb->pNextSRB = pSRB->pNextSRB;
-	if( pSRB == pDCB->pGoingLast )
-	    pDCB->pGoingLast = psrb;
-    }
-    pSRB->pNextSRB = pACB->pFreeSRB;
-    pACB->pFreeSRB = pSRB;
-    pDCB->GoingSRBCnt--;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,30)
+    pcmd->resid = pcmd->request_bufflen - pSRB->TotalXferredLen;
+#endif
 
-    dc390_DoWaitingSRB( pACB );
+    if (!DCB_removed) dc390_Going_remove (pDCB, pSRB);
+    /* Add to free list */
+    dc390_Free_insert (pACB, pSRB);
 
+    DEBUG0(printk (KERN_DEBUG "DC390: SRBdone: done pid %li\n", pcmd->pid);)
     DC390_UNLOCK_ACB_NI;
-    pcmd->scsi_done( pcmd );
+    pcmd->scsi_done (pcmd);
     DC390_LOCK_ACB_NI;
 
-    if( pDCB->QIORBCnt )
-	dc390_DoNextCmd( pACB, pDCB );
+    dc390_Query_to_Waiting (pACB);
+    dc390_Waiting_process (pACB);
     return;
 }
 
 
-/* Remove all SRBs and tell midlevel code DID_RESET */
+/* Remove all SRBs from Going list and inform midlevel */
 void
-dc390_DoingSRB_Done( PACB pACB )
+dc390_DoingSRB_Done( PACB pACB, PSCSICMD cmd )
 {
     PDCB   pDCB, pdcb;
     PSRB   psrb, psrb2;
@@ -1605,16 +1665,21 @@
 	{
 	    psrb2 = psrb->pNextSRB;
 	    pcmd = psrb->pcmd;
-	    pcmd->result = DID_RESET << 16;
+	    dc390_Free_insert (pACB, psrb);
+#ifndef USE_NEW_EH
+	    /* New EH will crash on being given timed out cmnds */
+	    if (pcmd == cmd)
+		pcmd->result = MK_RES(0,DID_ABORT,0,0);
+	    else
+		pcmd->result = MK_RES(0,DID_RESET,0,0);
 
 /*	    ReleaseSRB( pDCB, pSRB ); */
 
-	    psrb->pNextSRB = pACB->pFreeSRB;
-	    pACB->pFreeSRB = psrb;
-
+	    DEBUG0(printk (KERN_DEBUG "DC390: DoingSRB_Done: done pid %li\n", pcmd->pid);)
 	    DC390_UNLOCK_ACB_NI;
 	    pcmd->scsi_done( pcmd );
 	    DC390_LOCK_ACB_NI;
+#endif	
 	    psrb  = psrb2;
 	}
 	pdcb->GoingSRBCnt = 0;;
@@ -1622,21 +1687,21 @@
 	pdcb->TagMask = 0;
 	pdcb = pdcb->pNextDCB;
     } while( pdcb != pDCB );
+    dc390_Query_to_Waiting (pACB);
 }
 
 
 static void
 dc390_ResetSCSIBus( PACB pACB )
 {
-    pACB->ACBFlag |= RESET_DEV;
-
-    DC390_write8 (ScsiCmd, RST_DEVICE_CMD);
-    udelay (250);
-    DC390_write8 (ScsiCmd, NOP_CMD);
+    //DC390_write8 (ScsiCmd, RST_DEVICE_CMD);
+    //udelay (250);
+    //DC390_write8 (ScsiCmd, NOP_CMD);
 
     DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
     DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
     DC390_write8 (ScsiCmd, RST_SCSI_BUS_CMD);
+    pACB->Connected = 0;
 
     return;
 }
@@ -1644,27 +1709,31 @@
 static void
 dc390_ScsiRstDetect( PACB pACB )
 {
-    printk ("DC390: Rst_Detect: laststat = %08lx\n", dc390_laststatus);
+    printk ("DC390: Rst_Detect: laststat = %08x\n", dc390_laststatus);
     //DEBUG0(printk(KERN_INFO "RST_DETECT,");)
 
+    if (timer_pending (&pACB->Waiting_Timer)) del_timer (&pACB->Waiting_Timer);
     DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
     /* Unlock before ? */
-    /* delay a second */
-    { unsigned int msec = 1*1000; while (--msec) udelay(1000); }
+    /* delay half a second */
+    udelay (1000);
     DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+    pACB->pScsiHost->last_reset = jiffies + 5*HZ/2
+		    + HZ * dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY];
+    pACB->Connected = 0;
 
     if( pACB->ACBFlag & RESET_DEV )
 	pACB->ACBFlag |= RESET_DONE;
     else
-    {
+    {   /* Reset was issued by sb else */
 	pACB->ACBFlag |= RESET_DETECT;
 
 	dc390_ResetDevParam( pACB );
-/*	dc390_DoingSRB_Done( pACB ); ???? */
-	dc390_RecoverSRB( pACB );
+	dc390_DoingSRB_Done( pACB, 0 );
+	//dc390_RecoverSRB( pACB );
 	pACB->pActiveDCB = NULL;
 	pACB->ACBFlag = 0;
-	dc390_DoWaitingSRB( pACB );
+	dc390_Waiting_process( pACB );
     }
     return;
 }
@@ -1676,15 +1745,17 @@
     PSCSICMD  pcmd;
 
     REMOVABLEDEBUG(printk (KERN_INFO "DC390: RequestSense (Cmd %02x, Id %02x, LUN %02x)\n",\
-	    pSRB->CmdBlock[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN);)
+	    pSRB->pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN);)
 
     pSRB->SRBFlag |= AUTO_REQSENSE;
-    pSRB->Segment0[0] = (ULONG) pSRB->CmdBlock[0];
-    pSRB->Segment0[1] = (ULONG) pSRB->CmdBlock[4];
-    pSRB->Segment1[0] = (ULONG) ((pSRB->ScsiCmdLen << 8) + pSRB->SGcount);
-    pSRB->Segment1[1] = pSRB->TotalXferredLen;
+    //pSRB->Segment0[0] = (UINT) pSRB->CmdBlock[0];
+    //pSRB->Segment0[1] = (UINT) pSRB->CmdBlock[4];
+    //pSRB->Segment1[0] = ((UINT)(pSRB->pcmd->cmd_len) << 8) + pSRB->SGcount;
+    //pSRB->Segment1[1] = pSRB->TotalXferredLen;
+    pSRB->SavedSGCount = pSRB->SGcount;
+    pSRB->SavedTotXLen = pSRB->TotalXferredLen;
     pSRB->AdaptStatus = 0;
-    pSRB->TargetStatus = 0; /* SCSI_STAT_CHECKCOND; */
+    pSRB->TargetStatus = 0; /* CHECK_CONDITION<<1; */
 
     pcmd = pSRB->pcmd;
 
@@ -1694,16 +1765,18 @@
     pSRB->SGcount = 1;
     pSRB->SGIndex = 0;
 
-    pSRB->CmdBlock[0] = REQUEST_SENSE;
-    pSRB->CmdBlock[1] = pDCB->IdentifyMsg << 5;
-    (USHORT) pSRB->CmdBlock[2] = 0;
-    (USHORT) pSRB->CmdBlock[4] = sizeof(pcmd->sense_buffer);
-    pSRB->ScsiCmdLen = 6;
+    //pSRB->CmdBlock[0] = REQUEST_SENSE;
+    //pSRB->CmdBlock[1] = pDCB->TargetLUN << 5;
+    //(USHORT) pSRB->CmdBlock[2] = 0;
+    //(USHORT) pSRB->CmdBlock[4] = sizeof(pcmd->sense_buffer);
+    //pSRB->ScsiCmdLen = 6;
 
     pSRB->TotalXferredLen = 0;
     pSRB->SGToBeXferLen = 0;
-    if( dc390_StartSCSI( pACB, pDCB, pSRB ) )
-	dc390_RewaitSRB( pDCB, pSRB );
+    if( dc390_StartSCSI( pACB, pDCB, pSRB ) ) {
+	dc390_Going_to_Waiting ( pDCB, pSRB );
+	dc390_waiting_timer (pACB, HZ/5);
+    }
 }
 
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/sr.c linux.19p18/drivers/scsi/sr.c
--- linux.vanilla/drivers/scsi/sr.c	Mon Dec 11 22:12:55 2000
+++ linux.19p18/drivers/scsi/sr.c	Wed Dec 13 21:35:56 2000
@@ -26,6 +26,8 @@
  *	Modified by Jens Axboe <axboe@suse.de> - support DVD-RAM
  *	transparently and loose the GHOST hack
  *
+ *	Modified by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *	check resource allocation in sr_init and some cleanups - 2000/12/09
  */
 
 #include <linux/module.h>
@@ -70,10 +72,10 @@
 	sr_finish, sr_attach, sr_detach
 };
 
-Scsi_CD *scsi_CDs = NULL;
-static int *sr_sizes = NULL;
+Scsi_CD *scsi_CDs;
+static int *sr_sizes;
 
-static int *sr_blocksizes = NULL;
+static int *sr_blocksizes;
 
 static int sr_open(struct cdrom_device_info *, int);
 void get_sectorsize(int);
@@ -1113,16 +1115,21 @@
 	}
 	if (scsi_CDs)
 		return 0;
-	sr_template.dev_max =
-	    sr_template.dev_noticed + SR_EXTRA_DEVS;
-	scsi_CDs = (Scsi_CD *) scsi_init_malloc(sr_template.dev_max * sizeof(Scsi_CD), GFP_ATOMIC);
-	memset(scsi_CDs, 0, sr_template.dev_max * sizeof(Scsi_CD));
-
-	sr_sizes = (int *) scsi_init_malloc(sr_template.dev_max * sizeof(int), GFP_ATOMIC);
-	memset(sr_sizes, 0, sr_template.dev_max * sizeof(int));
-
-	sr_blocksizes = (int *) scsi_init_malloc(sr_template.dev_max *
-						 sizeof(int), GFP_ATOMIC);
+	sr_template.dev_max = sr_template.dev_noticed + SR_EXTRA_DEVS;
+	scsi_CDs = scsi_init_malloc(sr_template.dev_max * sizeof(Scsi_CD),
+					GFP_ATOMIC);
+	if (!scsi_CDs)
+		goto cleanup_register;
+
+	sr_sizes = scsi_init_malloc(sr_template.dev_max * sizeof(int),
+					GFP_ATOMIC);
+	if (!sr_sizes)
+		goto cleanup_cds;
+
+	sr_blocksizes = scsi_init_malloc(sr_template.dev_max * sizeof(int),
+					GFP_ATOMIC);
+	if (!sr_blocksizes)
+		goto cleanup_sizes;
 
 	/*
 	 * These are good guesses for the time being.
@@ -1131,6 +1138,18 @@
 		sr_blocksizes[i] = 2048;
 	blksize_size[MAJOR_NR] = sr_blocksizes;
 	return 0;
+cleanup_sizes:
+	scsi_init_free((char *) sr_sizes, sr_template.dev_max * sizeof(int));
+	sr_sizes = NULL;
+cleanup_cds:
+	scsi_init_free((char *) scsi_CDs,
+		       (sr_template.dev_noticed + SR_EXTRA_DEVS) *
+		       sizeof(Scsi_CD));
+	scsi_CDs = NULL;
+cleanup_register:
+	unregister_blkdev(MAJOR_NR, "sr");
+	sr_registered--;
+	return 1;
 }
 
 void sr_finish()
@@ -1241,7 +1260,7 @@
 		scsi_init_free((char *) scsi_CDs,
 			       (sr_template.dev_noticed + SR_EXTRA_DEVS)
 			       * sizeof(Scsi_CD));
-
+		scsi_CDs = NULL;
 		scsi_init_free((char *) sr_sizes, sr_template.dev_max * sizeof(int));
 		sr_sizes = NULL;
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/st.c linux.19p18/drivers/scsi/st.c
--- linux.vanilla/drivers/scsi/st.c	Mon Dec 11 22:12:55 2000
+++ linux.19p18/drivers/scsi/st.c	Wed Dec 13 21:31:48 2000
@@ -55,6 +55,8 @@
 
 #include "constants.h"
 
+#include "osst_detect.h"
+
 #ifdef MODULE
 MODULE_PARM(buffer_kbs, "i");
 MODULE_PARM(write_threshold_kbs, "i");
@@ -3407,6 +3409,18 @@
 #endif
 
 
+/* Returns zero for drives not supported by this driver */
+static int st_supported(Scsi_Device * SDp)
+{
+  /* These OnStream SC drives require a special driver. The OnStream ADR* drives
+     are supported by this driver */
+  if ( OSST_SUPPORTS(SDp) )
+      return 0;
+
+  return 1;
+}
+
+
 static struct file_operations st_fops = {
    NULL,            /* lseek - default */
    st_read,         /* read - general block-dev read */
@@ -3429,6 +3443,8 @@
 
    if (SDp->type != TYPE_TAPE)
        return 1;
+   if (!st_supported(SDp))
+       return 1;
 
    if (st_template.nr_dev >= st_template.dev_max) {
        SDp->attached--;
@@ -3502,6 +3518,8 @@
 static int st_detect(Scsi_Device * SDp)
 {
   if(SDp->type != TYPE_TAPE) return 0;
+  if (!st_supported(SDp))
+      return 0;
 
   printk(KERN_WARNING
 	 "Detected scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n",
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/tmscsim.c linux.19p18/drivers/scsi/tmscsim.c
--- linux.vanilla/drivers/scsi/tmscsim.c	Sat Sep  9 18:42:42 2000
+++ linux.19p18/drivers/scsi/tmscsim.c	Sat Dec 30 19:46:47 2000
@@ -5,11 +5,11 @@
  *		     Bus Master Host Adapter			       *
  * (C)Copyright 1995-1996 Tekram Technology Co., Ltd.		       *
  ***********************************************************************/
-/* (C) Copyright: put under GNU GPL in 10/96				*
+/* (C) Copyright: put under GNU GPL in 10/96  (see README.tmscsim)	*
 *************************************************************************/
-/* $Id: tmscsim.c,v 2.16 1998/12/25 17:54:44 garloff Exp $		*/
+/* $Id: tmscsim.c,v 2.60.2.30 2000/12/20 01:07:12 garloff Exp $		*/
 /*	Enhancements and bugfixes by					*
- *	Kurt Garloff <kurt@garloff.de>					*
+ *	Kurt Garloff <kurt@garloff.de>	<garloff@suse.de>		*
  ***********************************************************************/
 /*	HISTORY:							*
  *									*
@@ -95,8 +95,75 @@
  *	2.0c  98/11/19	KG	Cleaned up detect/init for SMP boxes, 	*
  *				Write Erase DMA (1.20t) caused problems	*
  *	2.0d  98/12/25	KG	Christmas release ;-) Message handling  *
- *				competely reworked. Handle target ini-	*
+ *				completely reworked. Handle target ini-	*
  *				tiated SDTR correctly.			*
+ *	2.0d1 99/01/25	KG	Try to handle RESTORE_PTR		*
+ *	2.0d2 99/02/08	KG	Check for failure of kmalloc, correct 	*
+ *				inclusion of scsicam.h, DelayReset	*
+ *	2.0d3 99/05/31	KG	DRIVER_OK -> DID_OK, DID_NO_CONNECT,	*
+ *				detect Target mode and warn.		*
+ *				pcmd->result handling cleaned up.	*
+ *	2.0d4 99/06/01	KG	Cleaned selection process. Found bug	*
+ *				which prevented more than 16 tags. Now:	*
+ *				24. SDTR cleanup. Cleaner multi-LUN	*
+ *				handling. Don't modify ControlRegs/FIFO	*
+ *				when connected.				*
+ *	2.0d5 99/06/01	KG	Clear DevID, Fix INQUIRY after cfg chg.	*
+ *	2.0d6 99/06/02	KG	Added ADD special command to allow cfg.	*
+ *				before detection. Reset SYNC_NEGO_DONE	*
+ *				after a bus reset.			*
+ *	2.0d7 99/06/03	KG	Fixed bugs wrt add,remove commands	*
+ *	2.0d8 99/06/04	KG	Removed copying of cmnd into CmdBlock.	*
+ *				Fixed Oops in _release().		*
+ *	2.0d9 99/06/06	KG	Also tag queue INQUIRY, T_U_R, ...	*
+ *				Allow arb. no. of Tagged Cmnds. Max 32	*
+ *	2.0d1099/06/20	KG	TagMaxNo changes now honoured! Queueing *
+ *				clearified (renamed ..) TagMask handling*
+ *				cleaned.				*
+ *	2.0d1199/06/28	KG	cmd->result now identical to 2.0d2	*
+ *	2.0d1299/07/04	KG	Changed order of processing in IRQ	*
+ *	2.0d1399/07/05	KG	Don't update DCB fields if removed	*
+ *	2.0d1499/07/05	KG	remove_dev: Move kfree() to the end	*
+ *	2.0d1599/07/12	KG	use_new_eh_code: 0, ULONG -> UINT where	*
+ *				appropriate				*
+ *	2.0d1699/07/13	KG	Reenable StartSCSI interrupt, Retry msg	*
+ *	2.0d1799/07/15	KG	Remove debug msg. Disable recfg. when	*
+ *				there are queued cmnds			*
+ *	2.0d1899/07/18	KG	Selection timeout: Don't requeue	*
+ *	2.0d1999/07/18	KG	Abort: Only call scsi_done if dequeued	*
+ *	2.0d2099/07/19	KG	Rst_Detect: DoingSRB_Done		*
+ *	2.0d2199/08/15	KG	dev_id for request/free_irq, cmnd[0] for*
+ *				RETRY, SRBdone does DID_ABORT for the 	*
+ *				cmd passed by DC390_reset()		*
+ *	2.0d2299/08/25	KG	dev_id fixed. can_queue: 42		*
+ *	2.0d2399/08/25	KG	Removed some debugging code. dev_id 	*
+ *				now is set to pACB. Use u8,u16,u32. 	*
+ *	2.0d2499/11/14	KG	Unreg. I/O if failed IRQ alloc. Call	*
+ * 				done () w/ DID_BAD_TARGET in case of	*
+ *				missing DCB. We	are old EH!!		*
+ *	2.0d2500/01/15	KG	2.3.3x compat from Andreas Schultz	*
+ *				set unique_id. Disable RETRY message.	*
+ *	2.0d2600/01/29	KG	Go to new EH.				*
+ *	2.0d2700/01/31	KG	... but maintain 2.0 compat.		*
+ *				and fix DCB freeing			*
+ *	2.0d2800/02/14	KG	Queue statistics fixed, dump special cmd*
+ *				Waiting_Timer for failed StartSCSI	*
+ *				New EH: Don't return cmnds to ML on RST *
+ *				Use old EH (don't have new EH fns yet)	*
+ * 				Reset: Unlock, but refuse to queue	*
+ * 				2.3 __setup function			*
+ *	2.0e  00/05/22	KG	Return residual for 2.3			*
+ *	2.0e1 00/05/25	KG	Compile fixes for 2.3.99		*
+ *	2.0e2 00/05/27	KG	Jeff Garzik's pci_enable_device()	*
+ *	2.0e3 00/09/29	KG	Some 2.4 changes. Don't try Sync Nego	*
+ *				before INQUIRY has reported ability. 	*
+ *				Recognise INQUIRY as scanning command.	*
+ *	2.0e4 00/10/13	KG	Allow compilation into 2.4 kernel	*
+ *	2.0e5 00/11/17	KG	Store Inq.flags in DCB			*
+ *	2.0e6 00/11/22  KG	2.4 init function (Thx to O.Schumann)	*
+ * 				2.4 PCI device table (Thx to A.Richter)	*
+ *	2.0e7 00/11/28	KG	Allow overriding of BIOS settings	*
+ *	2.0f  00/12/20	KG	Handle failed INQUIRYs during scan	*
  ***********************************************************************/
 
 /* Uncomment SA_INTERRUPT, if the driver refuses to share its IRQ with other devices */
@@ -108,6 +175,7 @@
 //#define DC390_DCBDEBUG
 //#define DC390_PARSEDEBUG
 //#define DC390_REMOVABLEDEBUG
+//#define DC390_LOCKDEBUG
 
 /* Debug definitions */
 #ifdef DC390_DEBUG0
@@ -159,6 +227,7 @@
 #include <linux/config.h>
 #include <linux/version.h>
 #include <linux/blk.h>
+#include <linux/timer.h>
 
 #include "scsi.h"
 #include "hosts.h"
@@ -175,8 +244,7 @@
 
 /* Note: Starting from 2.1.9x, the mid-level scsi code issues a 
  * spinlock_irqsave (&io_request_lock) before calling the driver's 
- * routines, so we don't need to lock.
- * TODO: Verify, if we are locked in every case!
+ * routines, so we don't need to lock, except in the IRQ handler.
  * The policy 3, let the midlevel scsi code do the io_request_locks
  * and us locking on a driver specific lock, shouldn't hurt anybody; it
  * just causes a minor performance degradation for setting the locks.
@@ -189,31 +257,46 @@
  * undef  : traditional save_flags; cli; restore_flags;
  */
 
-//#define DEBUG_SPINLOCKS 2	/* Set to 0, 1 or 2 in include/asm/spinlock.h */
+//#define DEBUG_SPINLOCKS 2	/* Set to 0, 1 or 2 in include/linux/spinlock.h */
 
-#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
-
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,30)
 # include <linux/init.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,30)
+# include <linux/spinlock.h>
+#else
 # include <asm/spinlock.h>
 #endif
+#endif
 
 
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93) 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,93) 
 # define USE_SPINLOCKS 1
 # define NEW_PCI 1
 #else
 # undef NEW_PCI
-# if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30)
+# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,30)
 #  define USE_SPINLOCKS 2
 # endif
 #endif
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,99)
+static struct pci_device_id tmscsim_pci_tbl[] __initdata = {
+	{
+		vendor: PCI_VENDOR_ID_AMD,
+		device: PCI_DEVICE_ID_AMD53C974,
+		subvendor: PCI_ANY_ID,
+		subdevice: PCI_ANY_ID,
+	},
+	{ }		/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(pci, tmscsim_pci_tbl);
+#endif
+	
 #ifdef USE_SPINLOCKS
 
 # if USE_SPINLOCKS == 3 /* both */
 
-#  if defined (__SMP__) || DEBUG_SPINLOCKS > 0
+#  if defined (CONFIG_SMP) || DEBUG_SPINLOCKS > 0
 #   define DC390_LOCKA_INIT { spinlock_t __unlocked = SPIN_LOCK_UNLOCKED; pACB->lock = __unlocked; };
 #  else
 #   define DC390_LOCKA_INIT
@@ -320,7 +403,11 @@
 # define PCI_PRESENT pci_present ()
 # define PCI_SET_MASTER pci_set_master (pdev)
 # define PCI_FIND_DEVICE(vend, id) (pdev = pci_find_device (vend, id, pdev))
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,10)
+# define PCI_GET_IO_AND_IRQ io_port = pci_resource_start (pdev, 0); irq = pdev->irq
+#else
 # define PCI_GET_IO_AND_IRQ io_port = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; irq = pdev->irq
+#endif
 #else
 # include <linux/bios32.h>
 # define PDEV pbus, pdevfn
@@ -369,7 +456,7 @@
 void dc390_Disconnect( PACB pACB );
 void dc390_Reselect( PACB pACB );
 void dc390_SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB );
-void dc390_DoingSRB_Done( PACB pACB );
+void dc390_DoingSRB_Done( PACB pACB, PSCSICMD cmd );
 static void dc390_ScsiRstDetect( PACB pACB );
 static void dc390_ResetSCSIBus( PACB pACB );
 static void __inline__ dc390_RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB );
@@ -379,7 +466,7 @@
 void do_DC390_Interrupt( int, void *, struct pt_regs *);
 
 int    dc390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, UCHAR index );
-void   dc390_initDCB( PACB pACB, PDCB *ppDCB, PSCSICMD cmd );
+void   dc390_initDCB( PACB pACB, PDCB *ppDCB, UCHAR id, UCHAR lun);
 void   dc390_updateDCB (PACB pACB, PDCB pDCB);
 
 #ifdef MODULE
@@ -393,31 +480,19 @@
 //static PSH	dc390_pSH_current = NULL;
 static PACB	dc390_pACB_start= NULL;
 static PACB	dc390_pACB_current = NULL;
-static UCHAR	dc390_adapterCnt = 0;
-static UCHAR	dc390_CurrSyncOffset = 0;
 static ULONG	dc390_lastabortedpid = 0;
-static ULONG	dc390_laststatus = 0;
+static UINT	dc390_laststatus = 0;
+static UCHAR	dc390_adapterCnt = 0;
 
-#ifndef CONFIG_SCSI_DC390T_NOGENSUPP
 /* Startup values, to be overriden on the commandline */
-int tmscsim[] = {7, 1 /* 8MHz */, 
-		PARITY_CHK_ | SEND_START_ | EN_DISCONNECT_
-		| SYNC_NEGO_ | TAG_QUEUEING_,
-		MORE2_DRV | GREATER_1G | RST_SCSI_BUS | ACTIVE_NEGATION
-		/* | NO_SEEK */
-# ifdef CONFIG_SCSI_MULTI_LUN
-		| LUN_CHECK
-# endif
-		, 3 /* 16 Tags per LUN */};
+int tmscsim[] = {-2, -2, -2, -2, -2, -2};
 
-# if defined(MODULE) && LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30)
-MODULE_PARM(tmscsim, "1-5i");
-MODULE_PARM_DESC(tmscsim, "Host SCSI ID, Speed (0=10MHz), Device Flags, Adapter Flags, Max Tags (log2(tags)-1)");
+# if defined(MODULE) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,30)
+MODULE_PARM(tmscsim, "1-6i");
+MODULE_PARM_DESC(tmscsim, "Host SCSI ID, Speed (0=10MHz), Device Flags, Adapter Flags, Max Tags (log2(tags)-1), DelayReset (s)");
 # endif
 
-#endif /* CONFIG_SCSI_DC390T_NOGENSUPP */
-
-#if defined(MODULE) && LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30)
+#if defined(MODULE) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,30)
 MODULE_AUTHOR("C.L. Huang / Kurt Garloff");
 MODULE_DESCRIPTION("SCSI host adapter driver for Tekram DC390 and other AMD53C974A based PCI SCSI adapters");
 MODULE_SUPPORTED_DEVICE("sd,sr,sg,st");
@@ -482,12 +557,14 @@
 static char*  dc390_adapname = "DC390";
 UCHAR  dc390_eepromBuf[MAX_ADAPTER_NUM][EE_LEN];
 UCHAR  dc390_clock_period1[] = {4, 5, 6, 7, 8, 10, 13, 20};
+UCHAR  dc390_clock_speed[] = {100,80,67,57,50, 40, 31, 20};
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,30)
 struct proc_dir_entry	DC390_proc_scsi_tmscsim ={
        PROC_SCSI_DC390T, 7 ,"tmscsim",
        S_IFDIR | S_IRUGO | S_IXUGO, 2
        };
-
+#endif
 
 /***********************************************************************
  * Functions for access to DC390 EEPROM
@@ -511,59 +588,107 @@
     udelay(160);
 }
 
-#ifndef CONFIG_SCSI_DC390T_NOGENSUPP
-static void __init dc390_EEpromDefaults (UCHAR index)
+
+/* Override EEprom values with explicitly set values */
+static void __init dc390_EEprom_Override (UCHAR index)
 {
     PUCHAR ptr;
     UCHAR  id;
     ptr = (PUCHAR) dc390_eepromBuf[index];
     
     /* Adapter Settings */
-    ptr[EE_ADAPT_SCSI_ID] = (UCHAR)tmscsim[0]; /* Adapter ID */
-    ptr[EE_MODE2] = (UCHAR)tmscsim[3];
-    ptr[EE_DELAY] = 0; /* ?? */
-    ptr[EE_TAG_CMD_NUM] = (UCHAR)tmscsim[4]; /* Tagged Comds */
+    if (tmscsim[0] != -2)
+	ptr[EE_ADAPT_SCSI_ID] = (UCHAR)tmscsim[0];	/* Adapter ID */
+    if (tmscsim[3] != -2)
+	ptr[EE_MODE2] = (UCHAR)tmscsim[3];
+    if (tmscsim[5] != -2)
+	ptr[EE_DELAY] = tmscsim[5];			/* Reset delay */
+    if (tmscsim[4] != -2)
+	ptr[EE_TAG_CMD_NUM] = (UCHAR)tmscsim[4];	/* Tagged Cmds */
     
     /* Device Settings */
     for (id = 0; id < MAX_SCSI_ID; id++)
     {
-      ptr[id<<2] = (UCHAR)tmscsim[2]; /* EE_MODE1 */
-      ptr[(id<<2) + 1] = (UCHAR)tmscsim[1]; /* EE_Speed */
+	if (tmscsim[2] != -2)
+		ptr[id<<2] = (UCHAR)tmscsim[2];		/* EE_MODE1 */
+	if (tmscsim[1] != -2)
+		ptr[(id<<2) + 1] = (UCHAR)tmscsim[1];	/* EE_Speed */
     };
-    dc390_adapname = "AM53C974";
 }
 
-static void __init dc390_checkparams (void)
+/* Handle "-1" case */
+static void __init dc390_check_for_safe_settings (void)
 {
-	PARSEDEBUG(printk(KERN_INFO "DC390: setup %08x %08x %08x %08x %08x\n", tmscsim[0],\
-		      tmscsim[1], tmscsim[2], tmscsim[3], tmscsim[4]);)
-	if (tmscsim[0] < 0 || tmscsim[0] > 7) /* modules-2.0.0 passes -1 as string */
+	if (tmscsim[0] == -1 || tmscsim[0] > 15) /* modules-2.0.0 passes -1 as string */
 	{
-		tmscsim[0] = 7; tmscsim[1] = 4; 
-		tmscsim[2] = 9; tmscsim[3] = 15;
-		tmscsim[4] = 2;
+		tmscsim[0] = 7; tmscsim[1] = 4;
+		tmscsim[2] = 0x09; tmscsim[3] = 0x0f;
+		tmscsim[4] = 2; tmscsim[5] = 10;
 		printk (KERN_INFO "DC390: Using safe settings.\n");
 	}
-	else
+}
+
+
+#ifndef CONFIG_SCSI_DC390T_NOGENSUPP
+int __initdata tmscsim_def[] = {7, 0 /* 10MHz */,
+		PARITY_CHK_ | SEND_START_ | EN_DISCONNECT_
+		| SYNC_NEGO_ | TAG_QUEUEING_,
+		MORE2_DRV | GREATER_1G | RST_SCSI_BUS | ACTIVE_NEGATION
+		/* | NO_SEEK */
+# ifdef CONFIG_SCSI_MULTI_LUN
+		| LUN_CHECK
+# endif
+		, 3 /* 16 Tags per LUN */, 1 /* s delay after Reset */ };
+
+/* Copy defaults over set values where missing */
+static void __init dc390_fill_with_defaults (void)
+{
+	int i;
+	PARSEDEBUG(printk(KERN_INFO "DC390: setup %08x %08x %08x %08x %08x %08x\n", tmscsim[0],\
+		      tmscsim[1], tmscsim[2], tmscsim[3], tmscsim[4], tmscsim[5]);)
+	for (i = 0; i < 6; i++)
 	{
-		/* if (tmscsim[0] < 0 || tmscsim[0] > 7) tmscsim[0] = 7; */
-		if (tmscsim[1] < 0 || tmscsim[1] > 7) tmscsim[1] = 4;
-		if (tmscsim[4] < 0 || tmscsim[4] > 5) tmscsim[4] = 4;
-	};
+		if (tmscsim[i] < 0 || tmscsim[i] > 255)
+			tmscsim[i] = tmscsim_def[i];
+	}
+	/* Sanity checks */
+	if (tmscsim[0] >   7) tmscsim[0] =   7;
+	if (tmscsim[1] >   7) tmscsim[1] =   4;
+	if (tmscsim[4] >   5) tmscsim[4] =   4;
+	if (tmscsim[5] > 180) tmscsim[5] = 180;
 };
+#endif
+
 /* Override defaults on cmdline:
  * tmscsim: AdaptID, MaxSpeed (Index), DevMode (Bitmapped), AdaptMode (Bitmapped)
  */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,13)
+void __init dc390_setup (char *str)
+{	
+	int ints[8];
+	int i, im;
+	(void)get_options (str, ARRAY_SIZE(ints), ints);
+#else
 void __init dc390_setup (char *str, int *ints)
 {
-	int i;
-	for (i = 0; i < ints[0]; i++)
-		tmscsim[i] = ints[i+1];
-	if (ints[0] > 5)
+	int i, im;
+#endif
+	im = ints[0];
+	if (im > 6)
+	{
 		printk (KERN_NOTICE "DC390: ignore extra params!\n");
+		im = 6;
+	};
+	for (i = 0; i < im; i++)
+		tmscsim[i] = ints[i+1];
 	/* dc390_checkparams (); */
 };
-#endif /* CONFIG_SCSI_DC390T_NOGENSUPP */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,13)
+#ifndef MODULE
+__setup("tmscsim=", dc390_setup);
+#endif
+#endif
 
 
 static void __init dc390_EEpromOutDI( PDEVDECL, PUCHAR regval, UCHAR Carry )
@@ -652,6 +777,12 @@
 }
 
 
+static void __init dc390_interpret_delay (UCHAR index)
+{
+    char interpd [] = {1,3,5,10,16,30,60,120};
+    dc390_eepromBuf[index][EE_DELAY] = interpd [dc390_eepromBuf[index][EE_DELAY]];
+};
+
 static UCHAR __init dc390_CheckEEpromCheckSum( PDEVDECL, UCHAR index )
 {
     UCHAR  i;
@@ -662,6 +793,8 @@
     memcpy (dc390_eepromBuf[index], EEbuf, EE_ADAPT_SCSI_ID);
     memcpy (&dc390_eepromBuf[index][EE_ADAPT_SCSI_ID], 
 	    &EEbuf[REAL_EE_ADAPT_SCSI_ID], EE_LEN - EE_ADAPT_SCSI_ID);
+    dc390_interpret_delay (index);
+    
     wval = 0;
     for(i=0; i<0x40; i++, ptr++)
 	wval += *ptr;
@@ -674,65 +807,94 @@
  * (DCBs, SRBs, Queueing)
  *
  **********************************************************************/
-static PDCB __inline__ dc390_findDCB ( PACB pACB, Scsi_Cmnd *cmd)
+static PDCB __inline__ dc390_findDCB ( PACB pACB, UCHAR id, UCHAR lun)
 {
    PDCB pDCB = pACB->pLinkDCB; if (!pDCB) return 0;
-   while (pDCB->UnitSCSIID != cmd->target || pDCB->UnitSCSILUN != cmd->lun)
+   while (pDCB->TargetID != id || pDCB->TargetLUN != lun)
      {
 	pDCB = pDCB->pNextDCB;
 	if (pDCB == pACB->pLinkDCB)
 	  {
-	     printk (KERN_WARNING "DC390: DCB not found (DCB=%08x, DCBmap[%2x]=%2x)\n",
-		     (int)pDCB, cmd->target, pACB->DCBmap[cmd->target]);
+	     DCBDEBUG(printk (KERN_WARNING "DC390: DCB not found (DCB=%p, DCBmap[%2x]=%2x)\n",
+		     pDCB, id, pACB->DCBmap[id]);)
 	     return 0;
 	  }
      };
-   DCBDEBUG1( printk (KERN_DEBUG "DCB %08x (%02x,%02x) found.\n",	\
-	   (int)pDCB, pDCB->UnitSCSIID, pDCB->UnitSCSILUN);)
+   DCBDEBUG1( printk (KERN_DEBUG "DCB %p (%02x,%02x) found.\n",	\
+		      pDCB, pDCB->TargetID, pDCB->TargetLUN);)
    return pDCB;
 };
 
-static void dc390_QLinkcmd( PSCSICMD cmd, PDCB pDCB )
-{
-    PSCSICMD  pcmd;
+/* Queueing philosphy:
+ * There are a couple of lists:
+ * - Query: Contains the Scsi Commands not yet turned into SRBs (per ACB)
+ *   (Note: For new EH, it is unecessary!)
+ * - Waiting: Contains a list of SRBs not yet sent (per DCB)
+ * - Free: List of free SRB slots
+ * 
+ * If there are no waiting commands for the DCB, the new one is sent to the bus
+ * otherwise the oldest one is taken from the Waiting list and the new one is 
+ * queued to the Waiting List
+ * 
+ * Lists are managed using two pointers and eventually a counter
+ */
+
 
-    if( !pDCB->QIORBCnt )
+#if 0
+/* Look for a SCSI cmd in a SRB queue */
+static PSRB dc390_find_cmd_in_SRBq (PSCSICMD cmd, PSRB queue)
+{
+    PSRB q = queue;
+    while (q)
     {
-	pDCB->pQIORBhead = cmd;
-	pDCB->pQIORBtail = cmd;
-	pDCB->QIORBCnt++;
-	cmd->next = NULL;
+	if (q->pcmd == cmd) return q;
+	q = q->pNextSRB;
+	if (q == queue) return 0;
     }
+    return q;
+};
+#endif
+    
+
+/* Append to Query List */
+static void dc390_Query_append( PSCSICMD cmd, PACB pACB )
+{
+    DEBUG0(printk ("DC390: Append cmd %li to Query\n", cmd->pid);)
+    if( !pACB->QueryCnt )
+	pACB->pQueryHead = cmd;
     else
-    {
-	pcmd = pDCB->pQIORBtail;
-	pcmd->next = cmd;
-	pDCB->pQIORBtail = cmd;
-	pDCB->QIORBCnt++;
-	cmd->next = NULL;
-    }
+	pACB->pQueryTail->next = cmd;
 
+    pACB->pQueryTail = cmd;
+    pACB->QueryCnt++;
+    pACB->CmdOutOfSRB++;
+    cmd->next = NULL;
 }
 
 
-static __inline__ PSCSICMD dc390_Getcmd( PDCB pDCB )
+/* Return next cmd from Query list */
+static PSCSICMD dc390_Query_get ( PACB pACB )
 {
     PSCSICMD  pcmd;
 
-    pcmd = pDCB->pQIORBhead;
-    pDCB->pQIORBhead = pcmd->next;
+    pcmd = pACB->pQueryHead;
+    if (!pcmd) return pcmd;
+    DEBUG0(printk ("DC390: Get cmd %li from Query\n", pcmd->pid);)
+    pACB->pQueryHead = pcmd->next;
     pcmd->next = NULL;
-    pDCB->QIORBCnt--;
-
+    if (!pACB->pQueryHead) pACB->pQueryTail = NULL;
+    pACB->QueryCnt--;
     return( pcmd );
 }
 
 
-static __inline__ PSRB dc390_GetSRB( PACB pACB )
+/* Return next free SRB */
+static __inline__ PSRB dc390_Free_get ( PACB pACB )
 {
     PSRB   pSRB;
 
     pSRB = pACB->pFreeSRB;
+    DEBUG0(printk ("DC390: Get Free SRB %p\n", pSRB);)
     if( pSRB )
     {
 	pACB->pFreeSRB = pSRB->pNextSRB;
@@ -742,130 +904,174 @@
     return( pSRB );
 }
 
-
-static __inline__ void dc390_RewaitSRB0( PDCB pDCB, PSRB pSRB )
+/* Insert SRB oin top of free list */
+static __inline__ void dc390_Free_insert (PACB pACB, PSRB pSRB)
 {
-    PSRB   psrb1;
+    DEBUG0(printk ("DC390: Free SRB %p\n", pSRB);)
+    pSRB->pNextSRB = pACB->pFreeSRB;
+    pACB->pFreeSRB = pSRB;
+}
 
-    if( (psrb1 = pDCB->pWaitingSRB) )
-    {
-	pSRB->pNextSRB = psrb1;
-    }
-    else
-    {
-	pSRB->pNextSRB = NULL;
+
+/* Inserts a SRB to the top of the Waiting list */
+static __inline__ void dc390_Waiting_insert ( PDCB pDCB, PSRB pSRB )
+{
+    DEBUG0(printk ("DC390: Insert pSRB %p cmd %li to Waiting\n", pSRB, pSRB->pcmd->pid);)
+    pSRB->pNextSRB = pDCB->pWaitingSRB;
+    if (!pDCB->pWaitingSRB)
 	pDCB->pWaitLast = pSRB;
-    }
     pDCB->pWaitingSRB = pSRB;
+    pDCB->WaitSRBCnt++;
 }
 
 
-static void dc390_RewaitSRB( PDCB pDCB, PSRB pSRB )
+/* Queue SRB to waiting list */
+static __inline__ void dc390_Waiting_append ( PDCB pDCB, PSRB pSRB)
 {
-    PSRB   psrb1;
-    UCHAR  bval;
-
-    pDCB->GoingSRBCnt--; pDCB->pDCBACB->SelLost++;
-    DEBUG0(printk(KERN_INFO "DC390: RewaitSRB (%p, %p) pid = %li\n", pDCB, pSRB, pSRB->pcmd->pid);)
-    psrb1 = pDCB->pGoingSRB;
-    if( pSRB == psrb1 )
-    {
-	pDCB->pGoingSRB = psrb1->pNextSRB;
-    }
+    DEBUG0(printk ("DC390: Append pSRB %p cmd %li to Waiting\n", pSRB, pSRB->pcmd->pid);)
+    if( pDCB->pWaitingSRB )
+	pDCB->pWaitLast->pNextSRB = pSRB;
     else
-    {
-	while( pSRB != psrb1->pNextSRB )
-	    psrb1 = psrb1->pNextSRB;
-	psrb1->pNextSRB = pSRB->pNextSRB;
-	if( pSRB == pDCB->pGoingLast )
-	    pDCB->pGoingLast = psrb1;
-    }
-    if( (psrb1 = pDCB->pWaitingSRB) )
-    {
-	pSRB->pNextSRB = psrb1;
 	pDCB->pWaitingSRB = pSRB;
-    }
+
+    pDCB->pWaitLast = pSRB;
+    pSRB->pNextSRB = NULL;
+    pDCB->WaitSRBCnt++;
+    pDCB->pDCBACB->CmdInQ++;
+}
+
+static __inline__ void dc390_Going_append (PDCB pDCB, PSRB pSRB)
+{
+    pDCB->GoingSRBCnt++;
+    DEBUG0(printk("DC390: Append SRB %p to Going\n", pSRB);)
+    /* Append to the list of Going commands */
+    if( pDCB->pGoingSRB )
+	pDCB->pGoingLast->pNextSRB = pSRB;
     else
-    {
-	pSRB->pNextSRB = NULL;
-	pDCB->pWaitingSRB = pSRB;
-	pDCB->pWaitLast = pSRB;
-    }
+	pDCB->pGoingSRB = pSRB;
+
+    pDCB->pGoingLast = pSRB;
+    /* No next one in sent list */
+    pSRB->pNextSRB = NULL;
+};
+
+static __inline__ void dc390_Going_remove (PDCB pDCB, PSRB pSRB)
+{
+   DEBUG0(printk("DC390: Remove SRB %p from Going\n", pSRB);)
+   if (pSRB == pDCB->pGoingSRB)
+	pDCB->pGoingSRB = pSRB->pNextSRB;
+   else
+     {
+	PSRB psrb = pDCB->pGoingSRB;
+	while (psrb && psrb->pNextSRB != pSRB)
+	  psrb = psrb->pNextSRB;
+	if (!psrb) 
+	  { printk (KERN_ERR "DC390: Remove non-ex. SRB %p from Going!\n", pSRB); return; }
+	psrb->pNextSRB = pSRB->pNextSRB;
+	if (pSRB == pDCB->pGoingLast)
+	  pDCB->pGoingLast = psrb;
+     }
+   pDCB->GoingSRBCnt--;
+};
+
+/* Moves SRB from Going list to the top of Waiting list */
+static void dc390_Going_to_Waiting ( PDCB pDCB, PSRB pSRB )
+{
+    DEBUG0(printk(KERN_INFO "DC390: Going_to_Waiting (SRB %p) pid = %li\n", pSRB, pSRB->pcmd->pid);)
+    /* Remove SRB from Going */
+    dc390_Going_remove (pDCB, pSRB);
+    /* Insert on top of Waiting */
+    dc390_Waiting_insert (pDCB, pSRB);
+    /* Tag Mask must be freed elsewhere ! (KG, 99/06/18) */
+}
+
+/* Moves first SRB from Waiting list to Going list */
+static __inline__ void dc390_Waiting_to_Going ( PDCB pDCB, PSRB pSRB )
+{	
+	/* Remove from waiting list */
+	DEBUG0(printk("DC390: Remove SRB %p from head of Waiting\n", pSRB);)
+	pDCB->pWaitingSRB = pSRB->pNextSRB;
+	if( !pDCB->pWaitingSRB ) pDCB->pWaitLast = NULL;
+	pDCB->WaitSRBCnt--;
+	dc390_Going_append (pDCB, pSRB);
+}
+
+/* 2.0 timer compatibility */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,30)
+ static inline int timer_pending(struct timer_list * timer)
+ {
+	return timer->prev != NULL;
+ }
+ #define time_after(a,b)         ((long)(b) - (long)(a) < 0)
+ #define time_before(a,b)        time_after(b,a)
+#endif
 
-    bval = pSRB->TagNumber;
-    pDCB->TagMask &= (~(1 << bval));	  /* Free TAG number */
+void DC390_waiting_timed_out (unsigned long ptr);
+/* Sets the timer to wake us up */
+static void dc390_waiting_timer (PACB pACB, unsigned long to)
+{
+	if (timer_pending (&pACB->Waiting_Timer)) return;
+	init_timer (&pACB->Waiting_Timer);
+	pACB->Waiting_Timer.function = DC390_waiting_timed_out;
+	pACB->Waiting_Timer.data = (unsigned long)pACB;
+	if (time_before (jiffies + to, pACB->pScsiHost->last_reset))
+		pACB->Waiting_Timer.expires = pACB->pScsiHost->last_reset + 1;
+	else
+		pACB->Waiting_Timer.expires = jiffies + to + 1;
+	add_timer (&pACB->Waiting_Timer);
 }
 
 
-static void dc390_DoWaitingSRB( PACB pACB )
+/* Send the next command from the waiting list to the bus */
+static void dc390_Waiting_process ( PACB pACB )
 {
     PDCB   ptr, ptr1;
     PSRB   pSRB;
 
-    if( !(pACB->pActiveDCB) && !(pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) )
-    {
-	ptr = pACB->pDCBRunRobin;
-	if( !ptr )
-	{
-	    ptr = pACB->pLinkDCB;
-	    pACB->pDCBRunRobin = ptr;
-	}
-	ptr1 = ptr;
-	for( ;ptr1; )
-	{
-	    pACB->pDCBRunRobin = ptr1->pNextDCB;
-	    if( !( ptr1->MaxCommand > ptr1->GoingSRBCnt ) ||
-		!( pSRB = ptr1->pWaitingSRB ) )
-	    {
-		if(pACB->pDCBRunRobin == ptr)
-		    break;
-		ptr1 = ptr1->pNextDCB;
-	    }
+    if( (pACB->pActiveDCB) || (pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) )
+	return;
+    if (timer_pending (&pACB->Waiting_Timer)) del_timer (&pACB->Waiting_Timer);
+    ptr = pACB->pDCBRunRobin;
+    if( !ptr )
+      {
+	ptr = pACB->pLinkDCB;
+	pACB->pDCBRunRobin = ptr;
+      }
+    ptr1 = ptr;
+    if (!ptr1) return;
+    do 
+      {
+	pACB->pDCBRunRobin = ptr1->pNextDCB;
+	if( !( pSRB = ptr1->pWaitingSRB ) ||
+	    ( ptr1->MaxCommand <= ptr1->GoingSRBCnt ))
+	  ptr1 = ptr1->pNextDCB;
+	else
+	  {
+	    /* Try to send to the bus */
+	    if( !dc390_StartSCSI(pACB, ptr1, pSRB) )
+	      dc390_Waiting_to_Going (ptr1, pSRB);
 	    else
-	    {
-		if( !dc390_StartSCSI(pACB, ptr1, pSRB) )
-		{
-		    ptr1->GoingSRBCnt++;
-		    if( ptr1->pWaitLast == pSRB )
-		    {
-			ptr1->pWaitingSRB = NULL;
-			ptr1->pWaitLast = NULL;
-		    }
-		    else
-		    {
-			ptr1->pWaitingSRB = pSRB->pNextSRB;
-		    }
-		    pSRB->pNextSRB = NULL;
-
-		    if( ptr1->pGoingSRB )
-			ptr1->pGoingLast->pNextSRB = pSRB;
-		    else
-			ptr1->pGoingSRB = pSRB;
-		    ptr1->pGoingLast = pSRB;
-		}
-		break;
-	    }
-	}
-    }
+	      dc390_waiting_timer (pACB, HZ/5);
+	    break;
+	  }
+      } while (ptr1 != ptr);
     return;
 }
 
-
-static __inline__ void dc390_SRBwaiting( PDCB pDCB, PSRB pSRB)
+/* Wake up waiting queue */
+void DC390_waiting_timed_out (unsigned long ptr)
 {
-    if( pDCB->pWaitingSRB )
-    {
-	pDCB->pWaitLast->pNextSRB = pSRB;
-	pSRB->pNextSRB = NULL;
-    }
-    else
-    {
-	pDCB->pWaitingSRB = pSRB;
-    }
-    pDCB->pWaitLast = pSRB;
+	PACB pACB = (PACB)ptr;
+	DC390_IFLAGS
+	DC390_AFLAGS
+	DEBUG0(printk ("DC390: Debug: Waiting queue woken up by timer!\n");)
+	DC390_LOCK_IO;
+	DC390_LOCK_ACB;
+	dc390_Waiting_process (pACB);
+	DC390_UNLOCK_ACB;
+	DC390_UNLOCK_IO;
 }
 
-
 /***********************************************************************
  * Function: static void dc390_SendSRB (PACB pACB, PSRB pSRB)
  *
@@ -878,41 +1084,33 @@
     PDCB   pDCB;
 
     pDCB = pSRB->pSRBDCB;
-    if( !(pDCB->MaxCommand > pDCB->GoingSRBCnt) || (pACB->pActiveDCB) ||
+    if( (pDCB->MaxCommand <= pDCB->GoingSRBCnt) || (pACB->pActiveDCB) ||
 	(pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV)) )
     {
-	dc390_SRBwaiting(pDCB, pSRB);
-	goto SND_EXIT;
+	dc390_Waiting_append (pDCB, pSRB);
+	dc390_Waiting_process (pACB);
+	return;
     }
 
+#if 0
     if( pDCB->pWaitingSRB )
     {
-	dc390_SRBwaiting(pDCB, pSRB);
+	dc390_Waiting_append (pDCB, pSRB);
 /*	pSRB = GetWaitingSRB(pDCB); */	/* non-existent */
 	pSRB = pDCB->pWaitingSRB;
+	/* Remove from waiting list */
 	pDCB->pWaitingSRB = pSRB->pNextSRB;
 	pSRB->pNextSRB = NULL;
+	if (!pDCB->pWaitingSRB) pDCB->pWaitLast = NULL;
     }
-
-    if( !dc390_StartSCSI(pACB, pDCB, pSRB) )
-    {
-	pDCB->GoingSRBCnt++;
-	if( pDCB->pGoingSRB )
-	{
-	    pDCB->pGoingLast->pNextSRB = pSRB;
-	    pDCB->pGoingLast = pSRB;
-	}
-	else
-	{
-	    pDCB->pGoingSRB = pSRB;
-	    pDCB->pGoingLast = pSRB;
-	}
-    }
-    else
-	dc390_RewaitSRB0( pDCB, pSRB );
-
-SND_EXIT:
-    return;
+#endif
+	
+    if (!dc390_StartSCSI(pACB, pDCB, pSRB))
+	dc390_Going_append (pDCB, pSRB);
+    else {
+	dc390_Waiting_insert (pDCB, pSRB);
+	dc390_waiting_timer (pACB, HZ/5);
+    };
 }
 
 /***********************************************************************
@@ -927,8 +1125,8 @@
 {
     pSRB->pSRBDCB = pDCB;
     pSRB->pcmd = pcmd;
-    pSRB->ScsiCmdLen = pcmd->cmd_len;
-    memcpy (pSRB->CmdBlock, pcmd->cmnd, pcmd->cmd_len);
+    //pSRB->ScsiCmdLen = pcmd->cmd_len;
+    //memcpy (pSRB->CmdBlock, pcmd->cmnd, pcmd->cmd_len);
     
     if( pcmd->use_sg )
     {
@@ -961,8 +1159,39 @@
     pSRB->SGToBeXferLen = 0;
     pSRB->ScsiPhase = 0;
     pSRB->EndMessage = 0;
+    pSRB->TagNumber = 255;
 };
 
+/* Put cmnd from Query to Waiting list and send next Waiting cmnd */
+static void dc390_Query_to_Waiting (PACB pACB)
+{
+    Scsi_Cmnd *pcmd;
+    PSRB   pSRB;
+    PDCB   pDCB;
+
+    if( pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) )
+	return;
+
+    while (pACB->QueryCnt)
+    {
+	pSRB = dc390_Free_get ( pACB );
+	if (!pSRB) return;
+	pcmd = dc390_Query_get ( pACB );
+	if (!pcmd) { dc390_Free_insert (pACB, pSRB); return; }; /* should not happen */
+	pDCB = dc390_findDCB (pACB, pcmd->target, pcmd->lun);
+	if (!pDCB) 
+	{ 
+		dc390_Free_insert (pACB, pSRB);
+		printk (KERN_ERR "DC390: Command in queue to non-existing device!\n");
+		pcmd->result = MK_RES(DRIVER_ERROR,DID_ERROR,0,0);
+		DC390_UNLOCK_ACB_NI;
+		pcmd->done (pcmd);
+		DC390_LOCK_ACB_NI;
+	};
+	dc390_BuildSRB (pcmd, pDCB, pSRB);
+	dc390_Waiting_append ( pDCB, pSRB );
+    }
+}
 
 /***********************************************************************
  * Function : static int DC390_queue_command (Scsi_Cmnd *cmd,
@@ -985,7 +1214,6 @@
 
 int DC390_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
 {
-    Scsi_Cmnd *pcmd;
     PDCB   pDCB;
     PSRB   pSRB;
     DC390_AFLAGS
@@ -993,7 +1221,7 @@
 
 
     DEBUG0(/*  if(pACB->scan_devices) */	\
-	printk(KERN_INFO "DC390: Queue Cmd=%02x,ID=%d,LUN=%d (pid=%li)\n",\
+	printk(KERN_INFO "DC390: Queue Cmd=%02x,Tgt=%d,LUN=%d (pid=%li)\n",\
 		cmd->cmnd[0],cmd->target,cmd->lun,cmd->pid);)
 
     DC390_LOCK_ACB;
@@ -1014,25 +1242,32 @@
     if ( ( cmd->target >= pACB->pScsiHost->max_id ) || 
 	 (cmd->lun >= pACB->pScsiHost->max_lun) )
     {
-/*	printk("DC390: Ignore target %d lun %d\n",
+/*	printk ("DC390: Ignore target %d lun %d\n",
 		cmd->target, cmd->lun); */
 	DC390_UNLOCK_ACB;
-	done(cmd);
-	return( 0 );
+	//return (1);
+	done (cmd);
+	return (0);
     }
 
-    if( (pACB->scan_devices || cmd->cmnd[0] == TEST_UNIT_READY) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) )
+    if( (pACB->scan_devices || cmd->cmnd[0] == TEST_UNIT_READY || cmd->cmnd[0] == INQUIRY) && 
+       !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) )
     {
-	pACB->DCBmap[cmd->target] |= (1 << cmd->lun);
         pACB->scan_devices = 1;
 
-	dc390_initDCB( pACB, &pDCB, cmd );
+	dc390_initDCB( pACB, &pDCB, cmd->target, cmd->lun );
 	if (!pDCB)
 	  {
-	    printk (KERN_ERR "DC390: kmalloc for DCB failed, ID=%2x\n", cmd->target);
+	    printk (KERN_ERR "DC390: kmalloc for DCB failed, target %02x lun %02x\n", 
+		    cmd->target, cmd->lun);
 	    DC390_UNLOCK_ACB;
-	    done(cmd);
-	    return(0);
+	    printk ("DC390: No DCB in queue_command!\n");
+#ifdef USE_NEW_EH
+	    return (1);
+#else
+	    done (cmd);
+	    return (0);
+#endif
 	  };
             
     }
@@ -1041,71 +1276,73 @@
 	printk(KERN_INFO "DC390: Ignore target %02x lun %02x\n",
 		cmd->target, cmd->lun); 
 	DC390_UNLOCK_ACB;
-	done(cmd);
-	return(0);
+	//return (1);
+	done (cmd);
+	return (0);
     }
     else
     {
-	pDCB = dc390_findDCB (pACB, cmd);
+	pDCB = dc390_findDCB (pACB, cmd->target, cmd->lun);
 	if (!pDCB)
 	 {  /* should never happen */
+	    printk (KERN_ERR "DC390: no DCB failed, target %02x lun %02x\n", 
+		    cmd->target, cmd->lun);
 	    DC390_UNLOCK_ACB;
-	    done(cmd);
-	    return(0);
+	    printk ("DC390: No DCB in queuecommand (2)!\n");
+#ifdef USE_NEW_EH
+	    return (1);
+#else
+	    done (cmd);
+	    return (0);
+#endif
 	 };
     }
 
     pACB->Cmds++;
     cmd->scsi_done = done;
     cmd->result = 0;
+	
+    dc390_Query_to_Waiting (pACB);
 
-    if( pDCB->QIORBCnt ) /* Unsent commands ? */
+    if( pACB->QueryCnt ) /* Unsent commands ? */
     {
-	dc390_QLinkcmd( cmd, pDCB );
-	pcmd = dc390_Getcmd( pDCB ); /* Get first command */
-        pACB->CmdInQ++;
+	DEBUG0(printk ("DC390: QueryCnt != 0\n");)
+	dc390_Query_append ( cmd, pACB );
+	dc390_Waiting_process (pACB);
     }
-    else
-	pcmd = cmd;
-
-    pSRB = dc390_GetSRB( pACB );
-
-    if( !pSRB )
+    else if (pDCB->pWaitingSRB)
     {
-        dc390_QLinkcmd( pcmd, pDCB ); /* Queue command at the end */
-	pACB->CmdOutOfSRB++;
-	DC390_UNLOCK_ACB;
-	return(0);
+ 	pSRB = dc390_Free_get ( pACB );
+	DEBUG0(if (!pSRB) printk ("DC390: No free SRB but Waiting\n"); else printk ("DC390: Free SRB w/ Waiting\n");)
+	if (!pSRB) dc390_Query_append (cmd, pACB);
+	else 
+	  {
+	    dc390_BuildSRB (cmd, pDCB, pSRB);
+	    dc390_Waiting_append (pDCB, pSRB);
+	  }
+	dc390_Waiting_process (pACB);
     }
-
-    dc390_BuildSRB (pcmd, pDCB, pSRB);
-    dc390_SendSRB( pACB, pSRB );
+    else
+    {
+ 	pSRB = dc390_Free_get ( pACB );
+	DEBUG0(if (!pSRB) printk ("DC390: No free SRB w/o Waiting\n"); else printk ("DC390: Free SRB w/o Waiting\n");)
+	if (!pSRB)
+	{
+	    dc390_Query_append (cmd, pACB);
+	    dc390_Waiting_process (pACB);
+	}
+	else 
+	{
+	    dc390_BuildSRB (cmd, pDCB, pSRB);
+	    dc390_SendSRB (pACB, pSRB);
+	};
+    };
 
     DC390_UNLOCK_ACB;
-    DEBUG1(printk (KERN_DEBUG " ... command (%02x) queued successfully.\n", pcmd->cmnd[0]);)
+    DEBUG1(printk (KERN_DEBUG " ... command (pid %li) queued successfully.\n", cmd->pid);)
     return(0);
 }
 
-
-static void dc390_DoNextCmd( PACB pACB, PDCB pDCB )
-{
-    Scsi_Cmnd *pcmd;
-    PSRB   pSRB;
-
-    if( pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) )
-	return;
-
-    pcmd = dc390_Getcmd( pDCB );
-    pSRB = dc390_GetSRB( pACB );
-    if( !pSRB )
-	dc390_QLinkcmd( pcmd, pDCB );
-    else
-      {
-	dc390_BuildSRB (pcmd, pDCB, pSRB);
-	dc390_SendSRB( pACB, pSRB );
-      };
-}
-
 /* We ignore mapping problems, as we expect everybody to respect 
  * valid partition tables. Waiting for complaints ;-) */
 
@@ -1242,15 +1479,17 @@
 void dc390_dumpinfo (PACB pACB, PDCB pDCB, PSRB pSRB)
 {
     USHORT pstat; PDEVDECL1;
+    if (!pDCB) pDCB = pACB->pActiveDCB;
+    if (!pSRB && pDCB) pSRB = pDCB->pActiveSRB;
 
     if (pSRB) 
     {
-	printk ("DC390: SRB: Xferred %08lx, Remain %08lx, State %08lx, Phase %02x\n",
+	printk ("DC390: SRB: Xferred %08lx, Remain %08lx, State %08x, Phase %02x\n",
 		pSRB->TotalXferredLen, pSRB->SGToBeXferLen, pSRB->SRBState,
 		pSRB->ScsiPhase);
 	printk ("DC390: AdpaterStatus: %02x, SRB Status %02x\n", pSRB->AdaptStatus, pSRB->SRBStatus);
     };
-    printk ("DC390: Status of last IRQ (DMA/SC/Int/IRQ): %08lx\n", dc390_laststatus);
+    printk ("DC390: Status of last IRQ (DMA/SC/Int/IRQ): %08x\n", dc390_laststatus);
     printk ("DC390: Register dump: SCSI block:\n");
     printk ("DC390: XferCnt  Cmd Stat IntS IRQS FFIS Ctl1 Ctl2 Ctl3 Ctl4\n");
     printk ("DC390:  %06x   %02x   %02x   %02x",
@@ -1260,6 +1499,12 @@
 	    DC390_read8(INT_Status), DC390_read8(Current_Fifo), DC390_read8(CtrlReg1),
 	    DC390_read8(CtrlReg2), DC390_read8(CtrlReg3), DC390_read8(CtrlReg4));
     DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT);
+    if (DC390_read8(Current_Fifo) & 0x1f)
+      {
+	printk ("DC390: FIFO:");
+	while (DC390_read8(Current_Fifo) & 0x1f) printk (" %02x", DC390_read8(ScsiFifo));
+	printk ("\n");
+      };
     printk ("DC390: Register dump: DMA engine:\n");
     printk ("DC390: Cmd   STrCnt    SBusA    WrkBC    WrkAC Stat SBusCtrl\n");
     printk ("DC390:  %02x %08x %08x %08x %08x   %02x %08x\n",
@@ -1289,44 +1534,40 @@
 {
     PDCB  pDCB;
     PSRB  pSRB, psrb;
-    ULONG count, i;
-    PSCSICMD  pcmd, pcmd1;
+    UINT  count, i;
+    PSCSICMD  pcmd;
     int   status;
-    ULONG sbac;
+    //ULONG sbac;
     DC390_AFLAGS
     PACB  pACB = (PACB) cmd->host->hostdata;
 
     DC390_LOCK_ACB;
 
-    pDCB = dc390_findDCB (pACB, cmd);
-    /* abort() is too buggy at the moment. If it's called we are in trouble anyway.
-     * so let's dump some info into the syslog at least. (KG, 98/08/20) */
-    if (pDCB) pSRB = pDCB->pActiveSRB; else pSRB = 0;
-    printk ("DC390: Abort command (pid %li, DCB %p, SRB %p)\n",
-	    cmd->pid, pDCB, pSRB);
-    dc390_dumpinfo (pACB, pDCB, pSRB);
-
-    if( !pDCB ) goto  NOT_RUN;
+    printk ("DC390: Abort command (pid %li, Device %02i-%02i)\n",
+	    cmd->pid, cmd->target, cmd->lun);
 
-    if( pDCB->QIORBCnt )
+    /* First scan Query list */
+    if( pACB->QueryCnt )
     {
-	pcmd = pDCB->pQIORBhead;
+	pcmd = pACB->pQueryHead;
 	if( pcmd == cmd )
 	{
-	    pDCB->pQIORBhead = pcmd->next;
+	    /* Found: Dequeue */
+	    pACB->pQueryHead = pcmd->next;
 	    pcmd->next = NULL;
-	    pDCB->QIORBCnt--;
+	    if (cmd == pACB->pQueryTail) pACB->pQueryTail = NULL;
+	    pACB->QueryCnt--;
 	    status = SCSI_ABORT_SUCCESS;
 	    goto  ABO_X;
 	}
-	for( count = pDCB->QIORBCnt, i=0; i<count-1; i++)
+	for( count = pACB->QueryCnt, i=0; i<count-1; i++)
 	{
 	    if( pcmd->next == cmd )
 	    {
-		pcmd1 = pcmd->next;
-		pcmd->next = pcmd1->next;
-		pcmd1->next = NULL;
-		pDCB->QIORBCnt--;
+		pcmd->next = cmd->next;
+		cmd->next = NULL;
+		if (cmd == pACB->pQueryTail) pACB->pQueryTail = NULL;
+		pACB->QueryCnt--;
 		status = SCSI_ABORT_SUCCESS;
 		goto  ABO_X;
 	    }
@@ -1337,14 +1578,21 @@
 	}
     }
 	
+    pDCB = dc390_findDCB (pACB, cmd->target, cmd->lun);
+    if( !pDCB ) goto  NOT_RUN;
+
     /* Added 98/07/02 KG */
+    /*
     pSRB = pDCB->pActiveSRB;
     if (pSRB && pSRB->pcmd == cmd )
 	goto ON_GOING;
-	
+     */
+    
     pSRB = pDCB->pWaitingSRB;
     if( !pSRB )
 	goto  ON_GOING;
+
+    /* Now scan Waiting queue */
     if( pSRB->pcmd == cmd )
     {
 	pDCB->pWaitingSRB = pSRB->pNextSRB;
@@ -1364,16 +1612,21 @@
 	pSRB = psrb->pNextSRB;
 	psrb->pNextSRB = pSRB->pNextSRB;
 	if( pSRB == pDCB->pWaitLast )
-	    pDCB->pWaitLast = psrb; /* No check for psrb == NULL ? */
+	    pDCB->pWaitLast = psrb;
 IN_WAIT:
-	pSRB->pNextSRB = pACB->pFreeSRB;
-	pACB->pFreeSRB = pSRB;
+	dc390_Free_insert (pACB, pSRB);
+	pDCB->WaitSRBCnt--;
 	cmd->next = NULL;
 	status = SCSI_ABORT_SUCCESS;
 	goto  ABO_X;
     }
 
+    /* SRB has already been sent ! */
 ON_GOING:
+    /* abort() is too stupid for already sent commands at the moment. 
+     * If it's called we are in trouble anyway, so let's dump some info 
+     * into the syslog at least. (KG, 98/08/20,99/06/20) */
+    dc390_dumpinfo (pACB, pDCB, pSRB);
     pSRB = pDCB->pGoingSRB;
     pDCB->DCBFlag |= ABORT_DEV_;
     /* Now for the hard part: The command is currently processed */
@@ -1404,12 +1657,13 @@
 ABO_X:
     cmd->result = DID_ABORT << 16;
     printk(KERN_INFO "DC390: Aborted pid %li with status %i\n", cmd->pid, status);
+#if 0
     if (cmd->pid == dc390_lastabortedpid) /* repeated failure ? */
 	{
 		/* Let's do something to help the bus getting clean again */
 		DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
 		DC390_write8 (ScsiCmd, DMA_COMMAND);
-			//DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+		//DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
 		//DC390_write8 (ScsiCmd, RESET_ATN_CMD);
 		DC390_write8 (ScsiCmd, NOP_CMD);
 		//udelay (10000);
@@ -1434,10 +1688,13 @@
 	sbac = DC390_read32 (DMA_ScsiBusCtrl);
 	printk ("%08lx\n", sbac);
     };
+#endif
     dc390_lastabortedpid = cmd->pid;
     DC390_UNLOCK_ACB;
     //do_DC390_Interrupt (pACB->IRQLevel, 0, 0);
-    cmd->scsi_done(cmd);
+#ifndef USE_NEW_EH	
+    if (status == SCSI_ABORT_SUCCESS) cmd->scsi_done(cmd);
+#endif	
     return( status );
 }
 
@@ -1454,20 +1711,24 @@
 	pDCB->SyncMode &= ~SYNC_NEGO_DONE;
 	pDCB->SyncPeriod = 0;
 	pDCB->SyncOffset = 0;
+	pDCB->TagMask = 0;
 	pDCB->CtrlR3 = FAST_CLK;
 	pDCB->CtrlR4 &= NEGATE_REQACKDATA | CTRL4_RESERVED | NEGATE_REQACK;
 	pDCB->CtrlR4 |= pACB->glitch_cfg;
 	pDCB = pDCB->pNextDCB;
     }
     while( pdcb != pDCB );
-}
+    pACB->ACBFlag &= ~(RESET_DEV | RESET_DONE | RESET_DETECT);
 
+}
 
+#if 0
+/* Moves all SRBs from Going to Waiting for all DCBs */
 static void dc390_RecoverSRB( PACB pACB )
 {
     PDCB   pDCB, pdcb;
     PSRB   psrb, psrb2;
-    ULONG  cnt, i;
+    UINT   cnt, i;
 
     pDCB = pACB->pLinkDCB;
     if( !pDCB ) return;
@@ -1499,7 +1760,7 @@
 	pdcb = pdcb->pNextDCB;
     } while( pdcb != pDCB );
 }
-
+#endif
 
 /***********************************************************************
  * Function : int DC390_reset (Scsi_Cmnd *cmd, ...)
@@ -1507,34 +1768,37 @@
  * Purpose : perform a hard reset on the SCSI bus
  *
  * Inputs : cmd - command which caused the SCSI RESET
+ *	    resetFlags - how hard to try
  *
  * Returns : 0 on success.
  ***********************************************************************/
 
-int DC390_reset(Scsi_Cmnd *cmd, unsigned int resetFlags)
+int DC390_reset (Scsi_Cmnd *cmd, unsigned int resetFlags)
 {
     UCHAR   bval;
-    ULONG   i;
     DC390_AFLAGS
     PACB    pACB = (PACB) cmd->host->hostdata;
 
     printk(KERN_INFO "DC390: RESET ... ");
 
     DC390_LOCK_ACB;
+    if (timer_pending (&pACB->Waiting_Timer)) del_timer (&pACB->Waiting_Timer);
     bval = DC390_read8 (CtrlReg1);
     bval |= DIS_INT_ON_SCSI_RST;
-    DC390_write8 (CtrlReg1, bval);	/* disable interrupt */
+    DC390_write8 (CtrlReg1, bval);	/* disable IRQ on bus reset */
 
+    pACB->ACBFlag |= RESET_DEV;
     dc390_ResetSCSIBus( pACB );
-    /* Unlock ? */
-    for( i=0; i<600; i++ )
-	udelay(1000);
 
+    dc390_ResetDevParam( pACB );
+    udelay (1000);
+    pACB->pScsiHost->last_reset = jiffies + 3*HZ/2 
+		+ HZ * dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY];
+    
     DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
     DC390_read8 (INT_Status);		/* Reset Pending INT */
 
-    dc390_ResetDevParam( pACB );
-    dc390_DoingSRB_Done( pACB );
+    dc390_DoingSRB_Done( pACB, cmd );
     /* dc390_RecoverSRB (pACB); */
     pACB->pActiveDCB = NULL;
 
@@ -1543,10 +1807,10 @@
     bval &= ~DIS_INT_ON_SCSI_RST;
     DC390_write8 (CtrlReg1, bval);	/* re-enable interrupt */
 
-    dc390_DoWaitingSRB( pACB );
+    dc390_Waiting_process( pACB );
 
-    DC390_UNLOCK_ACB;
     printk("done\n");
+    DC390_UNLOCK_ACB;
     return( SCSI_RESET_SUCCESS );
 }
 
@@ -1556,22 +1820,22 @@
 /***********************************************************************
  * Function : static void dc390_initDCB()
  *
- * Purpose :  initialize the internal structures for a given DCB
+ * Purpose :  initialize the internal structures for a DCB (to be malloced)
  *
- * Inputs : cmd - pointer to this scsi cmd request block structure
+ * Inputs : SCSI id and lun
  ***********************************************************************/
 
-void dc390_initDCB( PACB pACB, PDCB *ppDCB, PSCSICMD cmd )
+void dc390_initDCB( PACB pACB, PDCB *ppDCB, UCHAR id, UCHAR lun )
 {
     PEEprom	prom;
     UCHAR	index;
-    PDCB pDCB;
+    PDCB pDCB, pDCB2;
 
     pDCB = kmalloc (sizeof(DC390_DCB), GFP_ATOMIC);
-    DCBDEBUG(printk (KERN_INFO "DC390: alloc mem for DCB (ID %i, LUN %i): 0x%08x\n",	\
-	    cmd->target, cmd->lun, (int)pDCB);)
+    DCBDEBUG(printk (KERN_INFO "DC390: alloc mem for DCB (ID %i, LUN %i): %p\n"	\
+	    id, lun, pDCB);)
  
-    *ppDCB = pDCB;
+    *ppDCB = pDCB; pDCB2 = 0;
     if (!pDCB) return;
     if( pACB->DCBCnt == 0 )
     {
@@ -1585,37 +1849,58 @@
    
     pACB->DCBCnt++;
    
-    pACB->pLastDCB = pDCB;
     pDCB->pNextDCB = pACB->pLinkDCB;
+    pACB->pLastDCB = pDCB;
 
     pDCB->pDCBACB = pACB;
-    pDCB->QIORBCnt = 0;
-    pDCB->UnitSCSIID = cmd->target;
-    pDCB->UnitSCSILUN = cmd->lun;
+    pDCB->TargetID = id;
+    pDCB->TargetLUN = lun;
     pDCB->pWaitingSRB = NULL;
     pDCB->pGoingSRB = NULL;
     pDCB->GoingSRBCnt = 0;
+    pDCB->WaitSRBCnt = 0;
     pDCB->pActiveSRB = NULL;
     pDCB->TagMask = 0;
     pDCB->MaxCommand = 1;
     index = pACB->AdapterIndex;
     pDCB->DCBFlag = 0;
 
-    prom = (PEEprom) &dc390_eepromBuf[index][cmd->target << 2];
-    pDCB->DevMode = prom->EE_MODE1;
+    /* Is there a corresp. LUN==0 device ? */
+    if (lun != 0)
+	pDCB2 = dc390_findDCB (pACB, id, 0);
+    prom = (PEEprom) &dc390_eepromBuf[index][id << 2];
+    /* Some values are for all LUNs: Copy them */
+    /* In a clean way: We would have an own structure for a SCSI-ID */
+    if (pDCB2)
+    {
+      pDCB->DevMode = pDCB2->DevMode;
+      pDCB->SyncMode = pDCB2->SyncMode;
+      pDCB->SyncPeriod = pDCB2->SyncPeriod;
+      pDCB->SyncOffset = pDCB2->SyncOffset;
+      pDCB->NegoPeriod = pDCB2->NegoPeriod;
+      
+      pDCB->CtrlR3 = pDCB2->CtrlR3;
+      pDCB->CtrlR4 = pDCB2->CtrlR4;
+      pDCB->Inquiry7 = pDCB2->Inquiry7;
+    }
+    else
+    {		
+      pDCB->DevMode = prom->EE_MODE1;
+      pDCB->SyncMode = 0;
+      pDCB->SyncPeriod = 0;
+      pDCB->SyncOffset = 0;
+      pDCB->NegoPeriod = (dc390_clock_period1[prom->EE_SPEED] * 25) >> 2;
+            
+      pDCB->CtrlR3 = FAST_CLK;
+      
+      pDCB->CtrlR4 = pACB->glitch_cfg | CTRL4_RESERVED;
+      if( dc390_eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION)
+	pDCB->CtrlR4 |= NEGATE_REQACKDATA | NEGATE_REQACK;
+      pDCB->Inquiry7 = 0;
+    }
 
-    pDCB->SyncMode = 0;
+    pACB->DCBmap[id] |= (1 << lun);
     dc390_updateDCB(pACB, pDCB);
-
-    pDCB->SyncPeriod = 0;
-    pDCB->SyncOffset = 0;
-    pDCB->NegoPeriod = (dc390_clock_period1[prom->EE_SPEED] * 25) >> 2;
-
-    pDCB->CtrlR3 = FAST_CLK;
-
-    pDCB->CtrlR4 = pACB->glitch_cfg | CTRL4_RESERVED;
-    if( dc390_eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION)
-	pDCB->CtrlR4 |= NEGATE_REQACKDATA | NEGATE_REQACK;
 }
 
 /***********************************************************************
@@ -1626,24 +1911,26 @@
 
 void dc390_updateDCB (PACB pACB, PDCB pDCB)
 {
-  pDCB->IdentifyMsg = IDENTIFY (pDCB->DevMode & EN_DISCONNECT_, pDCB->UnitSCSILUN);
-  
-  if (pDCB->DevMode & TAG_QUEUEING_) pDCB->SyncMode &= EN_TAG_QUEUEING | SYNC_NEGO_DONE | EN_ATN_STOP;
-  else pDCB->SyncMode &= SYNC_NEGO_DONE | EN_ATN_STOP;
-  
-  if( pDCB->DevMode & SYNC_NEGO_ && (!(pDCB->UnitSCSILUN) || dc390_CurrSyncOffset) )
-     pDCB->SyncMode |= SYNC_ENABLE;
-  else
-     {
+  pDCB->SyncMode &= EN_TAG_QUEUEING | SYNC_NEGO_DONE /*| EN_ATN_STOP*/;
+  if (pDCB->DevMode & TAG_QUEUEING_) {
+	//if (pDCB->SyncMode & EN_TAG_QUEUEING) pDCB->MaxCommand = pACB->TagMaxNum;
+  } else {
+	pDCB->SyncMode &= ~EN_TAG_QUEUEING;
+	pDCB->MaxCommand = 1;
+  };
+
+  if( pDCB->DevMode & SYNC_NEGO_ )
+	pDCB->SyncMode |= SYNC_ENABLE;
+  else {
 	pDCB->SyncMode &= ~(SYNC_NEGO_DONE | SYNC_ENABLE);
 	pDCB->SyncOffset &= ~0x0f;
-     };
-   
-  if (! (pDCB->DevMode & EN_DISCONNECT_)) pDCB->SyncMode &= ~EN_ATN_STOP; 
-  
+  };
+
+  //if (! (pDCB->DevMode & EN_DISCONNECT_)) pDCB->SyncMode &= ~EN_ATN_STOP; 
+
   pDCB->CtrlR1 = pACB->pScsiHost->this_id;
   if( pDCB->DevMode & PARITY_CHK_ )
-    pDCB->CtrlR1 |= PARITY_ERR_REPO;
+	pDCB->CtrlR1 |= PARITY_ERR_REPO;
 };  
 
 
@@ -1657,7 +1944,7 @@
 {
   int i;
   PDCB pDCB = pACB->pLinkDCB;
-  for (i = 0; i < pACB->DeviceCnt; i++)
+  for (i = 0; i < pACB->DCBCnt; i++)
     {
       dc390_updateDCB (pACB, pDCB);
       pDCB = pDCB->pNextDCB;
@@ -1681,12 +1968,12 @@
 
 void dc390_linkSRB( PACB pACB )
 {
-    ULONG   count, i;
+    UINT   count, i;
 
     count = pACB->SRBCount;
-    for( i=0; i< count; i++)
+    for( i=0; i<count; i++)
     {
-	if( i != count - 1)
+	if( i != count-1 )
 	    pACB->SRB_array[i].pNextSRB = &pACB->SRB_array[i+1];
 	else
 	    pACB->SRB_array[i].pNextSRB = NULL;
@@ -1716,7 +2003,15 @@
     psh->io_port = io_port;
     psh->n_io_port = 0x80;
     psh->irq = Irq;
-
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,50)
+    psh->base = io_port;
+#else
+    psh->base = (char*)io_port;
+#endif	
+    psh->unique_id = io_port;
+    psh->dma_channel = -1;
+    psh->last_reset = jiffies;
+	
     pACB = (PACB) psh->hostdata;
     DC390_LOCKA_INIT;
     DC390_LOCK_ACB;
@@ -1741,6 +2036,8 @@
     pACB->pActiveDCB = NULL;
     pACB->pFreeSRB = pACB->SRB_array;
     pACB->SRBCount = MAX_SRB_CNT;
+    pACB->QueryCnt = 0;
+    pACB->pQueryHead = NULL;
     pACB->AdapterIndex = index;
     pACB->status = 0;
     psh->this_id = dc390_eepromBuf[index][EE_ADAPT_SCSI_ID];
@@ -1759,7 +2056,9 @@
 	pACB->DCBmap[i] = 0;
     pACB->sel_timeout = SEL_TIMEOUT;
     pACB->glitch_cfg = EATER_25NS;
-    pACB->Cmds = pACB->CmdInQ = pACB->CmdOutOfSRB = pACB->SelLost = 0;
+    pACB->Cmds = pACB->CmdInQ = pACB->CmdOutOfSRB = 0;
+    pACB->SelLost = pACB->SelConn = 0;
+    init_timer (&pACB->Waiting_Timer);
 }
 
 
@@ -1777,22 +2076,11 @@
 int __init dc390_initAdapter (PSH psh, ULONG io_port, UCHAR Irq, UCHAR index)
 {
     PACB   pACB, pACB2;
-    UCHAR  used_irq = 0, dstate;
+    UCHAR  dstate;
     int    i;
     
     pACB = (PACB) psh->hostdata;
     
-    for ( pACB2 = dc390_pACB_start; pACB2 ; )
-      {
-	if( pACB2->IRQLevel == Irq )
-	  {
-	    used_irq = 1;
-	    break;
-	  }
-	else
-	  pACB2 = pACB2->pNextACB;
-      }
-
     if (check_region (io_port, psh->n_io_port))
 	{
 	    printk(KERN_ERR "DC390: register IO ports error!\n");
@@ -1803,14 +2091,12 @@
 
     DC390_read8_ (INT_Status, io_port);		/* Reset Pending INT */
 
-    if( !used_irq )
-    {
-	if( (i = request_irq(Irq, do_DC390_Interrupt, DC390_IRQ, "tmscsim", NULL) ))
-	    {
-		    printk(KERN_ERR "DC390: register IRQ error!\n");
-		    return( -1 );
-	    }
-    }
+    if( (i = request_irq(Irq, do_DC390_Interrupt, DC390_IRQ, "tmscsim", pACB) ))
+      {
+	printk(KERN_ERR "DC390: register IRQ error!\n");
+	release_region (io_port, psh->n_io_port);
+	return( -1 );
+      }
 
     if( !dc390_pACB_start )
       {
@@ -1832,9 +2118,13 @@
     if (pACB->Gmode2 & RST_SCSI_BUS)
     {
 	dc390_ResetSCSIBus( pACB );
-	/* Unlock before ? */
-	for( i=0; i<600; i++ )
+	udelay (1000);
+	pACB->pScsiHost->last_reset = jiffies + HZ/2
+		    + HZ * dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY];
+	/*
+	for( i=0; i<(500 + 1000*dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY]); i++ )
 		udelay(1000);
+	 */
     };
     pACB->ACBFlag = 0;
     DC390_read8 (INT_Status);				/* Reset Pending INT */
@@ -1846,6 +2136,7 @@
     DC390_write8 (CtrlReg3, FAST_CLK);			/* fast clock */
     DC390_write8 (CtrlReg4, pACB->glitch_cfg |			/* glitch eater */
 		(dc390_eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION) ? NEGATE_REQACKDATA : 0);	/* Negation */
+    DC390_write8 (CtcReg_High, 0);			/* Clear Transfer Count High: ID */
     DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
     DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
     DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT);
@@ -1885,18 +2176,24 @@
 	printk (KERN_ERR "DC390_init: No EEPROM found!\n");
 	return( -1 );
 #else
-	int period;
-	printk (KERN_INFO "DC390_init: No EEPROM found!\n");
-	printk (KERN_INFO "DC390_init: Trying default EEPROM settings:\n");
-	dc390_checkparams ();
-	period = dc390_clock_period1[tmscsim[1]];
+	int speed;
+	dc390_adapname = "AM53C974";
+	printk (KERN_INFO "DC390_init: No EEPROM found! Trying default settings ...\n");
+	dc390_check_for_safe_settings ();
+	dc390_fill_with_defaults ();
+	dc390_EEprom_Override (index);
+	speed = dc390_clock_speed[tmscsim[1]];
 	printk (KERN_INFO "DC390: Used defaults: AdaptID=%i, SpeedIdx=%i (%i.%i MHz),"
-		" DevMode=0x%02x, AdaptMode=0x%02x, TaggedCmnds=%i (%i)\n", tmscsim[0], tmscsim[1],
-		40 / period, ((40%period)*10 + period/2) / period,
-		(UCHAR)tmscsim[2], (UCHAR)tmscsim[3], tmscsim[4], 2 << (tmscsim[4]));
-	dc390_EEpromDefaults (index);
+		" DevMode=0x%02x, AdaptMode=0x%02x, TaggedCmnds=%i (%i), DelayReset=%is\n", 
+		tmscsim[0], tmscsim[1], speed/10, speed%10,
+		(UCHAR)tmscsim[2], (UCHAR)tmscsim[3], tmscsim[4], 2 << (tmscsim[4]), tmscsim[5]);
 #endif
-    };
+    }
+    else
+    {
+	dc390_check_for_safe_settings ();
+	dc390_EEprom_Override (index);
+    }
    
     psh = scsi_register( psht, sizeof(DC390_ACB) );
     if( !psh ) return( -1 );
@@ -2000,7 +2297,8 @@
     PDEVDECL0;
     UCHAR   irq;
     UINT    io_port;
-    DC390_IFLAGS DC390_DFLAGS
+    //DC390_IFLAGS
+    DC390_DFLAGS
 
     DC390_LOCK_DRV;
     //dc390_pSHT_start = psht;
@@ -2009,7 +2307,11 @@
     if ( PCI_PRESENT )
 	while (PCI_FIND_DEVICE (PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD53C974))
 	{
-	    DC390_LOCK_IO;		/* Remove this when going to new eh */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,30)
+	    if (pci_enable_device (pdev))
+		continue;
+#endif
+	    //DC390_LOCK_IO;		/* Remove this when going to new eh */
 	    PCI_GET_IO_AND_IRQ;
 	    DEBUG0(printk(KERN_INFO "DC390(%i): IO_PORT=%04x,IRQ=%x\n", dc390_adapterCnt, (UINT) io_port, irq);)
 
@@ -2019,14 +2321,17 @@
 		dc390_set_pci_cfg (PDEV);
 		dc390_adapterCnt++;
 	    };
-	    DC390_UNLOCK_IO;		/* Remove when going to new eh */
+	    //DC390_UNLOCK_IO;		/* Remove when going to new eh */
 	}
     else
 	printk (KERN_ERR "DC390: No PCI BIOS found!\n");
    
     if (dc390_adapterCnt)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,30)
+	psht->proc_name = "tmscsim";
+#else
 	psht->proc_dir = &DC390_proc_scsi_tmscsim;
-
+#endif
     printk(KERN_INFO "DC390: %i adapters found\n", dc390_adapterCnt);
     DC390_UNLOCK_DRV;
     return( dc390_adapterCnt );
@@ -2048,7 +2353,7 @@
    if (cmd->result)
    {
 	PACB pACB = (PACB)cmd->host->hostdata;
-	PDCB pDCB = dc390_findDCB (pACB, cmd);
+	PDCB pDCB = dc390_findDCB (pACB, cmd->target, cmd->lun);
 	printk ("DC390: Unsetting DsCn, Sync and TagQ!\n");
 	if (pDCB)
 	{
@@ -2056,7 +2361,6 @@
 		dc390_updateDCB (pACB, pDCB);
 	};
    };
-   kfree (cmd->buffer);
    kfree (cmd);
 };
 
@@ -2064,20 +2368,21 @@
 {
    char* buffer;
    Scsi_Cmnd* cmd;
-   buffer = kmalloc (256, GFP_ATOMIC);
-   cmd = kmalloc (sizeof (Scsi_Cmnd), GFP_ATOMIC);
+   cmd = kmalloc (sizeof(Scsi_Cmnd) + 256, GFP_ATOMIC);
+   if (!cmd) { printk ("DC390: kmalloc failed in inquiry!\n"); return; };
+   buffer = (char*)cmd + sizeof(Scsi_Cmnd);
 
-   memset (buffer, 0, 256);
-   memset (cmd, 0, sizeof(Scsi_Cmnd));
+   memset (cmd, 0, sizeof(Scsi_Cmnd) + 256);
    cmd->cmnd[0] = INQUIRY;
-   cmd->cmnd[1] = (pDCB->UnitSCSILUN << 5) & 0xe0;
+   cmd->cmnd[1] = (pDCB->TargetLUN << 5) & 0xe0;
    cmd->cmnd[4] = 0xff;
    
    cmd->cmd_len = 6; cmd->old_cmd_len = 6;
    cmd->host = pACB->pScsiHost;
-   cmd->target = pDCB->UnitSCSIID;
-   cmd->lun = pDCB->UnitSCSILUN; 
+   cmd->target = pDCB->TargetID;
+   cmd->lun = pDCB->TargetLUN; 
    cmd->serial_number = 1;
+   cmd->pid = 390;
    cmd->bufflen = 128;
    cmd->buffer = buffer;
    cmd->request_bufflen = 128;
@@ -2088,11 +2393,62 @@
 
    cmd->request.rq_status = RQ_SCSI_BUSY;
 
+   pDCB->SyncMode &= ~SYNC_NEGO_DONE;
    printk (KERN_INFO "DC390: Queue INQUIRY command to dev ID %02x LUN %02x\n",
-	   pDCB->UnitSCSIID, pDCB->UnitSCSILUN);
+	   pDCB->TargetID, pDCB->TargetLUN);
    DC390_queue_command (cmd, dc390_inquiry_done);
 };
 
+/***********************************************************************
+ * Functions: dc390_sendstart(), dc390_sendstart_done()
+ *
+ * Purpose: When changing speed etc., we have to issue an INQUIRY
+ *	    command to make sure, we agree upon the nego parameters
+ *	    with the device
+ ***********************************************************************/
+
+static void dc390_sendstart_done (Scsi_Cmnd* cmd)
+{
+   printk (KERN_INFO "DC390: SENDSTART (ID %02x LUN %02x) returned %08x\n",
+	   cmd->target, cmd->lun, cmd->result);
+   kfree (cmd);
+};
+
+void dc390_sendstart (PACB pACB, PDCB pDCB)
+{
+   char* buffer;
+   Scsi_Cmnd* cmd;
+   cmd = kmalloc (sizeof(Scsi_Cmnd) + 256, GFP_ATOMIC);
+   if (!cmd) { printk ("DC390: kmalloc failed in sendstart!\n"); return; };
+   buffer = (char*)cmd + sizeof(Scsi_Cmnd);
+
+   memset (cmd, 0, sizeof(Scsi_Cmnd) + 256);
+   cmd->cmnd[0] = 0x1b; /* START_STOP_UNIT */
+   cmd->cmnd[1] = (pDCB->TargetLUN << 5) & 0xe0;
+   cmd->cmnd[4] = 0x01; /* START */
+   
+   cmd->cmd_len = 6; cmd->old_cmd_len = 6;
+   cmd->host = pACB->pScsiHost;
+   cmd->target = pDCB->TargetID;
+   cmd->lun = pDCB->TargetLUN; 
+   cmd->serial_number = 1;
+   cmd->pid = 310;
+   cmd->bufflen = 128;
+   cmd->buffer = buffer;
+   cmd->request_bufflen = 128;
+   cmd->request_buffer = &buffer[128];
+   cmd->done = dc390_sendstart_done;
+   cmd->scsi_done = dc390_sendstart_done;
+   cmd->timeout_per_command = 5*HZ;
+
+   cmd->request.rq_status = RQ_SCSI_BUSY;
+
+   pDCB->SyncMode &= ~SYNC_NEGO_DONE;
+   printk (KERN_INFO "DC390: Queue SEND_START command to dev ID %02x LUN %02x\n",
+	   pDCB->TargetID, pDCB->TargetLUN);
+   DC390_queue_command (cmd, dc390_sendstart_done);
+};
+
 /********************************************************************
  * Function: dc390_set_info()
  *
@@ -2210,6 +2566,9 @@
   if (!memcmp (pos, "RESET", 5)) goto reset;
   else if (!memcmp (pos, "INQUIRY", 7)) goto inquiry;
   else if (!memcmp (pos, "REMOVE", 6)) goto remove;
+  else if (!memcmp (pos, "ADD", 3)) goto add;
+  else if (!memcmp (pos, "START", 5)) goto start;
+  else if (!memcmp (pos, "DUMP", 4)) goto dump;
   
   if (isdigit (*pos))
     {
@@ -2226,13 +2585,20 @@
       pDCB = pACB->pLinkDCB;
       for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB;
       /* Sanity Check */
-      if (pDCB->UnitSCSIID != id || pDCB->UnitSCSILUN != lun) 
+      if (pDCB->TargetID != id || pDCB->TargetLUN != lun) 
 	 {
 	    printk (KERN_ERR "DC390: no such device: Idx=%02i ID=%02i LUN=%02i\n",
 		    dev, id, lun);
 	    goto einv2;
 	 };
 
+      if (pDCB->pWaitingSRB || pDCB->pGoingSRB)
+      {
+	  printk ("DC390: Cannot change dev (%i-%i) cfg: Pending requests\n",
+		  pDCB->TargetID, pDCB->TargetLUN);
+	  goto einv;
+      };
+	  
       olddevmode = pDCB->DevMode;
       YESNO (pos, pDCB->DevMode, PARITY_CHK_);
       needs_inquiry++;
@@ -2245,8 +2611,7 @@
       needs_inquiry++;
       YESNO (pos, pDCB->DevMode, TAG_QUEUEING_);
       if ((olddevmode & TAG_QUEUEING_) == (pDCB->DevMode & TAG_QUEUEING_)) needs_inquiry--;
-      YESNO (pos, pDCB->SyncMode, EN_ATN_STOP);
-      
+
       dc390_updateDCB (pACB, pDCB);
       if (!pos) goto ok;
        
@@ -2266,7 +2631,7 @@
       else pos = strtok (0, " \t\n:=,;.");
       if (!pos) goto ok;
       
-      /* Speed: NegoPeriod */
+      /* Sync Speed in MHz */
       if (*pos != '-')
 	{
 	  SCANF (pos, p0, dum, 1, 13); 
@@ -2281,11 +2646,11 @@
 		for (; p0-pos > 1; p0--) dum /= 10;
 		pDCB->NegoPeriod = (100000/(100*dumold + dum)) >> 2;
 		if (pDCB->NegoPeriod < 19) pDCB->NegoPeriod = 19;
-		if (pDCB->NegoPeriod != olddevmode) needs_inquiry++;
 		pos = strtok (0, " \t\n:=,;");
 		if (!pos) goto ok;
 	     };
 	  if (*pos == 'M') pos = strtok (0, " \t\n:=,;");
+	  if (pDCB->NegoPeriod != olddevmode) needs_inquiry++;
 	}
       else pos = strtok (0, " \t\n:=,;");
       /* dc390_updateDCB (pACB, pDCB); */
@@ -2300,28 +2665,49 @@
 	  if (pDCB->SyncOffset > olddevmode) needs_inquiry++;
 	}
       else pos = strtok (0, " \t\n:=,;");
+      if (!pos) goto ok;
       dc390_updateDCB (pACB, pDCB);
+
+      //olddevmode = pDCB->MaxCommand;
+      /* MaxCommand (Tags) */
+      if (*pos != '-')
+	{
+	  SCANF (pos, p0, dum, 1, 32 /*pACB->TagMaxNum*/);
+	  if (pDCB->SyncMode & EN_TAG_QUEUEING)
+		pDCB->MaxCommand = dum;
+	  else printk (KERN_INFO "DC390: Can't set MaxCmd larger than one without Tag Queueing!\n");
+	}
+      else pos = strtok (0, " \t\n:=,;");
+
     }
   else
     {
-      char* p1 = pos; UCHAR dum;
+      char* p1 = pos; UCHAR dum, newadaptid;
       PARSEDEBUG(printk (KERN_INFO "DC390: chg adapt cfg \"%s\"\n", prstr (pos, &buffer[length]));)
       dum = GLITCH_TO_NS (pACB->glitch_cfg);
       /* Adapter setting */
       SEARCH (pos, p0, pACB->pScsiHost->max_id, "MAXID", 8); 
       SEARCH (pos, p0, pACB->pScsiHost->max_lun, "MAXLUN", 8); 
-      SEARCH (pos, p0, pACB->pScsiHost->this_id, "ADAPTERID", 7); 
+      SEARCH (pos, p0, newadaptid, "ADAPTERID", 7);
       SEARCH (pos, p0, pACB->TagMaxNum, "TAGMAXNUM", 32);
       SEARCH (pos, p0, pACB->ACBFlag, "ACBFLAG", 255);
       SEARCH3 (pos, p0, dum, "GLITCHEATER", 40, 1000, "NS");
       SEARCH3 (pos, p0, pACB->sel_timeout, "SELTIMEOUT", 400, 163, "MS");
+      SEARCH3 (pos, p0, dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY], "DELAYRESET", 180, 100, "S");
     ok2:
       pACB->glitch_cfg = NS_TO_GLITCH (dum);
       if (pACB->sel_timeout < 60) pACB->sel_timeout = 60;
-      dum = 0; while (1 << dum <= pACB->TagMaxNum) dum ++;
-      pACB->TagMaxNum &= (1 << --dum);
-      if (pos == p1) goto einv;
+      DC390_write8 (Scsi_TimeOut, pACB->sel_timeout);
+      if (newadaptid != pACB->pScsiHost->this_id)
+      {
+	pACB->pScsiHost->this_id = newadaptid;
+	dc390_ResetDevParam (pACB);
+      }	    
+      //dum = 0; while (1 << dum <= pACB->TagMaxNum) dum ++;
+      //pACB->TagMaxNum &= (1 << --dum);
       dc390_updateDCBs (pACB);
+      // All devs should be INQUIRED now
+      if (pos == p1) goto einv;
     }
   if (pos) goto next;
       
@@ -2351,7 +2737,15 @@
 	DC390_UNLOCK_IO;
      };
   return (length);
-  
+
+ dump:
+     {
+	dc390_dumpinfo (pACB, 0, 0);
+	DC390_UNLOCK_ACB;
+	DC390_UNLOCK_IO;       
+     }
+  return (length);
+	
  inquiry:
      {
 	pos = strtok (0, " \t\n.:;="); if (!pos) goto einv;
@@ -2359,7 +2753,7 @@
 	if (dev >= pACB->DCBCnt) goto einv_dev;
 	for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB;
 	printk (KERN_NOTICE " DC390: Issue INQUIRY command to Dev(Idx) %i SCSI ID %i LUN %i\n",
-		dev, pDCB->UnitSCSIID, pDCB->UnitSCSILUN);
+		dev, pDCB->TargetID, pDCB->TargetLUN);
 	DC390_UNLOCK_ACB;
 	dc390_inquiry (pACB, pDCB);
 	DC390_UNLOCK_IO;
@@ -2373,13 +2767,45 @@
 	if (dev >= pACB->DCBCnt) goto einv_dev;
 	for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB;
 	printk (KERN_NOTICE " DC390: Remove DCB for Dev(Idx) %i SCSI ID %i LUN %i\n",
-		dev, pDCB->UnitSCSIID, pDCB->UnitSCSILUN);
+		dev, pDCB->TargetID, pDCB->TargetLUN);
+	/* TO DO: We should make sure no pending commands are left */
 	dc390_remove_dev (pACB, pDCB);
 	DC390_UNLOCK_ACB;
 	DC390_UNLOCK_IO;
      };
    return (length);
 
+ add:
+     {
+	int id, lun;
+	pos = strtok (0, " \t\n.:;=");
+	if (pos) { SCANF (pos, p0, id, 0, 7); } else goto einv;
+	if (pos) { SCANF (pos, p0, lun, 0, 7); } else goto einv;
+	pDCB = dc390_findDCB (pACB, id, lun);
+	if (pDCB) { printk ("DC390: ADD: Device already existing\n"); goto einv; };
+	dc390_initDCB (pACB, &pDCB, id, lun);
+	DC390_UNLOCK_ACB;
+	dc390_inquiry (pACB, pDCB);
+	DC390_UNLOCK_IO;
+     };
+   return (length);
+
+ start:
+     {
+	int id, lun;
+	pos = strtok (0, " \t\n.:;=");
+	if (pos) { SCANF (pos, p0, id, 0, 7); } else goto einv;
+	if (pos) { SCANF (pos, p0, lun, 0, 7); } else goto einv;
+	pDCB = dc390_findDCB (pACB, id, lun);
+	if (pDCB) printk ("DC390: SendStart: Device already existing ...\n");
+	else dc390_initDCB (pACB, &pDCB, id, lun);
+	DC390_UNLOCK_ACB;
+	dc390_sendstart (pACB, pDCB);
+	dc390_inquiry (pACB, pDCB);
+	DC390_UNLOCK_IO;
+     };
+   return (length);
+
  einv_dev:
    printk (KERN_WARNING "DC390: Ignore cmnd to illegal Dev(Idx) %i. Valid range: 0 - %i.\n", 
 	   dev, pACB->DCBCnt - 1);
@@ -2429,6 +2855,7 @@
   PSH shpnt;
   PACB pACB;
   PDCB pDCB;
+  PSCSICMD pcmd;
   DC390_AFLAGS
 
   pACB = dc390_pACB_start;
@@ -2454,46 +2881,87 @@
   SPRINTF("SCSI Host Nr %i, ", shpnt->host_no);
   SPRINTF("%s Adapter Nr %i\n", dc390_adapname, pACB->AdapterIndex);
   SPRINTF("IOPortBase 0x%04x, ", pACB->IOPortBase);
-  SPRINTF("IRQLevel 0x%02x\n", pACB->IRQLevel);
+  SPRINTF("IRQ %02i\n", pACB->IRQLevel);
 
   SPRINTF("MaxID %i, MaxLUN %i, ", shpnt->max_id, shpnt->max_lun);
-  SPRINTF("AdapterID %i, SelTimeout %i ms\n", 
-	  shpnt->this_id, (pACB->sel_timeout*164)/100);
+  SPRINTF("AdapterID %i, SelTimeout %i ms, DelayReset %i s\n", 
+	  shpnt->this_id, (pACB->sel_timeout*164)/100,
+	  dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY]);
 
-  SPRINTF("TagMaxNum %i, Status %i, ACBFlag %i, GlitchEater %i ns\n",
+  SPRINTF("TagMaxNum %i, Status 0x%02x, ACBFlag 0x%02x, GlitchEater %i ns\n",
 	  pACB->TagMaxNum, pACB->status, pACB->ACBFlag, GLITCH_TO_NS(pACB->glitch_cfg)*12);
 
-  SPRINTF("Statistics: Cmnds %li, Cmnds not sent directly %li, Out of SRB conds %li\n",
+  SPRINTF("Statistics: Cmnds %li, Cmnds not sent directly %i, Out of SRB conds %i\n",
 	  pACB->Cmds, pACB->CmdInQ, pACB->CmdOutOfSRB);
-  SPRINTF("            Lost arbitrations %li\n", pACB->SelLost);
+  SPRINTF("            Lost arbitrations %i, Sel. connected %i, Connected: %s\n", 
+	  pACB->SelLost, pACB->SelConn, pACB->Connected? "Yes": "No");
    
   SPRINTF("Nr of attached devices: %i, Nr of DCBs: %i\n", pACB->DeviceCnt, pACB->DCBCnt);
+  SPRINTF("Map of attached LUNs: %02x %02x %02x %02x %02x %02x %02x %02x\n",
+	  pACB->DCBmap[0], pACB->DCBmap[1], pACB->DCBmap[2], pACB->DCBmap[3], 
+	  pACB->DCBmap[4], pACB->DCBmap[5], pACB->DCBmap[6], pACB->DCBmap[7]);
 
-  SPRINTF("Idx ID LUN Prty Sync DsCn SndS TagQ STOP NegoPeriod SyncSpeed SyncOffs\n");
+  SPRINTF("Idx ID LUN Prty Sync DsCn SndS TagQ NegoPeriod SyncSpeed SyncOffs MaxCmd\n");
 
   pDCB = pACB->pLinkDCB;
   for (dev = 0; dev < pACB->DCBCnt; dev++)
      {
-      SPRINTF("%02i  %02i  %02i ", dev, pDCB->UnitSCSIID, pDCB->UnitSCSILUN);
+      SPRINTF("%02i  %02i  %02i ", dev, pDCB->TargetID, pDCB->TargetLUN);
       YESNO(pDCB->DevMode & PARITY_CHK_);
       YESNO(pDCB->SyncMode & SYNC_NEGO_DONE);
       YESNO(pDCB->DevMode & EN_DISCONNECT_);
-      //YESNO(pDCB->SyncMode & EN_ATN_STOP);
       YESNO(pDCB->DevMode & SEND_START_);
       YESNO(pDCB->SyncMode & EN_TAG_QUEUEING);
-      YESNO(pDCB->SyncMode & EN_ATN_STOP);
       if (pDCB->SyncOffset & 0x0f)
       {
 	 int sp = pDCB->SyncPeriod; if (! (pDCB->CtrlR3 & FAST_SCSI)) sp++;
 	 SPRINTF("  %03i ns ", (pDCB->NegoPeriod) << 2);
 	 spd = 40/(sp); spd1 = 40%(sp);
 	 spd1 = (spd1 * 10 + sp/2) / (sp);
-	 SPRINTF("   %2i.%1i M      %02i\n", spd, spd1, (pDCB->SyncOffset & 0x0f));
+	 SPRINTF("   %2i.%1i M      %02i", spd, spd1, (pDCB->SyncOffset & 0x0f));
       }
-      else SPRINTF(" (%03i ns)\n", (pDCB->NegoPeriod) << 2);
+      else SPRINTF(" (%03i ns)                 ", (pDCB->NegoPeriod) << 2);
       /* Add more info ...*/
+      SPRINTF ("      %02i\n", pDCB->MaxCommand);
       pDCB = pDCB->pNextDCB;
      }
+    SPRINTF ("Commands in Queues: Query: %li:", pACB->QueryCnt);
+    for (pcmd = pACB->pQueryHead; pcmd; pcmd = pcmd->next)
+	SPRINTF (" %li", pcmd->pid);
+    if (timer_pending(&pACB->Waiting_Timer)) SPRINTF ("Waiting queue timer running\n");
+    else SPRINTF ("\n");
+    pDCB = pACB->pLinkDCB;
+	
+    for (dev = 0; dev < pACB->DCBCnt; dev++)
+    {
+	PSRB pSRB;
+	if (pDCB->WaitSRBCnt) 
+		    SPRINTF ("DCB (%02i-%i): Waiting: %i:", pDCB->TargetID, pDCB->TargetLUN,
+			     pDCB->WaitSRBCnt);
+	for (pSRB = pDCB->pWaitingSRB; pSRB; pSRB = pSRB->pNextSRB)
+		SPRINTF(" %li", pSRB->pcmd->pid);
+	if (pDCB->GoingSRBCnt) 
+		    SPRINTF ("\nDCB (%02i-%i): Going  : %i:", pDCB->TargetID, pDCB->TargetLUN,
+			     pDCB->GoingSRBCnt);
+	for (pSRB = pDCB->pGoingSRB; pSRB; pSRB = pSRB->pNextSRB)
+#if 0 //def DC390_DEBUGTRACE
+		SPRINTF(" %s\n  ", pSRB->debugtrace);
+#else
+		SPRINTF(" %li", pSRB->pcmd->pid);
+#endif
+	if (pDCB->WaitSRBCnt || pDCB->GoingSRBCnt) SPRINTF ("\n");
+	pDCB = pDCB->pNextDCB;
+    }
+	
+#ifdef DC390_DEBUGDCB
+    SPRINTF ("DCB list for ACB %p:\n", pACB);
+    pDCB = pACB->pLinkDCB;
+    SPRINTF ("%p", pDCB);
+    for (dev = 0; dev < pACB->DCBCnt; dev++, pDCB=pDCB->pNextDCB)
+	SPRINTF ("->%p", pDCB->pNextDCB);
+    SPRINTF("\n");
+#endif
+  
 
   DC390_UNLOCK_ACB;
   *start = buffer + offset;
@@ -2528,13 +2996,14 @@
 
     printk(KERN_INFO "DC390: shutdown\n");
 
-    pACB->ACBFlag = RESET_DONE;
+    pACB->ACBFlag = RESET_DEV;
     bval = DC390_read8 (CtrlReg1);
     bval |= DIS_INT_ON_SCSI_RST;
     DC390_write8 (CtrlReg1, bval);	/* disable interrupt */
     if (pACB->Gmode2 & RST_SCSI_BUS)
 		dc390_ResetSCSIBus (pACB);
 
+    if (timer_pending (&pACB->Waiting_Timer)) del_timer (&pACB->Waiting_Timer);
     return( 0 );
 }
 
@@ -2548,41 +3017,30 @@
     do
     {
 	nDCB = pDCB->pNextDCB;
-	DCBDEBUG(printk (KERN_INFO "DC390: Free DCB (ID %i, LUN %i): 0x%08x\n",\
-		pDCB->UnitSCSIID, pDCB->UnitSCSILUN, (int)pDCB);)
-	kfree (pDCB);
+	DCBDEBUG(printk (KERN_INFO "DC390: Free DCB (ID %i, LUN %i): %p\n",\
+		pDCB->TargetID, pDCB->TargetLUN, pDCB);)
+	//kfree (pDCB);
+	dc390_remove_dev (pACB, pDCB);
 	pDCB = nDCB;
-    } while (pDCB && pDCB != pACB->pLinkDCB);
+    } while (pDCB && pACB->pLinkDCB);
 
 };
 
-int DC390_release(struct Scsi_Host *host)
+int DC390_release (struct Scsi_Host *host)
 {
-    int irq_count; 
-    PACB pACB;
     DC390_AFLAGS DC390_IFLAGS
-#if USE_SPINLOCKS > 1
     PACB pACB = (PACB)(host->hostdata);
-#endif
 
     DC390_LOCK_IO;
     DC390_LOCK_ACB;
 
+    /* TO DO: We should check for outstanding commands first. */
     dc390_shutdown (host);
 
     if (host->irq != IRQ_NONE)
     {
-	for (irq_count = 0, pACB = dc390_pACB_start; 
-	     pACB; pACB = pACB->pNextACB)
-	{
-	    if ( pACB->IRQLevel == host->irq )
-		++irq_count;
-	}
-	if (irq_count == 1)
-	 {
-	    DEBUG0(printk(KERN_INFO "DC390: Free IRQ %i\n",host->irq);)
-	    free_irq(host->irq,NULL);
-	 }
+	DEBUG0(printk(KERN_INFO "DC390: Free IRQ %i\n",host->irq);)
+	free_irq (host->irq, pACB);
     }
 
     release_region(host->io_port,host->n_io_port);
@@ -2591,7 +3049,12 @@
     DC390_UNLOCK_IO;
     return( 1 );
 }
+#endif /* def MODULE */
 
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,99)
+static Scsi_Host_Template driver_template = DC390_T;
+#include "scsi_module.c"
+#elif defined(MODULE)
 Scsi_Host_Template driver_template = DC390_T;
 #include "scsi_module.c"
-#endif /* def MODULE */
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/tmscsim.h linux.19p18/drivers/scsi/tmscsim.h
--- linux.vanilla/drivers/scsi/tmscsim.h	Fri Apr 21 23:21:08 2000
+++ linux.19p18/drivers/scsi/tmscsim.h	Sat Dec 30 19:46:47 2000
@@ -3,33 +3,47 @@
 ;*		    TEKRAM DC-390(T) PCI SCSI Bus Master Host Adapter  *
 ;*		    Device Driver				       *
 ;***********************************************************************/
-/* $Id: tmscsim.h,v 2.4 1998/12/25 17:33:27 garloff Exp $ */
+/* $Id: tmscsim.h,v 2.15.2.3 2000/11/17 20:52:27 garloff Exp $ */
 
 #ifndef _TMSCSIM_H
 #define _TMSCSIM_H
 
+#include <linux/types.h>
+#include <linux/config.h>
+/* 2.0 compat */
+#if defined(__SMP__) && !defined(CONFIG_SMP)
+# if LINUX_VERSION_CODE < KERNEL_VERSION (2,2,0)
+#  define CONFIG_SMP
+# else
+#  error __SMP__ defined but not CONFIG_SMP
+# endif
+#endif
+
+
 #define IRQ_NONE 255
 
 #define MAX_ADAPTER_NUM 	4
-#define MAX_SG_LIST_BUF 	16
-#define MAX_CMD_PER_LUN 	8
-#define MAX_CMD_QUEUE		2*MAX_CMD_PER_LUN+1	
+#define MAX_SG_LIST_BUF 	16	/* Not used */
+#define MAX_CMD_PER_LUN 	32
+#define MAX_CMD_QUEUE		MAX_CMD_PER_LUN+MAX_CMD_PER_LUN/2+1	
 #define MAX_SCSI_ID		8
 #define MAX_SRB_CNT		MAX_CMD_QUEUE+1	/* Max number of started commands */
-#define END_SCAN		2
 
 #define SEL_TIMEOUT		153	/* 250 ms selection timeout (@ 40 MHz) */
 
-typedef unsigned char	UCHAR;
-typedef unsigned short	USHORT;
-typedef unsigned long	ULONG;
-typedef unsigned int	UINT;
+#define END_SCAN		2
+
+typedef u8		UCHAR;	/*  8 bits */
+typedef u16		USHORT;	/* 16 bits */
+typedef u32		UINT;	/* 32 bits */
+typedef unsigned long	ULONG;	/* 32/64 bits */
 
 typedef UCHAR		*PUCHAR;
 typedef USHORT		*PUSHORT;
+typedef UINT		*PUINT;
 typedef ULONG		*PULONG;
-typedef Scsi_Host_Template  *PSHT;
-typedef struct Scsi_Host    *PSH;
+typedef Scsi_Host_Template	*PSHT;
+typedef struct Scsi_Host	*PSH;
 typedef Scsi_Device	*PSCSIDEV;
 typedef Scsi_Cmnd	*PSCSICMD;
 typedef void		*PVOID;
@@ -72,48 +86,49 @@
 */
 struct	_SRB
 {
-UCHAR		CmdBlock[12];
+//UCHAR		CmdBlock[12];
 
 struct _SRB	*pNextSRB;
 struct _DCB	*pSRBDCB;
 PSCSICMD	pcmd;
 PSGL		pSegmentList;
 
-ULONG		Segment0[2];
-ULONG		Segment1[2];
+/* 0x10: */
+SGL		Segmentx;	/* make a one entry of S/G list table */
 
-/* 0x2c:*/
-ULONG		TotalXferredLen;
+/* 0x1c: */
 ULONG		SGBusAddr;	/*;a segment starting address as seen by AM53C974A*/
 ULONG		SGToBeXferLen;	/*; to be xfer length */
-ULONG		SRBState;
-
-/* 0x3c: */
-UCHAR		MsgInBuf[6];
-UCHAR		MsgOutBuf[6];
-
-/* 0x48: */
-SGL		Segmentx;	/* make a one entry of S/G list table */
-
-UCHAR		ScsiCmdLen;
-UCHAR		ScsiPhase;
+ULONG		TotalXferredLen;
+ULONG		SavedTotXLen;
+UINT		SRBState;
 
+/* 0x30: */
+UCHAR		SRBStatus;
+UCHAR		SRBFlag;	/*; b0-AutoReqSense,b6-Read,b7-write */
+				/*; b4-settimeout,b5-Residual valid */
 UCHAR		AdaptStatus;
 UCHAR		TargetStatus;
 
-/* 0x58: */
+UCHAR		ScsiPhase;
+UCHAR		TagNumber;
+UCHAR		SGIndex;
+UCHAR		SGcount;
+
+/* 0x38: */
 UCHAR		MsgCnt;
 UCHAR		EndMessage;
 UCHAR		RetryCnt;
-UCHAR		SRBFlag;	/*; b0-AutoReqSense,b6-Read,b7-write */
-				/*; b4-settimeout,b5-Residual valid */
-UCHAR		TagNumber;
-UCHAR		SGcount;
-UCHAR		SGIndex;
-UCHAR		SRBStatus;
-  //UCHAR		IORBFlag;	/*;81h-Reset, 2-retry */
+UCHAR		SavedSGCount;			
+
+ULONG		Saved_Ptr;
+
+/* 0x40: */
+UCHAR		MsgInBuf[6];
+UCHAR		MsgOutBuf[6];
 
-/* 0x60: */
+//UCHAR		IORBFlag;	/*;81h-Reset, 2-retry */
+/* 0x4c: */
 };
 
 
@@ -129,48 +144,47 @@
 struct _DCB	*pNextDCB;
 struct _ACB	*pDCBACB;
 
-PSCSICMD	pQIORBhead;
-PSCSICMD	pQIORBtail;
-PSCSICMD	AboIORBhead;
-PSCSICMD	AboIORBtail;
-ULONG		QIORBCnt;
-ULONG		AboIORBcnt;
+/* Aborted Commands */
+//PSCSICMD	AboIORBhead;
+//PSCSICMD	AboIORBtail;
+//ULONG		AboIORBcnt;
 
-/* 0x20: */
+/* 0x08: */
+/* Queued SRBs */
 PSRB		pWaitingSRB;
 PSRB		pWaitLast;
 PSRB		pGoingSRB;
 PSRB		pGoingLast;
 PSRB		pActiveSRB;
+UCHAR		WaitSRBCnt;	/* Not used */
 UCHAR		GoingSRBCnt;
-UCHAR		WaitSRBCnt;	/* ??? */
+
 UCHAR		DevType;
 UCHAR		MaxCommand;
 
-/* 0x38: */
-ULONG		TagMask;
+/* 0x20: */
+UINT		TagMask;
 
-UCHAR		UnitSCSIID;	/*; SCSI Target ID  (SCSI Only) */
-UCHAR		UnitSCSILUN;	/*; SCSI Log.  Unit (SCSI Only) */
+UCHAR		TargetID;	/*; SCSI Target ID  (SCSI Only) */
+UCHAR		TargetLUN;	/*; SCSI Log.  Unit (SCSI Only) */
 UCHAR		DevMode;
-UCHAR		IdentifyMsg;
+UCHAR		DCBFlag;
 
 UCHAR		CtrlR1;
 UCHAR		CtrlR3;
 UCHAR		CtrlR4;
+UCHAR		Inquiry7;
 
-UCHAR		DCBFlag;
-
-/* 0x44: */
+/* 0x2c: */
 UCHAR		SyncMode;	/*; 0:async mode */
 UCHAR		NegoPeriod;	/*;for nego. */
 UCHAR		SyncPeriod;	/*;for reg. */
 UCHAR		SyncOffset;	/*;for reg. and nego.(low nibble) */
 
-/* 0x48:*/
+/* 0x30:*/
 //UCHAR		InqDataBuf[8];
 //UCHAR		CapacityBuf[8];
-/* 0x58: */
+///* 0x40: */
 };
 
 typedef  struct  _DCB	 DC390_DCB, *PDCB;
@@ -201,16 +215,24 @@
 PDCB		pLinkDCB;
 PDCB		pLastDCB;
 PDCB		pDCBRunRobin;
+
 PDCB		pActiveDCB;
 PSRB		pFreeSRB;
 PSRB		pTmpSRB;
 
 /* 0x2c: */
+ULONG		QueryCnt;
+PSCSICMD	pQueryHead;
+PSCSICMD	pQueryTail;
 
+/* 0x38: */
 UCHAR		msgin123[4];
 UCHAR		DCBmap[MAX_SCSI_ID];
+UCHAR		Connected;
+UCHAR		pad;
 
-#if defined(USE_SPINLOCKS) && USE_SPINLOCKS > 1 && (defined(__SMP__) || DEBUG_SPINLOCKS > 0)
+/* 0x3c: */
+#if defined(USE_SPINLOCKS) && USE_SPINLOCKS > 1 && (defined(CONFIG_SMP) || DEBUG_SPINLOCKS > 0)
 spinlock_t	lock;
 #endif
 UCHAR		sel_timeout;
@@ -220,18 +242,20 @@
 UCHAR		Ignore_IRQ;	/* Not used */
 
 PDEVDECL1;			/* Pointer to PCI cfg. space */
-/* 0x40/0x3c: */
+/* 0x4c/0x48: */
 ULONG		Cmds;
-ULONG		CmdInQ;
-ULONG		CmdOutOfSRB;
-ULONG		SelLost;
-
+UINT		SelLost;
+UINT		SelConn;
+UINT		CmdInQ;
+UINT		CmdOutOfSRB;
 	
-/* 0x50/0x4c: */	
+/* 0x60/0x5c: */
+struct timer_list	Waiting_Timer;
+/* 0x74/0x70: */
 DC390_SRB	TmpSRB;
-/* 0xb4/0xb0: */
-DC390_SRB	SRB_array[MAX_SRB_CNT]; 	/* 18 SRBs */
-/* 0x7bc/0x7b8: */
+/* 0xd8/0xd4: */
+DC390_SRB	SRB_array[MAX_SRB_CNT]; 	/* 50 SRBs */
+/* 0xfb0/0xfac: */
 };
 
 typedef  struct  _ACB	 DC390_ACB, *PACB;
@@ -339,21 +363,29 @@
 #define H_BAD_CCB_OR_SG  0x1A
 #define H_ABORT 	 0x0FF
 
-/*; SCSI Status byte codes*/ /* Twice the values defined in scsi/scsi.h */
-#define SCSI_STAT_GOOD		0x0	/*;  Good status */
-#define SCSI_STAT_CHECKCOND	0x02	/*;  SCSI Check Condition */
-#define SCSI_STAT_CONDMET	0x04	/*;  Condition Met */
-#define SCSI_STAT_BUSY		0x08	/*;  Target busy status */
-#define SCSI_STAT_INTER 	0x10	/*;  Intermediate status */
-#define SCSI_STAT_INTERCONDMET	0x14	/*;  Intermediate condition met */
-#define SCSI_STAT_RESCONFLICT	0x18	/*;  Reservation conflict */
-#define SCSI_STAT_CMDTERM	0x22	/*;  Command Terminated */
-#define SCSI_STAT_QUEUEFULL	0x28	/*;  Queue Full */
+/*; SCSI Status byte codes*/ 
+/* The values defined in include/scsi/scsi.h, to be shifted << 1 */
 
 #define SCSI_STAT_UNEXP_BUS_F	0xFD	/*;  Unexpect Bus Free */
 #define SCSI_STAT_BUS_RST_DETECT 0xFE	/*;  Scsi Bus Reset detected */
 #define SCSI_STAT_SEL_TIMEOUT	0xFF	/*;  Selection Time out */
 
+/* cmd->result */
+#define RES_TARGET		0x000000FF	/* Target State */
+#define RES_TARGET_LNX		STATUS_MASK	/* Only official ... */
+#define RES_ENDMSG		0x0000FF00	/* End Message */
+#define RES_DID			0x00FF0000	/* DID_ codes */
+#define RES_DRV			0xFF000000	/* DRIVER_ codes */
+
+#define MK_RES(drv,did,msg,tgt) ((int)(drv)<<24 | (int)(did)<<16 | (int)(msg)<<8 | (int)(tgt))
+#define MK_RES_LNX(drv,did,msg,tgt) ((int)(drv)<<24 | (int)(did)<<16 | (int)(msg)<<8 | (int)(tgt)<<1)
+
+#define SET_RES_TARGET(who,tgt) { who &= ~RES_TARGET; who |= (int)(tgt); }
+#define SET_RES_TARGET_LNX(who,tgt) { who &= ~RES_TARGET_LNX; who |= (int)(tgt) << 1; }
+#define SET_RES_MSG(who,msg) { who &= ~RES_ENDMSG; who |= (int)(msg) << 8; }
+#define SET_RES_DID(who,did) { who &= ~RES_DID; who |= (int)(did) << 16; }
+#define SET_RES_DRV(who,drv) { who &= ~RES_DRV; who |= (int)(drv) << 24; }
+
 /*;---Sync_Mode */
 #define SYNC_DISABLE	0
 #define SYNC_ENABLE	BIT0
@@ -375,31 +407,8 @@
 #define SCSI_MSG_OUT	6
 #define SCSI_MSG_IN	7
 
-/*;----SCSI MSG BYTE*/ /* see scsi/scsi.h */
-#define MSG_COMPLETE		0x00
-#define MSG_EXTENDED		0x01
-#define MSG_SAVE_PTR		0x02
-#define MSG_RESTORE_PTR 	0x03
-#define MSG_DISCONNECT		0x04
-#define MSG_INITIATOR_ERROR	0x05
-#define MSG_ABORT		0x06
-#define MSG_REJECT_		0x07
-#define MSG_NOP 		0x08
-#define MSG_PARITY_ERROR	0x09
-#define MSG_LINK_CMD_COMPL	0x0A
-#define MSG_LINK_CMD_COMPL_FLG	0x0B
-#define MSG_BUS_RESET		0x0C
-#define MSG_ABORT_TAG		0x0D
-#define MSG_SIMPLE_QTAG 	0x20
-#define MSG_HEAD_QTAG		0x21
-#define MSG_ORDER_QTAG		0x22
-#define MSG_IDENTIFY		0x80
-#define MSG_HOST_ID		0x0C0
-
-/* cmd->result */
-#define STATUS_MASK_		0xFF
-#define MSG_MASK		0xFF00
-#define RETURN_MASK		0xFF0000
+/*;----SCSI MSG BYTE*/ /* see scsi/scsi.h */ /* One is missing ! */
+#define ABORT_TAG	0x0d
 
 /*
 **  Inquiry Data format
@@ -439,8 +448,12 @@
 /*  Peripheral Device Type definitions */
 /*  see include/scsi/scsi.h for the rest */
 
-#define TYPE_PRINTER		 0x02	   /* Printer device		   */
-#define TYPE_COMM		 0x09	   /* Communications device	   */
+#ifndef TYPE_PRINTER
+# define TYPE_PRINTER		 0x02	   /* Printer device		   */
+#endif
+#ifndef TYPE_COMM
+# define TYPE_COMM		 0x09	   /* Communications device	   */
+#endif
 
 /*
 ** Inquiry flag definitions (Inq data byte 7)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/scsi/ultrastor.c linux.19p18/drivers/scsi/ultrastor.c
--- linux.vanilla/drivers/scsi/ultrastor.c	Fri Apr 21 12:46:33 2000
+++ linux.19p18/drivers/scsi/ultrastor.c	Thu Dec 21 22:57:30 2000
@@ -882,9 +882,8 @@
 	(inb(SYS_DOORBELL_INTR(config.doorbell_address)) & 1))
       {
 	int flags;
-	save_flags(flags);
 	printk("Ux4F: abort while completed command pending\n");
-	restore_flags(flags);
+	save_flags(flags);
 	cli();
 	ultrastor_interrupt(0, NULL, NULL);
 	restore_flags(flags);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/Config.in linux.19p18/drivers/sound/Config.in
--- linux.vanilla/drivers/sound/Config.in	Mon Dec 11 22:12:55 2000
+++ linux.19p18/drivers/sound/Config.in	Wed Jan  3 13:26:18 2001
@@ -35,6 +35,7 @@
 fi
 
 dep_tristate 'ESS Maestro' CONFIG_SOUND_MAESTRO $CONFIG_SOUND
+dep_tristate 'ESS Maestro3' CONFIG_SOUND_MAESTRO3 $CONFIG_SOUND
 dep_tristate 'ESS Solo1' CONFIG_SOUND_ESSSOLO1 $CONFIG_SOUND
 
 dep_tristate 'Intel ICH (810, 820, 440MX...)' CONFIG_SOUND_ICH $CONFIG_SOUND
@@ -311,9 +312,9 @@
   fi
   
   dep_tristate 'NM256AV/NM256ZX audio support' CONFIG_SOUND_NM256 $CONFIG_SOUND_OSS
-  dep_tristate 'Yamaha PCI legacy mode support' CONFIG_SOUND_YMPCI $CONFIG_SOUND_OSS
-  if [ "$CONFIG_SOUND_YMPCI" = "n" ]; then
-    dep_tristate 'Yamaha PCI native mode support (EXPERIMENTAL)' CONFIG_SOUND_YMFPCI $CONFIG_SOUND_OSS
+  dep_tristate 'Yamaha PCI native mode support' CONFIG_SOUND_YMFPCI $CONFIG_SOUND_OSS
+  if [ "$CONFIG_SOUND_YMFPCI" != "n" ]; then
+    bool '  Yamaha PCI legacy ports support' CONFIG_SOUND_YMFPCI_LEGACY
   fi
 
   # Additional low level drivers.
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/Makefile linux.19p18/drivers/sound/Makefile
--- linux.vanilla/drivers/sound/Makefile	Mon Dec 11 22:12:55 2000
+++ linux.19p18/drivers/sound/Makefile	Tue Jan  9 11:59:25 2001
@@ -93,11 +93,15 @@
 obj-$(CONFIG_SOUND_ESSSOLO1)	+= esssolo1.o
 obj-$(CONFIG_SOUND_FUSION)	+= cs46xx.o ac97_codec.o
 obj-$(CONFIG_SOUND_ICH)		+= i810_audio.o ac97_codec.o
-obj-$(CONFIG_SOUND_MAESTRO)	+= maestro.o
+obj-$(CONFIG_SOUND_MAESTRO)	+= maestro.o ac97_codec.o
+obj-$(CONFIG_SOUND_MAESTRO3)	+= maestro3.o ac97_codec.o
 obj-$(CONFIG_SOUND_SONICVIBES)	+= sonicvibes.o
 obj-$(CONFIG_SOUND_TRIDENT)     += trident.o ac97_codec.o
 obj-$(CONFIG_SOUND_VIA82CXXX)	+= via82cxxx_audio.o ac97_codec.o
 obj-$(CONFIG_SOUND_YMFPCI)	+= ymfpci.o ac97_codec.o
+ifeq ($(CONFIG_SOUND_YMFPCI_LEGACY),y)
+  obj-$(CONFIG_SOUND_YMFPCI)	+= opl3.o uart401.o
+endif
 
 ifeq ($(CONFIG_SOUND_EMU10K1),y)
   obj-y				+= emu10k1/emu10k1.o
@@ -126,7 +130,6 @@
 wavefront-objs  := wavfront.o wf_midi.o yss225.o
 nm256-objs	:= nm256_audio.o ac97.o
 via82cxxx-objs  := via82cxxx_audio.o ac97.o
-ymfsb-objs	:= ymf_sb.o ac97.o
 
 
 # Extract lists of the multi-part drivers.
@@ -217,9 +220,6 @@
 
 via82cxxx.o: $(via82cxxx-objs)
 	$(LD) -r -o $@ $(via82cxxx-objs)
-
-ymfsb.o: $(ymfsb-objs)
-	$(LD) -r -o $@ $(ymfsb-objs)
 
 # Firmware files that need translation
 #
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/cs46xx.c linux.19p18/drivers/sound/cs46xx.c
--- linux.vanilla/drivers/sound/cs46xx.c	Mon Dec 11 22:12:55 2000
+++ linux.19p18/drivers/sound/cs46xx.c	Wed Dec 13 21:55:26 2000
@@ -2499,7 +2499,7 @@
 	{PCI_VENDOR_ID_IBM, 0x0132, "Thinkpad 570", amp_none, clkrun_hack},
 	{PCI_VENDOR_ID_IBM, 0x0153, "Thinkpad 600X/A20/T20", amp_none, clkrun_hack},
 	{PCI_VENDOR_ID_IBM, 0x1010, "Thinkpad 600E (unsupported)", NULL, NULL},
-	{0, 0, "Card without SSID set", NULL, NULL },
+	{0, 0, "Card without SSID set", amp_none, NULL },
 	{0, 0, NULL, NULL, NULL}
 };
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/emu10k1/main.c linux.19p18/drivers/sound/emu10k1/main.c
--- linux.vanilla/drivers/sound/emu10k1/main.c	Mon Dec 11 22:12:56 2000
+++ linux.19p18/drivers/sound/emu10k1/main.c	Thu Dec 21 23:00:02 2000
@@ -784,10 +784,3 @@
 
 module_init(emu10k1_init_module);
 module_exit(emu10k1_cleanup_module);
-
-#ifndef MODULE
-int __init init_emu10k1(void)
-{
-        return emu10k1_init_module();
-}
-#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/es1370.c linux.19p18/drivers/sound/es1370.c
--- linux.vanilla/drivers/sound/es1370.c	Mon Dec 11 22:12:56 2000
+++ linux.19p18/drivers/sound/es1370.c	Tue Dec 19 02:13:08 2000
@@ -114,6 +114,11 @@
  *    03.09.1999   0.30  change read semantics for MIDI to match
  *                       OSS more closely; remove possible wakeup race
  *    28.10.1999   0.31  More waitqueue races fixed
+ *    08.01.2000   0.32  Prevent some ioctl's from returning bad count values on underrun/overrun;
+ *                       Tim Janik's BSE (Bedevilled Sound Engine) found this
+ *    21.11.2000   0.34  Initialize dma buffers in poll, otherwise poll may return a bogus mask
+ *    12.12.2000   0.35  More dma buffer initializations, patch from
+ *                       Tjeerd Mulder <tjeerd.mulder@fujitsu-siemens.com>
  *
  * some important things missing in Ensoniq documentation:
  *
@@ -858,7 +863,8 @@
 	VALIDATE_STATE(s);
 	if (cmd == SOUND_MIXER_PRIVATE1) {
 		/* enable/disable/query mixer preamp */
-		get_user_ret(val, (int *)arg, -EFAULT);
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (val != -1) {
 			s->mix.micpreamp = !!val;
 			wrcodec(s, 0x19, s->mix.micpreamp);
@@ -867,7 +873,8 @@
 	}
 	if (cmd == SOUND_MIXER_PRIVATE2) {
 		/* enable/disable/query use of linein as second lineout */
-		get_user_ret(val, (int *)arg, -EFAULT);
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (val != -1) {
 			spin_lock_irqsave(&s->lock, flags);
 			if (val)
@@ -881,7 +888,8 @@
 	}
 	if (cmd == SOUND_MIXER_PRIVATE3) {
 		/* enable/disable/query microphone impedance setting */
-		get_user_ret(val, (int *)arg, -EFAULT);
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (val != -1) {
 			spin_lock_irqsave(&s->lock, flags);
 			if (val)
@@ -957,12 +965,14 @@
 	switch (_IOC_NR(cmd)) {
 
 	case SOUND_MIXER_IMIX:
-		get_user_ret(s->mix.imix, (int *)arg, -EFAULT);
+		if (get_user(s->mix.imix, (int *)arg))
+			return -EFAULT;
 		set_recsrc(s, s->mix.recsrc);
 		return 0;
 
 	case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
-		get_user_ret(val, (int *)arg, -EFAULT);
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
 		set_recsrc(s, val);
 		return 0;
 
@@ -970,7 +980,8 @@
 		i = _IOC_NR(cmd);
 		if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].avail)
 			return -EINVAL;
-		get_user_ret(val, (int *)arg, -EFAULT);
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
 		l = val & 0xff;
 		if (l > 100)
 			l = 100;
@@ -1354,6 +1365,7 @@
 	unsigned long flags;
         audio_buf_info abinfo;
         count_info cinfo;
+	int count;
 	int val, mapped, ret;
 
 	VALIDATE_STATE(s);
@@ -1388,7 +1400,8 @@
 		return 0;
 
         case SNDCTL_DSP_SPEED:
-                get_user_ret(val, (int *)arg, -EFAULT);
+                if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (val >= 0) {
 			if (s->open_mode & (~file->f_mode) & (FMODE_READ|FMODE_WRITE))
 				return -EINVAL;
@@ -1407,7 +1420,8 @@
 		return put_user(DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV), (int *)arg);
 		
         case SNDCTL_DSP_STEREO:
-                get_user_ret(val, (int *)arg, -EFAULT);
+                if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (file->f_mode & FMODE_READ) {
 			stop_adc(s);
 			s->dma_adc.ready = 0;
@@ -1433,7 +1447,8 @@
 		return 0;
 
         case SNDCTL_DSP_CHANNELS:
-                get_user_ret(val, (int *)arg, -EFAULT);
+                if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (val != 0) {
 			if (file->f_mode & FMODE_READ) {
 				stop_adc(s);
@@ -1464,7 +1479,8 @@
                 return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg);
 		
 	case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
-		get_user_ret(val, (int *)arg, -EFAULT);
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (val != AFMT_QUERY) {
 			if (file->f_mode & FMODE_READ) {
 				stop_adc(s);
@@ -1504,7 +1520,8 @@
 		return put_user(val, (int *)arg);
 		
 	case SNDCTL_DSP_SETTRIGGER:
-		get_user_ret(val, (int *)arg, -EFAULT);
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (file->f_mode & FMODE_READ) {
 			if (val & PCM_ENABLE_INPUT) {
 				if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
@@ -1526,12 +1543,15 @@
 	case SNDCTL_DSP_GETOSPACE:
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
-		if (!(s->ctrl & CTRL_DAC2_EN) && (val = prog_dmabuf_dac2(s)) != 0)
+		if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0)
 			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		es1370_update_ptr(s);
 		abinfo.fragsize = s->dma_dac2.fragsize;
-                abinfo.bytes = s->dma_dac2.dmasize - s->dma_dac2.count;
+		count = s->dma_dac2.count;
+		if (count < 0)
+			count = 0;
+                abinfo.bytes = s->dma_dac2.dmasize - count;
                 abinfo.fragstotal = s->dma_dac2.numfrag;
                 abinfo.fragments = abinfo.bytes >> s->dma_dac2.fragshift;      
 		spin_unlock_irqrestore(&s->lock, flags);
@@ -1540,12 +1560,15 @@
 	case SNDCTL_DSP_GETISPACE:
 		if (!(file->f_mode & FMODE_READ))
 			return -EINVAL;
-		if (!(s->ctrl & CTRL_ADC_EN) && (val = prog_dmabuf_adc(s)) != 0)
+		if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0)
 			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		es1370_update_ptr(s);
 		abinfo.fragsize = s->dma_adc.fragsize;
-                abinfo.bytes = s->dma_adc.count;
+		count = s->dma_adc.count;
+		if (count < 0)
+			count = 0;
+                abinfo.bytes = count;
                 abinfo.fragstotal = s->dma_adc.numfrag;
                 abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;      
 		spin_unlock_irqrestore(&s->lock, flags);
@@ -1558,19 +1581,28 @@
         case SNDCTL_DSP_GETODELAY:
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
+		if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0)
+			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		es1370_update_ptr(s);
-                val = s->dma_dac2.count;
+                count = s->dma_dac2.count;
 		spin_unlock_irqrestore(&s->lock, flags);
-		return put_user(val, (int *)arg);
+		if (count < 0)
+			count = 0;
+		return put_user(count, (int *)arg);
 
         case SNDCTL_DSP_GETIPTR:
 		if (!(file->f_mode & FMODE_READ))
 			return -EINVAL;
+		if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0)
+			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		es1370_update_ptr(s);
                 cinfo.bytes = s->dma_adc.total_bytes;
-                cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
+		count = s->dma_adc.count;
+		if (count < 0)
+			count = 0;
+                cinfo.blocks = count >> s->dma_adc.fragshift;
                 cinfo.ptr = s->dma_adc.hwptr;
 		if (s->dma_adc.mapped)
 			s->dma_adc.count &= s->dma_adc.fragsize-1;
@@ -1580,10 +1612,15 @@
         case SNDCTL_DSP_GETOPTR:
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
+		if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0)
+			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		es1370_update_ptr(s);
                 cinfo.bytes = s->dma_dac2.total_bytes;
-                cinfo.blocks = s->dma_dac2.count >> s->dma_dac2.fragshift;
+		count = s->dma_dac2.count;
+		if (count < 0)
+			count = 0;
+                cinfo.blocks = count >> s->dma_dac2.fragshift;
                 cinfo.ptr = s->dma_dac2.hwptr;
 		if (s->dma_dac2.mapped)
 			s->dma_dac2.count &= s->dma_dac2.fragsize-1;
@@ -1601,7 +1638,8 @@
 		return put_user(s->dma_adc.fragsize, (int *)arg);
 
         case SNDCTL_DSP_SETFRAGMENT:
-                get_user_ret(val, (int *)arg, -EFAULT);
+                if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (file->f_mode & FMODE_READ) {
 			s->dma_adc.ossfragshift = val & 0xffff;
 			s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
@@ -1628,7 +1666,8 @@
 		if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
 		    (file->f_mode & FMODE_WRITE && s->dma_dac2.subdivision))
 			return -EINVAL;
-                get_user_ret(val, (int *)arg, -EFAULT);
+                if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (val != 1 && val != 2 && val != 4)
 			return -EINVAL;
 		if (file->f_mode & FMODE_READ)
@@ -1878,6 +1917,7 @@
 	unsigned long flags;
         audio_buf_info abinfo;
         count_info cinfo;
+	int count;
 	unsigned ctrl;
 	int val, ret;
 
@@ -1902,7 +1942,8 @@
 		return 0;
 
         case SNDCTL_DSP_SPEED:
-                get_user_ret(val, (int *)arg, -EFAULT);
+                if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (val >= 0) {
 			stop_dac1(s);
 			s->dma_dac1.ready = 0;
@@ -1917,7 +1958,8 @@
 		return put_user(dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL], (int *)arg);
 		
         case SNDCTL_DSP_STEREO:
-                get_user_ret(val, (int *)arg, -EFAULT);
+                if (get_user(val, (int *)arg))
+			return -EFAULT;
 		stop_dac1(s);
 		s->dma_dac1.ready = 0;
 		spin_lock_irqsave(&s->lock, flags);
@@ -1930,7 +1972,8 @@
 		return 0;
 
         case SNDCTL_DSP_CHANNELS:
-                get_user_ret(val, (int *)arg, -EFAULT);
+                if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (val != 0) {
 			if (s->dma_dac1.mapped)
 				return -EINVAL;
@@ -1950,7 +1993,8 @@
                 return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg);
 		
         case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
-		get_user_ret(val, (int *)arg, -EFAULT);
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (val != AFMT_QUERY) {
 			stop_dac1(s);
 			s->dma_dac1.ready = 0;
@@ -1971,7 +2015,8 @@
 		return put_user((s->ctrl & CTRL_DAC1_EN) ? PCM_ENABLE_OUTPUT : 0, (int *)arg);
 						
 	case SNDCTL_DSP_SETTRIGGER:
-		get_user_ret(val, (int *)arg, -EFAULT);
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (val & PCM_ENABLE_OUTPUT) {
 			if (!s->dma_dac1.ready && (ret = prog_dmabuf_dac1(s)))
 				return ret;
@@ -1981,12 +2026,15 @@
 		return 0;
 
 	case SNDCTL_DSP_GETOSPACE:
-		if (!(s->ctrl & CTRL_DAC1_EN) && (val = prog_dmabuf_dac1(s)) != 0)
+		if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0)
 			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		es1370_update_ptr(s);
 		abinfo.fragsize = s->dma_dac1.fragsize;
-                abinfo.bytes = s->dma_dac1.dmasize - s->dma_dac1.count;
+		count = s->dma_dac1.count;
+		if (count < 0)
+			count = 0;
+                abinfo.bytes = s->dma_dac1.dmasize - count;
                 abinfo.fragstotal = s->dma_dac1.numfrag;
                 abinfo.fragments = abinfo.bytes >> s->dma_dac1.fragshift;      
 		spin_unlock_irqrestore(&s->lock, flags);
@@ -1997,19 +2045,26 @@
                 return 0;
 
         case SNDCTL_DSP_GETODELAY:
+		if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0)
+			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		es1370_update_ptr(s);
-                val = s->dma_dac1.count;
+                count = s->dma_dac1.count;
 		spin_unlock_irqrestore(&s->lock, flags);
-		return put_user(val, (int *)arg);
+		if (count < 0)
+			count = 0;
+		return put_user(count, (int *)arg);
 
         case SNDCTL_DSP_GETOPTR:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
+		if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0)
+			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		es1370_update_ptr(s);
                 cinfo.bytes = s->dma_dac1.total_bytes;
-                cinfo.blocks = s->dma_dac1.count >> s->dma_dac1.fragshift;
+		count = s->dma_dac1.count;
+		if (count < 0)
+			count = 0;
+                cinfo.blocks = count >> s->dma_dac1.fragshift;
                 cinfo.ptr = s->dma_dac1.hwptr;
 		if (s->dma_dac1.mapped)
 			s->dma_dac1.count &= s->dma_dac1.fragsize-1;
@@ -2022,7 +2077,8 @@
                 return put_user(s->dma_dac1.fragsize, (int *)arg);
 
         case SNDCTL_DSP_SETFRAGMENT:
-                get_user_ret(val, (int *)arg, -EFAULT);
+                if (get_user(val, (int *)arg))
+			return -EFAULT;
 		s->dma_dac1.ossfragshift = val & 0xffff;
 		s->dma_dac1.ossmaxfrags = (val >> 16) & 0xffff;
 		if (s->dma_dac1.ossfragshift < 4)
@@ -2036,7 +2092,8 @@
         case SNDCTL_DSP_SUBDIVIDE:
 		if (s->dma_dac1.subdivision)
 			return -EINVAL;
-                get_user_ret(val, (int *)arg, -EFAULT);
+                if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (val != 1 && val != 2 && val != 4)
 			return -EINVAL;
 		s->dma_dac1.subdivision = val;
@@ -2463,7 +2520,7 @@
 
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO "es1370: version v0.31 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "es1370: version v0.35 time " __TIME__ " " __DATE__ "\n");
 	while (index < NR_DEVICE && 
 	       (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, pcidev))) {
 		if (pcidev->base_address[0] == 0 || 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/es1371.c linux.19p18/drivers/sound/es1371.c
--- linux.vanilla/drivers/sound/es1371.c	Mon Dec 11 22:12:56 2000
+++ linux.19p18/drivers/sound/es1371.c	Tue Dec 19 02:13:08 2000
@@ -96,6 +96,12 @@
  *                       detect ES137x chip and derivatives.
  *    05.01.2000   0.22  Should now work with rev7 boards; patch by
  *                       Eric Lemar, elemar@cs.washington.edu
+ *    08.01.2000   0.23  Prevent some ioctl's from returning bad count values on underrun/overrun;
+ *                       Tim Janik's BSE (Bedevilled Sound Engine) found this
+ *    01.03.2000   0.26  SPDIF patch by Mikael Bouillot <mikael.bouillot@bigfoot.com>
+ *    21.11.2000   0.27  Initialize dma buffers in poll, otherwise poll may return a bogus mask
+ *    12.12.2000   0.28  More dma buffer initializations, patch from
+ *                       Tjeerd Mulder <tjeerd.mulder@fujitsu-siemens.com>
  */
 
 /*****************************************************************************/
@@ -1937,6 +1943,7 @@
 	unsigned long flags;
         audio_buf_info abinfo;
         count_info cinfo;
+	int count;
 	int val, mapped, ret;
 
 	VALIDATE_STATE(s);
@@ -1971,7 +1978,8 @@
 		return 0;
 
         case SNDCTL_DSP_SPEED:
-                get_user_ret(val, (int *)arg, -EFAULT);
+                if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (val >= 0) {
 			if (file->f_mode & FMODE_READ) {
 				stop_adc(s);
@@ -1987,7 +1995,8 @@
 		return put_user((file->f_mode & FMODE_READ) ? s->adcrate : s->dac2rate, (int *)arg);
 
         case SNDCTL_DSP_STEREO:
-		get_user_ret(val, (int *)arg, -EFAULT);
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (file->f_mode & FMODE_READ) {
 			stop_adc(s);
 			s->dma_adc.ready = 0;
@@ -2013,7 +2022,8 @@
 		return 0;
 
         case SNDCTL_DSP_CHANNELS:
-                get_user_ret(val, (int *)arg, -EFAULT);
+                if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (val != 0) {
 			if (file->f_mode & FMODE_READ) {
 				stop_adc(s);
@@ -2044,7 +2054,8 @@
                 return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg);
 		
 	case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
-		get_user_ret(val, (int *)arg, -EFAULT);
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (val != AFMT_QUERY) {
 			if (file->f_mode & FMODE_READ) {
 				stop_adc(s);
@@ -2084,7 +2095,8 @@
 		return put_user(val, (int *)arg);
 		
 	case SNDCTL_DSP_SETTRIGGER:
-		get_user_ret(val, (int *)arg, -EFAULT);
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (file->f_mode & FMODE_READ) {
 			if (val & PCM_ENABLE_INPUT) {
 				if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
@@ -2106,12 +2118,15 @@
 	case SNDCTL_DSP_GETOSPACE:
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
-		if (!(s->ctrl & CTRL_DAC2_EN) && (val = prog_dmabuf_dac2(s)) != 0)
+		if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0)
 			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		es1371_update_ptr(s);
 		abinfo.fragsize = s->dma_dac2.fragsize;
-                abinfo.bytes = s->dma_dac2.dmasize - s->dma_dac2.count;
+		count = s->dma_dac2.count;
+		if (count < 0)
+			count = 0;
+                abinfo.bytes = s->dma_dac2.dmasize - count;
                 abinfo.fragstotal = s->dma_dac2.numfrag;
                 abinfo.fragments = abinfo.bytes >> s->dma_dac2.fragshift;      
 		spin_unlock_irqrestore(&s->lock, flags);
@@ -2120,12 +2135,15 @@
 	case SNDCTL_DSP_GETISPACE:
 		if (!(file->f_mode & FMODE_READ))
 			return -EINVAL;
-		if (!(s->ctrl & CTRL_ADC_EN) && (val = prog_dmabuf_adc(s)) != 0)
+		if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0)
 			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		es1371_update_ptr(s);
 		abinfo.fragsize = s->dma_adc.fragsize;
-                abinfo.bytes = s->dma_adc.count;
+		count = s->dma_adc.count;
+		if (count < 0)
+			count = 0;
+                abinfo.bytes = count;
                 abinfo.fragstotal = s->dma_adc.numfrag;
                 abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;      
 		spin_unlock_irqrestore(&s->lock, flags);
@@ -2138,19 +2156,28 @@
         case SNDCTL_DSP_GETODELAY:
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
+		if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0)
+			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		es1371_update_ptr(s);
-                val = s->dma_dac2.count;
+                count = s->dma_dac2.count;
 		spin_unlock_irqrestore(&s->lock, flags);
-		return put_user(val, (int *)arg);
+		if (count < 0)
+			count = 0;
+		return put_user(count, (int *)arg);
 
         case SNDCTL_DSP_GETIPTR:
 		if (!(file->f_mode & FMODE_READ))
 			return -EINVAL;
+		if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0)
+			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		es1371_update_ptr(s);
                 cinfo.bytes = s->dma_adc.total_bytes;
-                cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
+		count = s->dma_adc.count;
+		if (count < 0)
+			count = 0;
+                cinfo.blocks = count >> s->dma_adc.fragshift;
                 cinfo.ptr = s->dma_adc.hwptr;
 		if (s->dma_adc.mapped)
 			s->dma_adc.count &= s->dma_adc.fragsize-1;
@@ -2160,10 +2187,15 @@
         case SNDCTL_DSP_GETOPTR:
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
+		if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0)
+			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		es1371_update_ptr(s);
                 cinfo.bytes = s->dma_dac2.total_bytes;
-                cinfo.blocks = s->dma_dac2.count >> s->dma_dac2.fragshift;
+		count = s->dma_dac2.count;
+		if (count < 0)
+			count = 0;
+                cinfo.blocks = count >> s->dma_dac2.fragshift;
                 cinfo.ptr = s->dma_dac2.hwptr;
 		if (s->dma_dac2.mapped)
 			s->dma_dac2.count &= s->dma_dac2.fragsize-1;
@@ -2181,7 +2213,8 @@
 		return put_user(s->dma_adc.fragsize, (int *)arg);
 
         case SNDCTL_DSP_SETFRAGMENT:
-                get_user_ret(val, (int *)arg, -EFAULT);
+                if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (file->f_mode & FMODE_READ) {
 			s->dma_adc.ossfragshift = val & 0xffff;
 			s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
@@ -2208,7 +2241,8 @@
 		if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
 		    (file->f_mode & FMODE_WRITE && s->dma_dac2.subdivision))
 			return -EINVAL;
-                get_user_ret(val, (int *)arg, -EFAULT);
+                if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (val != 1 && val != 2 && val != 4)
 			return -EINVAL;
 		if (file->f_mode & FMODE_READ)
@@ -2458,6 +2492,7 @@
 	unsigned long flags;
         audio_buf_info abinfo;
         count_info cinfo;
+	int count;
 	int val, ret;
 
 	VALIDATE_STATE(s);
@@ -2481,7 +2516,8 @@
 		return 0;
 
         case SNDCTL_DSP_SPEED:
-                get_user_ret(val, (int *)arg, -EFAULT);
+                if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (val >= 0) {
 			stop_dac1(s);
 			s->dma_dac1.ready = 0;
@@ -2490,7 +2526,8 @@
 		return put_user(s->dac1rate, (int *)arg);
 
         case SNDCTL_DSP_STEREO:
-		get_user_ret(val, (int *)arg, -EFAULT);
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
 		stop_dac1(s);
 		s->dma_dac1.ready = 0;
 		spin_lock_irqsave(&s->lock, flags);
@@ -2503,7 +2540,8 @@
 		return 0;
 
         case SNDCTL_DSP_CHANNELS:
-                get_user_ret(val, (int *)arg, -EFAULT);
+                if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (val != 0) {
 			stop_dac1(s);
 			s->dma_dac1.ready = 0;
@@ -2521,7 +2559,8 @@
                 return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg);
 		
         case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
-		get_user_ret(val, (int *)arg, -EFAULT);
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (val != AFMT_QUERY) {
 			stop_dac1(s);
 			s->dma_dac1.ready = 0;
@@ -2542,7 +2581,8 @@
 		return put_user((s->ctrl & CTRL_DAC1_EN) ? PCM_ENABLE_OUTPUT : 0, (int *)arg);
 						
 	case SNDCTL_DSP_SETTRIGGER:
-		get_user_ret(val, (int *)arg, -EFAULT);
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (val & PCM_ENABLE_OUTPUT) {
 			if (!s->dma_dac1.ready && (ret = prog_dmabuf_dac1(s)))
 				return ret;
@@ -2552,12 +2592,15 @@
 		return 0;
 
 	case SNDCTL_DSP_GETOSPACE:
-		if (!(s->ctrl & CTRL_DAC1_EN) && (val = prog_dmabuf_dac1(s)) != 0)
+		if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0)
 			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		es1371_update_ptr(s);
 		abinfo.fragsize = s->dma_dac1.fragsize;
-                abinfo.bytes = s->dma_dac1.dmasize - s->dma_dac1.count;
+		count = s->dma_dac1.count;
+		if (count < 0)
+			count = 0;
+                abinfo.bytes = s->dma_dac1.dmasize - count;
                 abinfo.fragstotal = s->dma_dac1.numfrag;
                 abinfo.fragments = abinfo.bytes >> s->dma_dac1.fragshift;      
 		spin_unlock_irqrestore(&s->lock, flags);
@@ -2568,19 +2611,26 @@
                 return 0;
 
         case SNDCTL_DSP_GETODELAY:
+		if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0)
+			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		es1371_update_ptr(s);
-                val = s->dma_dac1.count;
+                count = s->dma_dac1.count;
 		spin_unlock_irqrestore(&s->lock, flags);
-		return put_user(val, (int *)arg);
+		if (count < 0)
+			count = 0;
+		return put_user(count, (int *)arg);
 
         case SNDCTL_DSP_GETOPTR:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
+		if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0)
+			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		es1371_update_ptr(s);
                 cinfo.bytes = s->dma_dac1.total_bytes;
-                cinfo.blocks = s->dma_dac1.count >> s->dma_dac1.fragshift;
+		count = s->dma_dac1.count;
+		if (count < 0)
+			count = 0;
+                cinfo.blocks = count >> s->dma_dac1.fragshift;
                 cinfo.ptr = s->dma_dac1.hwptr;
 		if (s->dma_dac1.mapped)
 			s->dma_dac1.count &= s->dma_dac1.fragsize-1;
@@ -2593,7 +2643,8 @@
                 return put_user(s->dma_dac1.fragsize, (int *)arg);
 
         case SNDCTL_DSP_SETFRAGMENT:
-                get_user_ret(val, (int *)arg, -EFAULT);
+                if (get_user(val, (int *)arg))
+			return -EFAULT;
 		s->dma_dac1.ossfragshift = val & 0xffff;
 		s->dma_dac1.ossmaxfrags = (val >> 16) & 0xffff;
 		if (s->dma_dac1.ossfragshift < 4)
@@ -2607,7 +2658,8 @@
         case SNDCTL_DSP_SUBDIVIDE:
 		if (s->dma_dac1.subdivision)
 			return -EINVAL;
-                get_user_ret(val, (int *)arg, -EFAULT);
+                if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (val != 1 && val != 2 && val != 4)
 			return -EINVAL;
 		s->dma_dac1.subdivision = val;
@@ -3261,7 +3313,7 @@
 
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO "es1371: version v0.22 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "es1371: version v0.28 time " __TIME__ " " __DATE__ "\n");
 	for (pcidev = pci_devices; pcidev && index < NR_DEVICE; pcidev = pcidev->next) {
 		if (pcidev->vendor == PCI_VENDOR_ID_ENSONIQ) {
 			if (pcidev->device != PCI_DEVICE_ID_ENSONIQ_ES1371 &&
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/esssolo1.c linux.19p18/drivers/sound/esssolo1.c
--- linux.vanilla/drivers/sound/esssolo1.c	Mon Dec 11 22:12:56 2000
+++ linux.19p18/drivers/sound/esssolo1.c	Tue Dec 19 02:13:08 2000
@@ -63,7 +63,12 @@
  *    28.10.1999   0.10  More waitqueue races fixed
  *    09.12.1999   0.11  Work around stupid Alpha port issue (virt_to_bus(kmalloc(GFP_DMA)) > 16M)
  *                       Disabling recording on Alpha
- *
+ *    12.01.2000   0.12  Prevent some ioctl's from returning bad count values on underrun/overrun;
+ *                       Tim Janik's BSE (Bedevilled Sound Engine) found this
+ *                       Integrated (aka redid 8-)) APM support patch by Zach Brown
+ *    21.11.2000   0.16  Initialize dma buffers in poll, otherwise poll may return a bogus mask
+ *    12.12.2000   0.17  More dma buffer initializations, patch from
+ *                       Tjeerd Mulder <tjeerd.mulder@fujitsu-siemens.com>
  */
 
 /*****************************************************************************/
@@ -1276,7 +1281,8 @@
 		return 0;
 
         case SNDCTL_DSP_SPEED:
-                get_user_ret(val, (int *)arg, -EFAULT);
+                if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (val >= 0) {
 			stop_adc(s);
 			stop_dac(s);
@@ -1303,7 +1309,8 @@
 		return put_user(s->rate, (int *)arg);
 		
         case SNDCTL_DSP_STEREO:
-                get_user_ret(val, (int *)arg, -EFAULT);
+                if (get_user(val, (int *)arg))
+			return -EFAULT;
 		stop_adc(s);
 		stop_dac(s);
 		s->dma_adc.ready = s->dma_dac.ready = 0;
@@ -1313,7 +1320,8 @@
 		return 0;
 
         case SNDCTL_DSP_CHANNELS:
-                get_user_ret(val, (int *)arg, -EFAULT);
+                if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (val != 0) {
 			stop_adc(s);
 			stop_dac(s);
@@ -1328,7 +1336,8 @@
                 return put_user(AFMT_S16_LE|AFMT_U16_LE|AFMT_S8|AFMT_U8, (int *)arg);
 
 	case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
-		get_user_ret(val, (int *)arg, -EFAULT);
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (val != AFMT_QUERY) {
 			stop_adc(s);
 			stop_dac(s);
@@ -1354,7 +1363,8 @@
 		return put_user(val, (int *)arg);
 
 	case SNDCTL_DSP_SETTRIGGER:
-		get_user_ret(val, (int *)arg, -EFAULT);
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (file->f_mode & FMODE_READ) {
 			if (val & PCM_ENABLE_INPUT) {
 				if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
@@ -1378,7 +1388,7 @@
 	case SNDCTL_DSP_GETOSPACE:
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
-		if (!(s->ena & FMODE_WRITE) && (val = prog_dmabuf_dac(s)) != 0)
+		if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)) != 0)
 			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		solo1_update_ptr(s);
@@ -1395,7 +1405,7 @@
 	case SNDCTL_DSP_GETISPACE:
 		if (!(file->f_mode & FMODE_READ))
 			return -EINVAL;
-		if (!(s->ena & FMODE_READ) && (val = prog_dmabuf_adc(s)) != 0)
+		if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0)
 			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		solo1_update_ptr(s);
@@ -1413,6 +1423,8 @@
         case SNDCTL_DSP_GETODELAY:
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
+		if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)) != 0)
+			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		solo1_update_ptr(s);
                 count = s->dma_dac.count;
@@ -1424,13 +1436,12 @@
         case SNDCTL_DSP_GETIPTR:
 		if (!(file->f_mode & FMODE_READ))
 			return -EINVAL;
+		if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0)
+			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		solo1_update_ptr(s);
                 cinfo.bytes = s->dma_adc.total_bytes;
-		count = s->dma_dac.count;
-		if (count < 0)
-			count = 0;
-		cinfo.blocks = count >> s->dma_dac.fragshift;
+                cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
                 cinfo.ptr = s->dma_adc.hwptr;
 		if (s->dma_adc.mapped)
 			s->dma_adc.count &= s->dma_adc.fragsize-1;
@@ -1440,10 +1451,15 @@
         case SNDCTL_DSP_GETOPTR:
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
+		if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)) != 0)
+			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		solo1_update_ptr(s);
                 cinfo.bytes = s->dma_dac.total_bytes;
-                cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift;
+		count = s->dma_dac.count;
+		if (count < 0)
+			count = 0;
+                cinfo.blocks = count >> s->dma_dac.fragshift;
                 cinfo.ptr = s->dma_dac.hwptr;
 		if (s->dma_dac.mapped)
 			s->dma_dac.count &= s->dma_dac.fragsize-1;
@@ -1467,7 +1483,8 @@
 		return put_user(s->dma_adc.fragsize, (int *)arg);
 
         case SNDCTL_DSP_SETFRAGMENT:
-                get_user_ret(val, (int *)arg, -EFAULT);
+                if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (file->f_mode & FMODE_READ) {
 			s->dma_adc.ossfragshift = val & 0xffff;
 			s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
@@ -1494,7 +1511,8 @@
 		if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
 		    (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
 			return -EINVAL;
-                get_user_ret(val, (int *)arg, -EFAULT);
+                if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (val != 1 && val != 2 && val != 4)
 			return -EINVAL;
 		if (file->f_mode & FMODE_READ)
@@ -2170,7 +2188,7 @@
 
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO "solo1: version v0.11 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "solo1: version v0.17 time " __TIME__ " " __DATE__ "\n");
 	while (index < NR_DEVICE && 
 	       (pcidev = pci_find_device(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_SOLO1, pcidev))) {
 		if (pcidev->base_address[0] == 0 ||
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/maestro3.c linux.19p18/drivers/sound/maestro3.c
--- linux.vanilla/drivers/sound/maestro3.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/sound/maestro3.c	Wed Jan  3 01:01:13 2001
@@ -0,0 +1,3033 @@
+/*****************************************************************************
+ *
+ *      ESS Maestro3/Allegro driver for Linux 2.2.x
+ *
+ *      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.
+ *
+ *    (c) Copyright 2000 Zach Brown <zab@zabbo.net>
+ *
+ * I need to thank many people for helping make this driver happen.  
+ * As always, Eric Brombaugh was a hacking machine and killed many bugs
+ * that I was too dumb to notice.  Howard Kim at ESS provided reference boards 
+ * and as much docs as he could.  Todd and Mick at Dell tested snapshots on 
+ * an army of laptops.  msw and deviant at Red Hat also humoured me by hanging
+ * their laptops every few hours in the name of science.
+ * 
+ * Shouts go out to Mike "DJ XPCom" Ang.
+ *
+ * History
+ *  v0.51 - Dec 31 2000 - Zach Brown <zab@zabbo.net>
+ *   fix up incredibly broken open/release resource management
+ *   duh.  fix record format setting.
+ *   add SMP locking and cleanup formatting here and there
+ *  v0.50 - Dec 16 2000 - Zach Brown <zab@zabbo.net>
+ *   use native ac97_codec
+ *   pull out most SILLY_ stuff
+ *   align instance allocation so record works
+ *   fix up PCI IDs..
+ *  v0.02 - Nov 04 2000 - Zach Brown <zab@zabbo.net>
+ *   changed clocking setup for m3, slowdown fixed.
+ *   codec reset is hopefully reliable now
+ *   rudimentary apm/power management makes suspend/resume work
+ *  v0.01 - Oct 31 2000 - Zach Brown <zab@zabbo.net>
+ *   first release
+ *  v0.00 - Sep 09 2000 - Zach Brown <zab@zabbo.net>
+ *   first pass derivation from maestro.c
+ *
+ * TODO
+ *  no beep on init (mute)
+ *  resetup msrc data memory if freq changes?
+ *  clean up driver in general, 2.2/2.3 junk, etc.
+ *
+ *  --- 
+ *
+ *  Allow me to ramble a bit about the m3 architecture.  The core of the
+ *  chip is the 'assp', the custom ESS dsp that runs the show.  It has
+ *  a small amount of code and data ram.  ESS drops binary dsp code images
+ *  on our heads, but we don't get to see specs on the dsp.  
+ *
+ *  The constant piece of code on the dsp is the 'kernel'.  It also has a 
+ *  chunk of the dsp memory that is statically set aside for its control
+ *  info.  This is the KDATA defines in maestro3.h.  Part of its core
+ *  data is a list of code addresses that point to the pieces of DSP code
+ *  that it should walk through in its loop.  These other pieces of code
+ *  do the real work.  The kernel presumably jumps into each of them in turn.
+ *  These code images tend to have their own data area, and one can have
+ *  multiple data areas representing different states for each of the 'client
+ *  instance' code portions.  There is generaly a list in the kernel data
+ *  that points to the data instances for a given piece of code.
+ *
+ *  We've only been given the binary image for the 'minisrc', mini sample 
+ *  rate converter.  This is rather annoying because it limits the work
+ *  we can do on the dsp, but it also greatly simplifies the job of managing
+ *  dsp data memory for the code and data for our playing streams :).  We
+ *  statically allocate the minisrc code into a region we 'know' to be free
+ *  based on the map of the binary kernel image we're loading.  We also 
+ *  statically allocate the data areas for the maximum number of pcm streams
+ *  we can be dealing with.  This max is set by the length of the static list
+ *  in the kernel data that records the number of minisrc data regions we
+ *  can have.  Thats right, all software dsp mixing with static code list
+ *  limits.  Rock.
+ *
+ *  How sound goes in and out is still a relative mystery.  It appears
+ *  that the dsp has the ability to get input and output through various
+ *  'connections'.  To do IO from or to a connection, you put the address
+ *  of the minisrc client area in the static kernel data lists for that 
+ *  input or output.  so for pcm -> dsp -> mixer, we put the minisrc data
+ *  instance in the DMA list and also in the list for the mixer.  I guess
+ *  it Just Knows which is in/out, and we give some dma control info that
+ *  helps.  There are all sorts of cool inputs/outputs that it seems we can't
+ *  use without dsp code images that know how to use them.
+ *
+ *  So at init time we preload all the memory allocation stuff and set some
+ *  system wide parameters.  When we really get a sound to play we build
+ *  up its minisrc header (stream parameters, buffer addresses, input/output
+ *  settings).  Then we throw its header on the various lists.  We also
+ *  tickle some KDATA settings that ask the assp to raise clock interrupts
+ *  and do some amount of software mixing before handing data to the ac97.
+ *
+ *  Sorry for the vague details.  Feel free to ask Eric or myself if you
+ *  happen to be trying to use this driver elsewhere.  Please accept my
+ *  apologies for the quality of the OSS support code, its passed through
+ *  too many hands now and desperately wants to be rethought.
+ */
+
+/*****************************************************************************/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/sound.h>
+#include <linux/malloc.h>
+#include <linux/soundcard.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/reboot.h>
+#include <asm/uaccess.h>
+#include <asm/hardirq.h>
+#include <asm/spinlock.h>
+
+ /* 
+  * apologies for old intra-2.2 and 
+  * 2.2->2.4 compat cruft.. it will
+  * die someday.
+  */
+#ifndef wait_queue_head_t 
+    #define wait_queue_head_t struct wait_queue *
+#endif
+#ifndef DECLARE_WAITQUEUE
+    #define DECLARE_WAITQUEUE(QUEUE,INIT) struct wait_queue QUEUE = {INIT, NULL}
+#endif
+#ifndef init_waitqueue_head
+  #define init_waitqueue_head init_waitqueue
+#endif
+
+#define SILLY_PCI_BASE_ADDRESS(PCIDEV) (PCIDEV->base_address[0] & PCI_BASE_ADDRESS_IO_MASK)
+#define SILLY_INIT_SEM(SEM) SEM=MUTEX;
+#define SILLY_MAKE_INIT(FUNC) __initfunc(FUNC)
+#define SILLY_OFFSET(VMA) ((VMA)->vm_offset)
+
+#include <linux/ac97_codec.h>
+
+#include "maestro3.h"
+
+#define M_DEBUG 1
+
+#define DRIVER_VERSION      "0.51"
+#define PFX                 "maestro3: "
+
+#ifndef PCI_VENDOR_ESS
+#define PCI_VENDOR_ESS      0x125D
+#endif
+
+#define M3_STATE_MAGIC      0x734d724d
+#define M3_CARD_MAGIC       0x646e6f50
+
+#define ESS_FMT_STEREO      0x01
+#define ESS_FMT_16BIT       0x02
+#define ESS_FMT_MASK        0x03
+#define ESS_DAC_SHIFT       0   
+#define ESS_ADC_SHIFT       4
+
+#define DAC_RUNNING         1
+#define ADC_RUNNING         2
+
+#define SND_DEV_DSP16       5 
+
+   
+#ifdef M_DEBUG
+static int debug=0;
+static int global_dsp_speed = 49;
+#define DPMOD   1   /* per module load */
+#define DPSTR   2   /* per 'stream' */
+#define DPSYS   3   /* per syscall */
+#define DPCRAP  4   /* stuff the user shouldn't see unless they're really debuggin */
+#define DPINT   5   /* per interrupt, LOTS */
+#define DPRINTK(DP, args...) {if (debug >= (DP)) printk(KERN_DEBUG PFX args);}
+#else
+#define DPRINTK(x)
+#endif
+
+#ifdef CONFIG_APM
+#include <linux/apm_bios.h>
+static int m3_apm_callback(apm_event_t ae);
+static int in_suspend=0;
+wait_queue_head_t suspend_queue;
+static void check_suspend(void);
+#else
+#define check_suspend(args...)
+#define in_suspend 0
+#endif
+
+struct m3_list {
+    int curlen;
+    int mem_addr;
+    int max;
+};
+
+int external_amp = 1;
+static int maestro_notifier(struct notifier_block *nb, unsigned long event, void *buf);
+
+struct notifier_block maestro_nb = {maestro_notifier, NULL, 0};
+
+struct ess_state {
+    unsigned int magic;
+    struct ess_card *card;
+    unsigned char fmt, enable;
+
+    spinlock_t lock;
+
+    int index;
+
+    struct semaphore open_sem;
+    wait_queue_head_t open_wait;
+    mode_t open_mode;
+
+    int dev_audio;
+
+    struct assp_instance {
+        u16 code, data;
+    } dac_inst, adc_inst;
+
+    /* should be in dmabuf */
+    unsigned int rateadc, ratedac;
+
+    struct dmabuf {
+        void *rawbuf;
+        unsigned buforder;
+        unsigned numfrag;
+        unsigned fragshift;
+        unsigned hwptr, swptr;
+        unsigned total_bytes;
+        int count;
+        unsigned error; /* over/underrun */
+        wait_queue_head_t wait;
+        /* redundant, but makes calculations easier */
+        unsigned fragsize;
+        unsigned dmasize;
+        unsigned fragsamples;
+        /* OSS stuff */
+        unsigned mapped:1;
+        unsigned ready:1;    
+        unsigned endcleared:1;
+        unsigned ossfragshift;
+        int ossmaxfrags;
+        unsigned subdivision;
+        /* new in m3 */
+        int mixer_index, dma_index, msrc_index, adc1_index;
+        int in_lists;
+
+    } dma_dac, dma_adc;
+};
+    
+struct ess_card {
+    unsigned int magic;
+
+    struct ess_card *next;
+
+    struct ac97_codec *ac97;
+    spinlock_t ac97_lock;
+
+    int card_type;
+
+#define NR_DSPS 1
+#define MAX_DSPS NR_DSPS
+    struct ess_state channels[MAX_DSPS];
+
+    spinlock_t lock;
+
+    /* hardware resources */
+    struct pci_dev *pcidev;
+    u32 iobase;
+    u32 irq;
+
+    int dacs_active;
+
+    int timer_users;
+
+    struct m3_list  msrc_list,
+                    mixer_list,
+                    adc1_list,
+                    dma_list;
+
+    /* for storing reset state..*/
+    u8 reset_state;
+
+#ifdef CONFIG_APM
+    u16 *suspend_dsp_mem;
+#endif
+};
+
+/*
+ * an arbitrary volume we set the internal
+ * volume settings to so that the ac97 volume
+ * range is a little less insane.  0x7fff is 
+ * max.
+ */
+#define ARB_VOLUME ( 0x6800 )
+
+static const unsigned sample_shift[] = { 0, 1, 1, 2 };
+
+enum {
+    ESS_ALLEGRO,
+    ESS_MAESTRO3,
+    /* hardware strapping */
+    ESS_MAESTRO3HW
+};
+
+static struct card_type {
+    int pci_id;
+    int type;
+    char *name;
+} m3_card_types[] = {
+    {0x1988, ESS_ALLEGRO, "Allegro"},
+    {0x1998, ESS_MAESTRO3, "Maestro3(i)"},
+    {0x199a, ESS_MAESTRO3, "Maestro3(i)hw"},
+};
+#define NUM_CARD_TYPES ( sizeof(m3_card_types) / sizeof(m3_card_types[0]) )
+
+static 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;
+}
+
+static struct ess_card *devs = NULL;
+
+static void m3_outw(struct ess_card *card,
+        u16 value, unsigned long reg)
+{
+    check_suspend();
+    outw(value, card->iobase + reg);
+}
+
+static u16 m3_inw(struct ess_card *card, unsigned long reg)
+{
+    check_suspend();
+    return inw(card->iobase + reg);
+}
+static void m3_outb(struct ess_card *card, 
+        u8 value, unsigned long reg)
+{
+    check_suspend();
+    outb(value, card->iobase + reg);
+}
+static u8 m3_inb(struct ess_card *card, unsigned long reg)
+{
+    check_suspend();
+    return inb(card->iobase + reg);
+}
+
+/*
+ * access 16bit words to the code or data regions of the dsp's memory.
+ * index addresses 16bit words.
+ */
+static u16 __m3_assp_read(struct ess_card *card, u16 region, u16 index)
+{
+    m3_outw(card, region & MEMTYPE_MASK, DSP_PORT_MEMORY_TYPE);
+    m3_outw(card, index, DSP_PORT_MEMORY_INDEX);
+    return m3_inw(card, DSP_PORT_MEMORY_DATA);
+}
+static u16 m3_assp_read(struct ess_card *card, u16 region, u16 index)
+{
+    unsigned long flags;
+    u16 ret;
+
+    spin_lock_irqsave(&(card->lock), flags);
+    ret = __m3_assp_read(card, region, index);
+    spin_unlock_irqrestore(&(card->lock), flags);
+
+    return ret;
+}
+static void __m3_assp_write(struct ess_card *card, 
+        u16 region, u16 index, u16 data)
+{
+    m3_outw(card, region & MEMTYPE_MASK, DSP_PORT_MEMORY_TYPE);
+    m3_outw(card, index, DSP_PORT_MEMORY_INDEX);
+    m3_outw(card, data, DSP_PORT_MEMORY_DATA);
+}
+
+static void m3_assp_write(struct ess_card *card, 
+        u16 region, u16 index, u16 data)
+{
+    unsigned long flags;
+    spin_lock_irqsave(&(card->lock), flags);
+    __m3_assp_write(card, region, index, data);
+    spin_unlock_irqrestore(&(card->lock), flags);
+}
+
+static void m3_assp_halt(struct ess_card *card)
+{
+    card->reset_state = m3_inb(card, DSP_PORT_CONTROL_REG_B) & ~REGB_STOP_CLOCK;
+    mdelay(10);
+    m3_outb(card, card->reset_state & ~REGB_ENABLE_RESET, DSP_PORT_CONTROL_REG_B);
+}
+
+static void m3_assp_continue(struct ess_card *card)
+{
+    m3_outb(card, card->reset_state | REGB_ENABLE_RESET, DSP_PORT_CONTROL_REG_B);
+}
+
+/*
+ * This makes me sad. the maestro3 has lists
+ * internally that must be packed.. 0 terminates,
+ * apparently, or maybe all unused entries have
+ * to be 0, the lists have static lengths set
+ * by the binary code images.
+ */
+
+static int m3_add_list(struct ess_card *card,
+        struct m3_list *list, u16 val)
+{
+    DPRINTK(DPSTR, "adding val 0x%x to list 0x%p at pos %d\n",
+            val, list, list->curlen);
+
+    m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+            list->mem_addr + list->curlen,
+            val);
+
+    return list->curlen++;
+
+}
+
+static void m3_remove_list(struct ess_card *card,
+        struct m3_list *list, int index)
+{
+    u16  val;
+    int lastindex = list->curlen - 1;
+
+    DPRINTK(DPSTR, "removing ind %d from list 0x%p\n",
+            index, list);
+
+    if(index != lastindex) {
+        val = m3_assp_read(card, MEMTYPE_INTERNAL_DATA,
+                list->mem_addr + lastindex);
+        m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+                list->mem_addr + index,
+                val);
+    }
+
+    m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+            list->mem_addr + lastindex,
+            0);
+
+    list->curlen--;
+}
+
+static void set_fmt(struct ess_state *s, unsigned char mask, unsigned char data)
+{
+    int tmp;
+
+    s->fmt = (s->fmt & mask) | data;
+
+    tmp = (s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK;
+
+    /* write to 'mono' word */
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+            s->dac_inst.data + SRC3_DIRECTION_OFFSET + 1, 
+            (tmp & ESS_FMT_STEREO) ? 0 : 1);
+    /* write to '8bit' word */
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+            s->dac_inst.data + SRC3_DIRECTION_OFFSET + 2, 
+            (tmp & ESS_FMT_16BIT) ? 0 : 1);
+
+    tmp = (s->fmt >> ESS_ADC_SHIFT) & ESS_FMT_MASK;
+
+    /* write to 'mono' word */
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+            s->adc_inst.data + SRC3_DIRECTION_OFFSET + 1, 
+            (tmp & ESS_FMT_STEREO) ? 0 : 1);
+    /* write to '8bit' word */
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+            s->adc_inst.data + SRC3_DIRECTION_OFFSET + 2, 
+            (tmp & ESS_FMT_16BIT) ? 0 : 1);
+}
+
+static void set_dac_rate(struct ess_state *s, unsigned int rate)
+{
+    u32 freq;
+
+    if (rate > 48000)
+        rate = 48000;
+    if (rate < 8000)
+        rate = 8000;
+
+    s->ratedac = rate;
+
+    freq = ((rate << 15) + 24000 ) / 48000;
+    if(freq) 
+        freq--;
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+            s->dac_inst.data + CDATA_FREQUENCY,
+            freq);
+}
+
+static void set_adc_rate(struct ess_state *s, unsigned int rate)
+{
+    u32 freq;
+
+    if (rate > 48000)
+        rate = 48000;
+    if (rate < 8000)
+        rate = 8000;
+
+    s->rateadc = rate;
+
+    freq = ((rate << 15) + 24000 ) / 48000;
+    if(freq) 
+        freq--;
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+            s->adc_inst.data + CDATA_FREQUENCY,
+            freq);
+}
+
+static void inc_timer_users(struct ess_card *card)
+{
+    unsigned long flags;
+
+    spin_lock_irqsave(&card->lock, flags);
+    card->timer_users++;
+    DPRINTK(DPSYS, "inc timer users now %d\n",
+            card->timer_users);
+    if(card->timer_users != 1) 
+        goto out;
+
+    __m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+        KDATA_TIMER_COUNT_RELOAD,
+         240 ) ;
+
+    __m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+        KDATA_TIMER_COUNT_CURRENT,
+         240 ) ;
+
+    m3_outw(card,  
+            m3_inw(card, HOST_INT_CTRL) | CLKRUN_GEN_ENABLE,
+            HOST_INT_CTRL);
+
+out:
+    spin_unlock_irqrestore(&card->lock, flags);
+}
+
+static void dec_timer_users(struct ess_card *card)
+{
+    unsigned long flags;
+
+    spin_lock_irqsave(&card->lock, flags);
+
+    card->timer_users--;
+    DPRINTK(DPSYS, "dec timer users now %d\n",
+            card->timer_users);
+    if(card->timer_users > 0 ) 
+        goto out;
+
+    __m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+        KDATA_TIMER_COUNT_RELOAD,
+         0 ) ;
+
+    __m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+        KDATA_TIMER_COUNT_CURRENT,
+         0 ) ;
+
+    m3_outw(card,  m3_inw(card, HOST_INT_CTRL) & ~CLKRUN_GEN_ENABLE,
+            HOST_INT_CTRL);
+out:
+    spin_unlock_irqrestore(&card->lock, flags);
+}
+
+/*
+ * {start,stop}_{adc,dac} should be called
+ * while holding the 'state' lock and they
+ * will try to grab the 'card' lock..
+ */
+static void stop_adc(struct ess_state *s)
+{
+    if (! (s->enable & ADC_RUNNING)) 
+        return;
+
+    s->enable &= ~ADC_RUNNING;
+    dec_timer_users(s->card);
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+            s->adc_inst.data + CDATA_INSTANCE_READY, 0);
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+            KDATA_ADC1_REQUEST, 0);
+}    
+
+static void stop_dac(struct ess_state *s)
+{
+    if (! (s->enable & DAC_RUNNING)) 
+        return;
+
+    DPRINTK(DPSYS, "stop_dac()\n");
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+            s->dac_inst.data + CDATA_INSTANCE_READY, 0);
+
+    s->enable &= ~DAC_RUNNING;
+    s->card->dacs_active--;
+    dec_timer_users(s->card);
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+            KDATA_MIXER_TASK_NUMBER, 
+            s->card->dacs_active ) ;
+}    
+
+static void start_dac(struct ess_state *s)
+{
+    if( (!s->dma_dac.mapped && s->dma_dac.count < 1) ||
+            !s->dma_dac.ready ||
+            (s->enable & DAC_RUNNING)) 
+        return;
+
+    DPRINTK(DPSYS, "start_dac()\n");
+
+    s->enable |= DAC_RUNNING;
+    s->card->dacs_active++;
+    inc_timer_users(s->card);
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+            s->dac_inst.data + CDATA_INSTANCE_READY, 1);
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+            KDATA_MIXER_TASK_NUMBER, 
+            s->card->dacs_active ) ;
+}    
+
+static void start_adc(struct ess_state *s)
+{
+    if ((! s->dma_adc.mapped &&
+                s->dma_adc.count >= (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize)) 
+        || !s->dma_adc.ready 
+        || (s->enable & ADC_RUNNING) ) 
+            return;
+
+    DPRINTK(DPSYS, "start_adc()\n");
+
+    s->enable |= ADC_RUNNING;
+    inc_timer_users(s->card);
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+            KDATA_ADC1_REQUEST, 1);
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+            s->adc_inst.data + CDATA_INSTANCE_READY, 1);
+}    
+
+static struct play_vals {
+    u16 addr, val;
+} pv[] = {
+    {CDATA_LEFT_VOLUME, ARB_VOLUME},
+    {CDATA_RIGHT_VOLUME, ARB_VOLUME},
+    {SRC3_DIRECTION_OFFSET, 0} ,
+    /* +1, +2 are stereo/16 bit */
+    {SRC3_DIRECTION_OFFSET + 3, 0X0000}, /* fraction? */
+    {SRC3_DIRECTION_OFFSET + 4, 0}, /* first l */
+    {SRC3_DIRECTION_OFFSET + 5, 0}, /* first r */
+    {SRC3_DIRECTION_OFFSET + 6, 0}, /* second l */
+    {SRC3_DIRECTION_OFFSET + 7, 0}, /* second r */
+    {SRC3_DIRECTION_OFFSET + 8, 0}, /* delta l */
+    {SRC3_DIRECTION_OFFSET + 9, 0}, /* delta r */
+    {SRC3_DIRECTION_OFFSET + 10, 0X8000}, /* round */
+    {SRC3_DIRECTION_OFFSET + 11, 0XFF00}, /* higher bute mark */
+    {SRC3_DIRECTION_OFFSET + 13, 0}, /* temp0 */
+    {SRC3_DIRECTION_OFFSET + 14, 0}, /* c fraction */
+    {SRC3_DIRECTION_OFFSET + 15, 0}, /* counter */
+    {SRC3_DIRECTION_OFFSET + 16, 8}, /* numin */
+    {SRC3_DIRECTION_OFFSET + 17, 50*2}, /* numout */
+    {SRC3_DIRECTION_OFFSET + 18, MINISRC_BIQUAD_STAGE - 1}, /* numstage */
+    {SRC3_DIRECTION_OFFSET + 20, 0}, /* filtertap */
+    {SRC3_DIRECTION_OFFSET + 21, 0} /* booster */
+};
+
+static void 
+ess_play_setup(struct ess_state *s, int mode, u32 rate, void *buffer, int size)
+{
+    int dsp_in_size = MINISRC_IN_BUFFER_SIZE - (0x20 * 2);
+    int dsp_out_size = MINISRC_OUT_BUFFER_SIZE - (0x20 * 2);
+    int dsp_in_buffer = s->dac_inst.data + (MINISRC_TMP_BUFFER_SIZE / 2);
+    int dsp_out_buffer = dsp_in_buffer + (dsp_in_size / 2) + 1;
+    struct dmabuf *db = &s->dma_dac;
+    int i;
+
+    DPRINTK(DPSTR, "mode=%d rate=%d buf=%p len=%d.\n",
+        mode, rate, buffer, size);
+
+#define LO(x) ((x) & 0xffff)
+#define HI(x) LO((x) >> 16)
+
+    /* host dma buffer pointers */
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+        s->dac_inst.data + CDATA_HOST_SRC_ADDRL,
+        LO(virt_to_bus(buffer)));
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+        s->dac_inst.data + CDATA_HOST_SRC_ADDRH,
+        HI(virt_to_bus(buffer)));
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+        s->dac_inst.data + CDATA_HOST_SRC_END_PLUS_1L,
+        LO(virt_to_bus(buffer) + size));
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+        s->dac_inst.data + CDATA_HOST_SRC_END_PLUS_1H,
+        HI(virt_to_bus(buffer) + size));
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+        s->dac_inst.data + CDATA_HOST_SRC_CURRENTL,
+        LO(virt_to_bus(buffer)));
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+        s->dac_inst.data + CDATA_HOST_SRC_CURRENTH,
+        HI(virt_to_bus(buffer)));
+#undef LO
+#undef HI
+
+    /* dsp buffers */
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+        s->dac_inst.data + CDATA_IN_BUF_BEGIN,
+        dsp_in_buffer);
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+        s->dac_inst.data + CDATA_IN_BUF_END_PLUS_1,
+        dsp_in_buffer + (dsp_in_size / 2));
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+        s->dac_inst.data + CDATA_IN_BUF_HEAD,
+        dsp_in_buffer);
+    
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+        s->dac_inst.data + CDATA_IN_BUF_TAIL,
+        dsp_in_buffer);
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+        s->dac_inst.data + CDATA_OUT_BUF_BEGIN,
+        dsp_out_buffer);
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+        s->dac_inst.data + CDATA_OUT_BUF_END_PLUS_1,
+        dsp_out_buffer + (dsp_out_size / 2));
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+        s->dac_inst.data + CDATA_OUT_BUF_HEAD,
+        dsp_out_buffer);
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+        s->dac_inst.data + CDATA_OUT_BUF_TAIL,
+        dsp_out_buffer);
+
+    /*
+     * some per client initializers
+     */
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+        s->dac_inst.data + SRC3_DIRECTION_OFFSET + 12,
+        s->dac_inst.data + 40 + 8);
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+        s->dac_inst.data + SRC3_DIRECTION_OFFSET + 19,
+        s->dac_inst.code + MINISRC_COEF_LOC);
+
+    /* enable or disable low pass filter? */
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+        s->dac_inst.data + SRC3_DIRECTION_OFFSET + 22,
+        s->ratedac > 45000 ? 0xff : 0 );
+    
+    /* tell it which way dma is going? */
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+        s->dac_inst.data + CDATA_DMA_CONTROL,
+        DMACONTROL_AUTOREPEAT + DMAC_PAGE3_SELECTOR + DMAC_BLOCKF_SELECTOR);
+
+    /*
+     * set an armload of static initializers
+     */
+    for(i = 0 ; i < (sizeof(pv) / sizeof(pv[0])) ; i++) 
+        m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+            s->dac_inst.data + pv[i].addr, pv[i].val);
+
+    /* 
+     * put us in the lists if we're not already there
+     */
+
+    if(db->in_lists == 0) {
+
+        db->msrc_index = m3_add_list(s->card, &s->card->msrc_list, 
+                s->dac_inst.data >> DP_SHIFT_COUNT);
+
+        db->dma_index = m3_add_list(s->card, &s->card->dma_list, 
+                s->dac_inst.data >> DP_SHIFT_COUNT);
+
+        db->mixer_index = m3_add_list(s->card, &s->card->mixer_list, 
+                s->dac_inst.data >> DP_SHIFT_COUNT);
+
+        db->in_lists = 1;
+    }
+
+    set_dac_rate(s,rate);
+    start_dac(s);
+}
+
+/*
+ *    Native record driver 
+ */
+static struct rec_vals {
+    u16 addr, val;
+} rv[] = {
+    {CDATA_LEFT_VOLUME, ARB_VOLUME},
+    {CDATA_RIGHT_VOLUME, ARB_VOLUME},
+    {SRC3_DIRECTION_OFFSET, 1} ,
+    /* +1, +2 are stereo/16 bit */
+    {SRC3_DIRECTION_OFFSET + 3, 0X0000}, /* fraction? */
+    {SRC3_DIRECTION_OFFSET + 4, 0}, /* first l */
+    {SRC3_DIRECTION_OFFSET + 5, 0}, /* first r */
+    {SRC3_DIRECTION_OFFSET + 6, 0}, /* second l */
+    {SRC3_DIRECTION_OFFSET + 7, 0}, /* second r */
+    {SRC3_DIRECTION_OFFSET + 8, 0}, /* delta l */
+    {SRC3_DIRECTION_OFFSET + 9, 0}, /* delta r */
+    {SRC3_DIRECTION_OFFSET + 10, 0X8000}, /* round */
+    {SRC3_DIRECTION_OFFSET + 11, 0XFF00}, /* higher bute mark */
+    {SRC3_DIRECTION_OFFSET + 13, 0}, /* temp0 */
+    {SRC3_DIRECTION_OFFSET + 14, 0}, /* c fraction */
+    {SRC3_DIRECTION_OFFSET + 15, 0}, /* counter */
+    {SRC3_DIRECTION_OFFSET + 16, 50},/* numin */
+    {SRC3_DIRECTION_OFFSET + 17, 8}, /* numout */
+    {SRC3_DIRECTION_OFFSET + 18, 0}, /* numstage */
+    {SRC3_DIRECTION_OFFSET + 19, 0}, /* coef */
+    {SRC3_DIRECTION_OFFSET + 20, 0}, /* filtertap */
+    {SRC3_DIRECTION_OFFSET + 21, 0}, /* booster */
+    {SRC3_DIRECTION_OFFSET + 22, 0xff} /* skip lpf */
+};
+
+/*
+ * the buffer passed here must be 32bit aligned 
+ */
+static void 
+ess_rec_setup(struct ess_state *s, int mode, u32 rate, void *buffer, int size)
+{
+    int dsp_in_size = MINISRC_IN_BUFFER_SIZE + (0x10 * 2);
+    int dsp_out_size = MINISRC_OUT_BUFFER_SIZE - (0x10 * 2);
+    int dsp_in_buffer = s->adc_inst.data + (MINISRC_TMP_BUFFER_SIZE / 2);
+    int dsp_out_buffer = dsp_in_buffer + (dsp_in_size / 2) + 1;
+    struct dmabuf *db = &s->dma_adc;
+    int i;
+
+    DPRINTK(DPSTR, "rec_setup mode=%d rate=%d buf=%p len=%d.\n",
+        mode, rate, buffer, size);
+
+#define LO(x) ((x) & 0xffff)
+#define HI(x) LO((x) >> 16)
+
+    /* host dma buffer pointers */
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+        s->adc_inst.data + CDATA_HOST_SRC_ADDRL,
+        LO(virt_to_bus(buffer)));
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+        s->adc_inst.data + CDATA_HOST_SRC_ADDRH,
+        HI(virt_to_bus(buffer)));
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+        s->adc_inst.data + CDATA_HOST_SRC_END_PLUS_1L,
+        LO(virt_to_bus(buffer) + size));
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+        s->adc_inst.data + CDATA_HOST_SRC_END_PLUS_1H,
+        HI(virt_to_bus(buffer) + size));
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+        s->adc_inst.data + CDATA_HOST_SRC_CURRENTL,
+        LO(virt_to_bus(buffer)));
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+        s->adc_inst.data + CDATA_HOST_SRC_CURRENTH,
+        HI(virt_to_bus(buffer)));
+#undef LO
+#undef HI
+
+    /* dsp buffers */
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+        s->adc_inst.data + CDATA_IN_BUF_BEGIN,
+        dsp_in_buffer);
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+        s->adc_inst.data + CDATA_IN_BUF_END_PLUS_1,
+        dsp_in_buffer + (dsp_in_size / 2));
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+        s->adc_inst.data + CDATA_IN_BUF_HEAD,
+        dsp_in_buffer);
+    
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+        s->adc_inst.data + CDATA_IN_BUF_TAIL,
+        dsp_in_buffer);
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+        s->adc_inst.data + CDATA_OUT_BUF_BEGIN,
+        dsp_out_buffer);
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+        s->adc_inst.data + CDATA_OUT_BUF_END_PLUS_1,
+        dsp_out_buffer + (dsp_out_size / 2));
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+        s->adc_inst.data + CDATA_OUT_BUF_HEAD,
+        dsp_out_buffer);
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+        s->adc_inst.data + CDATA_OUT_BUF_TAIL,
+        dsp_out_buffer);
+
+    /*
+     * some per client initializers
+     */
+
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+        s->adc_inst.data + SRC3_DIRECTION_OFFSET + 12,
+        s->adc_inst.data + 40 + 8);
+
+    /* tell it which way dma is going? */
+    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+        s->adc_inst.data + CDATA_DMA_CONTROL,
+        DMACONTROL_DIRECTION + DMACONTROL_AUTOREPEAT + 
+        DMAC_PAGE3_SELECTOR + DMAC_BLOCKF_SELECTOR);
+
+    /*
+     * set an armload of static initializers
+     */
+    for(i = 0 ; i < (sizeof(rv) / sizeof(rv[0])) ; i++) 
+        m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
+            s->adc_inst.data + rv[i].addr, rv[i].val);
+
+    /* 
+     * put us in the lists if we're not already there
+     */
+
+    if(db->in_lists == 0) {
+
+        db->adc1_index = m3_add_list(s->card, &s->card->adc1_list, 
+                s->adc_inst.data >> DP_SHIFT_COUNT);
+
+        db->dma_index = m3_add_list(s->card, &s->card->dma_list, 
+                s->adc_inst.data >> DP_SHIFT_COUNT);
+
+        db->msrc_index = m3_add_list(s->card, &s->card->msrc_list, 
+                s->adc_inst.data >> DP_SHIFT_COUNT);
+
+        db->in_lists = 1;
+    }
+
+    set_fmt(s, ~0, 0);
+    set_adc_rate(s,rate);
+    start_adc(s);
+}
+/* --------------------------------------------------------------------- */
+
+static void set_dmaa(struct ess_state *s, unsigned int addr, unsigned int count)
+{
+    DPRINTK(DPINT,"set_dmaa??\n");
+}
+
+static void set_dmac(struct ess_state *s, unsigned int addr, unsigned int count)
+{
+    DPRINTK(DPINT,"set_dmac??\n");
+}
+
+u32 get_dma_pos(struct ess_card *card,
+        int instance_addr)
+{
+    u16 hi = 0, lo = 0;
+    int retry = 10;
+
+    /*
+     * try and get a valid answer
+     */
+    while(retry--) {
+        hi =  m3_assp_read(card, MEMTYPE_INTERNAL_DATA,
+                instance_addr + CDATA_HOST_SRC_CURRENTH);
+
+        lo = m3_assp_read(card, MEMTYPE_INTERNAL_DATA,
+                instance_addr + CDATA_HOST_SRC_CURRENTL);
+
+        if(hi == m3_assp_read(card, MEMTYPE_INTERNAL_DATA,
+                instance_addr + CDATA_HOST_SRC_CURRENTH))
+            break;
+    }
+    return lo | (hi<<16);
+}
+
+u32 get_dmaa(struct ess_state *s)
+{
+    u32 offset;
+
+    offset = get_dma_pos(s->card, s->dac_inst.data) - 
+        virt_to_bus(s->dma_dac.rawbuf);
+
+    DPRINTK(DPINT,"get_dmaa: 0x%08x\n",offset);
+
+    return offset;
+}
+
+u32 get_dmac(struct ess_state *s)
+{
+    u32 offset;
+
+    offset = get_dma_pos(s->card, s->adc_inst.data) -
+        virt_to_bus(s->dma_adc.rawbuf);
+
+    DPRINTK(DPINT,"get_dmac: 0x%08x\n",offset);
+
+    return offset;
+
+}
+
+static void ess_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+
+static int 
+prog_dmabuf(struct ess_state *s, unsigned rec)
+{
+    struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac;
+    unsigned rate = rec ? s->rateadc : s->ratedac;
+    unsigned bytepersec;
+    unsigned bufs;
+    unsigned char fmt;
+    unsigned long flags;
+
+    spin_lock_irqsave(&s->lock, flags);
+
+    fmt = s->fmt;
+    if (rec) {
+        stop_adc(s);
+        fmt >>= ESS_ADC_SHIFT;
+    } else {
+        stop_dac(s);
+        fmt >>= ESS_DAC_SHIFT;
+    }
+    fmt &= ESS_FMT_MASK;
+
+    db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
+
+    bytepersec = rate << sample_shift[fmt];
+    bufs = PAGE_SIZE << db->buforder;
+    if (db->ossfragshift) {
+        if ((1000 << db->ossfragshift) < bytepersec)
+            db->fragshift = ld2(bytepersec/1000);
+        else
+            db->fragshift = db->ossfragshift;
+    } else {
+        db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1));
+        if (db->fragshift < 3)
+            db->fragshift = 3; 
+    }
+    db->numfrag = bufs >> db->fragshift;
+    while (db->numfrag < 4 && db->fragshift > 3) {
+        db->fragshift--;
+        db->numfrag = bufs >> db->fragshift;
+    }
+    db->fragsize = 1 << db->fragshift;
+    if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
+        db->numfrag = db->ossmaxfrags;
+    db->fragsamples = db->fragsize >> sample_shift[fmt];
+    db->dmasize = db->numfrag << db->fragshift;
+
+    DPRINTK(DPSTR,"prog_dmabuf: numfrag: %d fragsize: %d dmasize: %d\n",db->numfrag,db->fragsize,db->dmasize);
+
+    memset(db->rawbuf, (fmt & ESS_FMT_16BIT) ? 0 : 0x80, db->dmasize);
+
+    if (rec) 
+        ess_rec_setup(s, fmt, s->rateadc, db->rawbuf, db->dmasize);
+    else 
+        ess_play_setup(s, fmt, s->ratedac, db->rawbuf, db->dmasize);
+
+    db->ready = 1;
+
+    spin_unlock_irqrestore(&s->lock, flags);
+
+    return 0;
+}
+
+static void clear_advance(struct ess_state *s)
+{
+    unsigned char c = ((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_16BIT) ? 0 : 0x80;
+    
+    unsigned char *buf = s->dma_dac.rawbuf;
+    unsigned bsize = s->dma_dac.dmasize;
+    unsigned bptr = s->dma_dac.swptr;
+    unsigned len = s->dma_dac.fragsize;
+    
+    if (bptr + len > bsize) {
+        unsigned x = bsize - bptr;
+        memset(buf + bptr, c, x);
+        /* account for wrapping? */
+        bptr = 0;
+        len -= x;
+    }
+    memset(buf + bptr, c, len);
+}
+
+static void ess_update_ptr(struct ess_state *s)
+{
+    unsigned hwptr;
+    int diff;
+
+    /* update ADC pointer */
+    if (s->dma_adc.ready) {
+        hwptr = get_dmac(s) % s->dma_adc.dmasize;
+        diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;
+        s->dma_adc.hwptr = hwptr;
+        s->dma_adc.total_bytes += diff;
+        s->dma_adc.count += diff;
+        if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) 
+            wake_up(&s->dma_adc.wait);
+        if (!s->dma_adc.mapped) {
+            if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
+                stop_adc(s); 
+                /* brute force everyone back in sync, sigh */
+                s->dma_adc.count = 0;
+                s->dma_adc.swptr = 0;
+                s->dma_adc.hwptr = 0;
+                s->dma_adc.error++;
+            }
+        }
+    }
+    /* update DAC pointer */
+    if (s->dma_dac.ready) {
+        hwptr = get_dmaa(s) % s->dma_dac.dmasize; 
+        diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
+
+        DPRINTK(DPINT,"updating dac: hwptr: %6d diff: %6d count: %6d\n",
+                hwptr,diff,s->dma_dac.count);
+
+        s->dma_dac.hwptr = hwptr;
+        s->dma_dac.total_bytes += diff;
+
+        if (s->dma_dac.mapped) {
+            
+            s->dma_dac.count += diff;
+            if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) {
+                wake_up(&s->dma_dac.wait);
+            }
+        } else {
+
+            s->dma_dac.count -= diff;
+            
+            if (s->dma_dac.count <= 0) {
+                DPRINTK(DPCRAP,"underflow! diff: %d (0x%x) count: %d (0x%x) hw: %d (0x%x) sw: %d (0x%x)\n", 
+                        diff, diff, 
+                        s->dma_dac.count, 
+                        s->dma_dac.count, 
+                    hwptr, hwptr,
+                    s->dma_dac.swptr,
+                    s->dma_dac.swptr);
+                stop_dac(s);
+                /* brute force everyone back in sync, sigh */
+                s->dma_dac.count = 0; 
+                s->dma_dac.swptr = hwptr; 
+                s->dma_dac.error++;
+            } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) {
+                clear_advance(s);
+                s->dma_dac.endcleared = 1;
+            }
+            if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize) {
+                wake_up(&s->dma_dac.wait);
+                DPRINTK(DPINT,"waking up DAC count: %d sw: %d hw: %d\n",
+                        s->dma_dac.count, s->dma_dac.swptr, hwptr);
+            }
+        }
+    }
+}
+
+static void 
+ess_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+    struct ess_card *c = (struct ess_card *)dev_id;
+    struct ess_state *s = &c->channels[0];
+    u8 status;
+
+    status = inb(c->iobase + 0x1A);
+
+    if(status == 0xff) 
+        return;
+   
+    /* presumably acking the ints? */
+    outw(status, c->iobase + 0x1A); 
+
+    if(in_suspend)
+        return;
+
+    /*
+     * ack an assp int if its running
+     * and has an int pending
+     */
+    if( status & ASSP_INT_PENDING) {
+        u8 ctl = inb(c->iobase + ASSP_CONTROL_B);
+        if( !(ctl & STOP_ASSP_CLOCK)) {
+            ctl = inb(c->iobase + ASSP_HOST_INT_STATUS );
+            if(ctl & DSP2HOST_REQ_TIMER) {
+                outb( DSP2HOST_REQ_TIMER, c->iobase + ASSP_HOST_INT_STATUS);
+
+                /* update adc/dac info if it was a timer int */
+                spin_lock(&s->lock);
+                ess_update_ptr(s);
+                spin_unlock(&s->lock);
+            }
+        }
+    }
+
+    /* XXX is this needed? */
+    if(status & 0x40) 
+        outb(0x40, c->iobase+0x1A);
+}
+
+
+/* --------------------------------------------------------------------- */
+
+static const char invalid_magic[] = KERN_CRIT PFX "invalid magic value in %s\n";
+
+#define VALIDATE_MAGIC(FOO,MAG)                         \
+({                                                \
+    if (!(FOO) || (FOO)->magic != MAG) { \
+        printk(invalid_magic,__FUNCTION__);            \
+        return -ENXIO;                    \
+    }                                         \
+})
+
+#define VALIDATE_STATE(a) VALIDATE_MAGIC(a,M3_STATE_MAGIC)
+#define VALIDATE_CARD(a) VALIDATE_MAGIC(a,M3_CARD_MAGIC)
+
+/* --------------------------------------------------------------------- */
+
+static loff_t m3_llseek(struct file *file, loff_t offset, int origin)
+{
+    return -ESPIPE;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int drain_dac(struct ess_state *s, int nonblock)
+{
+    DECLARE_WAITQUEUE(wait,current);
+    unsigned long flags;
+    int count;
+    signed long tmo;
+
+    if (s->dma_dac.mapped || !s->dma_dac.ready)
+        return 0;
+    current->state = TASK_INTERRUPTIBLE;
+    add_wait_queue(&s->dma_dac.wait, &wait);
+    for (;;) {
+        spin_lock_irqsave(&s->lock, flags);
+        count = s->dma_dac.count;
+        spin_unlock_irqrestore(&s->lock, flags);
+        if (count <= 0)
+            break;
+        if (signal_pending(current))
+            break;
+        if (nonblock) {
+            remove_wait_queue(&s->dma_dac.wait, &wait);
+            current->state = TASK_RUNNING;
+            return -EBUSY;
+        }
+        tmo = (count * HZ) / s->ratedac;
+        tmo >>= sample_shift[(s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK];
+        /* XXX this is just broken.  someone is waking us up alot, or schedule_timeout is broken.
+            or something.  who cares. - zach */
+        if (!schedule_timeout(tmo ? tmo : 1) && tmo)
+            DPRINTK(DPCRAP,"dma timed out?? %ld\n",jiffies);
+    }
+    remove_wait_queue(&s->dma_dac.wait, &wait);
+    current->state = TASK_RUNNING;
+    if (signal_pending(current))
+            return -ERESTARTSYS;
+    return 0;
+}
+
+static ssize_t 
+ess_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+    struct ess_state *s = (struct ess_state *)file->private_data;
+    ssize_t ret;
+    unsigned long flags;
+    unsigned swptr;
+    int cnt;
+    
+    VALIDATE_STATE(s);
+    if (ppos != &file->f_pos)
+        return -ESPIPE;
+    if (s->dma_adc.mapped)
+        return -ENXIO;
+    if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
+        return ret;
+    if (!access_ok(VERIFY_WRITE, buffer, count))
+        return -EFAULT;
+    ret = 0;
+
+    spin_lock_irqsave(&s->lock, flags);
+
+    while (count > 0) {
+        int timed_out;
+
+        swptr = s->dma_adc.swptr;
+        cnt = s->dma_adc.dmasize-swptr;
+        if (s->dma_adc.count < cnt)
+            cnt = s->dma_adc.count;
+
+        if (cnt > count)
+            cnt = count;
+
+        if (cnt <= 0) {
+            start_adc(s);
+            if (file->f_flags & O_NONBLOCK) {
+                ret = ret ? ret : -EAGAIN;
+                goto out;
+            }
+
+            spin_unlock_irqrestore(&s->lock, flags);
+
+            timed_out = interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ) == 0;
+
+            spin_lock_irqsave(&s->lock, flags);
+                
+            if(timed_out) {
+                printk("read: chip lockup? dmasz %d fragsz %d count %d hwptr %d swptr %d\n",
+                       s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count, 
+                       s->dma_adc.hwptr, s->dma_adc.swptr);
+                stop_adc(s);
+                set_dmac(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.numfrag << s->dma_adc.fragshift);
+                s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
+            }
+
+            if (signal_pending(current)) {
+                ret = ret ? ret : -ERESTARTSYS;
+                goto out;
+            }
+            continue;
+        }
+    
+        spin_unlock_irqrestore(&s->lock, flags);
+        if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) {
+            ret = ret ? ret : -EFAULT;
+            return ret;
+        }
+        spin_lock_irqsave(&s->lock, flags);
+
+        swptr = (swptr + cnt) % s->dma_adc.dmasize;
+        s->dma_adc.swptr = swptr;
+        s->dma_adc.count -= cnt;
+        count -= cnt;
+        buffer += cnt;
+        ret += cnt;
+        start_adc(s);
+    }
+
+out:
+    spin_unlock_irqrestore(&s->lock, flags);
+    return ret;
+}
+
+static ssize_t 
+ess_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+    struct ess_state *s = (struct ess_state *)file->private_data;
+    ssize_t ret;
+    unsigned long flags;
+    unsigned swptr;
+    int cnt;
+    
+    VALIDATE_STATE(s);
+    if (ppos != &file->f_pos)
+        return -ESPIPE;
+    if (s->dma_dac.mapped)
+        return -ENXIO;
+    if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
+        return ret;
+    if (!access_ok(VERIFY_READ, buffer, count))
+        return -EFAULT;
+    ret = 0;
+
+    spin_lock_irqsave(&s->lock, flags);
+
+    while (count > 0) {
+        int timed_out;
+
+        if (s->dma_dac.count < 0) {
+            s->dma_dac.count = 0;
+            s->dma_dac.swptr = s->dma_dac.hwptr;
+        }
+        swptr = s->dma_dac.swptr;
+
+        cnt = s->dma_dac.dmasize-swptr;
+
+        if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
+            cnt = s->dma_dac.dmasize - s->dma_dac.count;
+
+        if (cnt > count)
+            cnt = count;
+
+        if (cnt <= 0) {
+            start_dac(s);
+            if (file->f_flags & O_NONBLOCK) {
+                if(!ret) ret = -EAGAIN;
+                goto out;
+            }
+
+            spin_unlock_irqrestore(&s->lock, flags);
+            timed_out = interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ) == 0;
+            spin_lock_irqsave(&s->lock, flags);
+
+            if(timed_out) {
+                DPRINTK(DPCRAP,"write: chip lockup? dmasz %d fragsz %d count %d hwptr %d swptr %d\n",
+                       s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count, 
+                       s->dma_dac.hwptr, s->dma_dac.swptr);
+                stop_dac(s);
+                set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.numfrag << s->dma_dac.fragshift);
+                s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0;
+            }
+            if (signal_pending(current)) {
+                if (!ret) ret = -ERESTARTSYS;
+                goto out;
+            }
+            continue;
+        }
+        spin_unlock_irqrestore(&s->lock, flags);
+        if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) {
+            if (!ret) ret = -EFAULT;
+            return ret;
+        }
+        spin_lock_irqsave(&s->lock, flags);
+        DPRINTK(DPSYS,"wrote %6d bytes at sw: %6d cnt: %6d while hw: %6d\n",
+                cnt, swptr, s->dma_dac.count, s->dma_dac.hwptr);
+        
+        swptr = (swptr + cnt) % s->dma_dac.dmasize;
+
+        s->dma_dac.swptr = swptr;
+        s->dma_dac.count += cnt;
+        s->dma_dac.endcleared = 0;
+        count -= cnt;
+        buffer += cnt;
+        ret += cnt;
+        start_dac(s);
+    }
+out:
+    spin_unlock_irqrestore(&s->lock, flags);
+    return ret;
+}
+
+static unsigned int ess_poll(struct file *file, struct poll_table_struct *wait)
+{
+    struct ess_state *s = (struct ess_state *)file->private_data;
+    unsigned long flags;
+    unsigned int mask = 0;
+
+    VALIDATE_STATE(s);
+    if (file->f_mode & FMODE_WRITE)
+        poll_wait(file, &s->dma_dac.wait, wait);
+    if (file->f_mode & FMODE_READ)
+        poll_wait(file, &s->dma_adc.wait, wait);
+
+    spin_lock_irqsave(&s->lock, flags);
+    ess_update_ptr(s);
+
+    if (file->f_mode & FMODE_READ) {
+        if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
+            mask |= POLLIN | POLLRDNORM;
+    }
+    if (file->f_mode & FMODE_WRITE) {
+        if (s->dma_dac.mapped) {
+            if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) 
+                mask |= POLLOUT | POLLWRNORM;
+        } else {
+            if ((signed)s->dma_dac.dmasize >= s->dma_dac.count + (signed)s->dma_dac.fragsize)
+                mask |= POLLOUT | POLLWRNORM;
+        }
+    }
+
+    spin_unlock_irqrestore(&s->lock, flags);
+    return mask;
+}
+
+static int ess_mmap(struct file *file, struct vm_area_struct *vma)
+{
+    struct ess_state *s = (struct ess_state *)file->private_data;
+    struct dmabuf *db;
+    int ret;
+    unsigned long size;
+
+    VALIDATE_STATE(s);
+    if (vma->vm_flags & VM_WRITE) {
+        if ((ret = prog_dmabuf(s, 1)) != 0)
+            return ret;
+        db = &s->dma_dac;
+    } else 
+    if (vma->vm_flags & VM_READ) {
+        if ((ret = prog_dmabuf(s, 0)) != 0)
+            return ret;
+        db = &s->dma_adc;
+    } else  
+        return -EINVAL;
+    if (SILLY_OFFSET(vma) != 0)
+        return -EINVAL;
+    size = vma->vm_end - vma->vm_start;
+    if (size > (PAGE_SIZE << db->buforder))
+        return -EINVAL;
+    if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot))
+        return -EAGAIN;
+    db->mapped = 1;
+    return 0;
+}
+
+/*
+ * god, what an absolute mess..
+ * not all the paths through here are
+ * properly locked.  
+ *   *sob*
+ */
+static int ess_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+    struct ess_state *s = (struct ess_state *)file->private_data;
+    unsigned long flags;
+    audio_buf_info abinfo;
+    count_info cinfo;
+    int val, mapped, ret;
+    unsigned char fmtm, fmtd;
+
+    VALIDATE_STATE(s);
+
+    mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
+        ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
+
+    DPRINTK(DPSYS,"ess_ioctl: cmd %d\n", cmd);
+
+    switch (cmd) {
+    case OSS_GETVERSION:
+        return put_user(SOUND_VERSION, (int *)arg);
+
+    case SNDCTL_DSP_SYNC:
+        if (file->f_mode & FMODE_WRITE)
+            return drain_dac(s, file->f_flags & O_NONBLOCK);
+        return 0;
+        
+    case SNDCTL_DSP_SETDUPLEX:
+        /* XXX fix */
+        return 0;
+
+    case SNDCTL_DSP_GETCAPS:
+        return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg);
+        
+    case SNDCTL_DSP_RESET:
+        spin_lock_irqsave(&s->lock, flags);
+        if (file->f_mode & FMODE_WRITE) {
+            stop_dac(s);
+            synchronize_irq();
+            s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0;
+        }
+        if (file->f_mode & FMODE_READ) {
+            stop_adc(s);
+            synchronize_irq();
+            s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
+        }
+        spin_unlock_irqrestore(&s->lock, flags);
+        return 0;
+
+    case SNDCTL_DSP_SPEED:
+        get_user_ret(val, (int *)arg, -EFAULT);
+        spin_lock_irqsave(&s->lock, flags);
+        if (val >= 0) {
+            if (file->f_mode & FMODE_READ) {
+                stop_adc(s);
+                s->dma_adc.ready = 0;
+                set_adc_rate(s, val);
+            }
+            if (file->f_mode & FMODE_WRITE) {
+                stop_dac(s);
+                s->dma_dac.ready = 0;
+                set_dac_rate(s, val);
+            }
+        }
+        spin_unlock_irqrestore(&s->lock, flags);
+        return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg);
+        
+    case SNDCTL_DSP_STEREO:
+        get_user_ret(val, (int *)arg, -EFAULT);
+        spin_lock_irqsave(&s->lock, flags);
+        fmtd = 0;
+        fmtm = ~0;
+        if (file->f_mode & FMODE_READ) {
+            stop_adc(s);
+            s->dma_adc.ready = 0;
+            if (val)
+                fmtd |= ESS_FMT_STEREO << ESS_ADC_SHIFT;
+            else
+                fmtm &= ~(ESS_FMT_STEREO << ESS_ADC_SHIFT);
+        }
+        if (file->f_mode & FMODE_WRITE) {
+            stop_dac(s);
+            s->dma_dac.ready = 0;
+            if (val)
+                fmtd |= ESS_FMT_STEREO << ESS_DAC_SHIFT;
+            else
+                fmtm &= ~(ESS_FMT_STEREO << ESS_DAC_SHIFT);
+        }
+        set_fmt(s, fmtm, fmtd);
+        spin_unlock_irqrestore(&s->lock, flags);
+        return 0;
+
+    case SNDCTL_DSP_CHANNELS:
+        get_user_ret(val, (int *)arg, -EFAULT);
+        spin_lock_irqsave(&s->lock, flags);
+        if (val != 0) {
+            fmtd = 0;
+            fmtm = ~0;
+            if (file->f_mode & FMODE_READ) {
+                stop_adc(s);
+                s->dma_adc.ready = 0;
+                if (val >= 2)
+                    fmtd |= ESS_FMT_STEREO << ESS_ADC_SHIFT;
+                else
+                    fmtm &= ~(ESS_FMT_STEREO << ESS_ADC_SHIFT);
+            }
+            if (file->f_mode & FMODE_WRITE) {
+                stop_dac(s);
+                s->dma_dac.ready = 0;
+                if (val >= 2)
+                    fmtd |= ESS_FMT_STEREO << ESS_DAC_SHIFT;
+                else
+                    fmtm &= ~(ESS_FMT_STEREO << ESS_DAC_SHIFT);
+            }
+            set_fmt(s, fmtm, fmtd);
+        }
+        spin_unlock_irqrestore(&s->lock, flags);
+        return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_STEREO << ESS_ADC_SHIFT) 
+                       : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, (int *)arg);
+        
+    case SNDCTL_DSP_GETFMTS: /* Returns a mask */
+        return put_user(AFMT_U8|AFMT_S16_LE, (int *)arg);
+        
+    case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
+        get_user_ret(val, (int *)arg, -EFAULT);
+        spin_lock_irqsave(&s->lock, flags);
+        if (val != AFMT_QUERY) {
+            fmtd = 0;
+            fmtm = ~0;
+            if (file->f_mode & FMODE_READ) {
+                stop_adc(s);
+                s->dma_adc.ready = 0;
+                if (val == AFMT_S16_LE)
+                    fmtd |= ESS_FMT_16BIT << ESS_ADC_SHIFT;
+                else
+                    fmtm &= ~(ESS_FMT_16BIT << ESS_ADC_SHIFT);
+            }
+            if (file->f_mode & FMODE_WRITE) {
+                stop_dac(s);
+                s->dma_dac.ready = 0;
+                if (val == AFMT_S16_LE)
+                    fmtd |= ESS_FMT_16BIT << ESS_DAC_SHIFT;
+                else
+                    fmtm &= ~(ESS_FMT_16BIT << ESS_DAC_SHIFT);
+            }
+            set_fmt(s, fmtm, fmtd);
+        }
+        spin_unlock_irqrestore(&s->lock, flags);
+        return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? 
+            (ESS_FMT_16BIT << ESS_ADC_SHIFT) 
+            : (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ? 
+                AFMT_S16_LE : 
+                AFMT_U8, 
+            (int *)arg);
+        
+    case SNDCTL_DSP_POST:
+        return 0;
+
+    case SNDCTL_DSP_GETTRIGGER:
+        val = 0;
+        if ((file->f_mode & FMODE_READ) && (s->enable & ADC_RUNNING))
+            val |= PCM_ENABLE_INPUT;
+        if ((file->f_mode & FMODE_WRITE) && (s->enable & DAC_RUNNING)) 
+            val |= PCM_ENABLE_OUTPUT;
+        return put_user(val, (int *)arg);
+        
+    case SNDCTL_DSP_SETTRIGGER:
+        get_user_ret(val, (int *)arg, -EFAULT);
+        if (file->f_mode & FMODE_READ) {
+            if (val & PCM_ENABLE_INPUT) {
+                if (!s->dma_adc.ready && (ret =  prog_dmabuf(s, 1)))
+                    return ret;
+                start_adc(s);
+            } else
+                stop_adc(s);
+        }
+        if (file->f_mode & FMODE_WRITE) {
+            if (val & PCM_ENABLE_OUTPUT) {
+                if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
+                    return ret;
+                start_dac(s);
+            } else
+                stop_dac(s);
+        }
+        return 0;
+
+    case SNDCTL_DSP_GETOSPACE:
+        if (!(file->f_mode & FMODE_WRITE))
+            return -EINVAL;
+        if (!(s->enable & DAC_RUNNING) && (val = prog_dmabuf(s, 0)) != 0)
+            return val;
+        spin_lock_irqsave(&s->lock, flags);
+        ess_update_ptr(s);
+        abinfo.fragsize = s->dma_dac.fragsize;
+        abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count;
+        abinfo.fragstotal = s->dma_dac.numfrag;
+        abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;      
+        spin_unlock_irqrestore(&s->lock, flags);
+        return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+
+    case SNDCTL_DSP_GETISPACE:
+        if (!(file->f_mode & FMODE_READ))
+            return -EINVAL;
+        if (!(s->enable & ADC_RUNNING) && (val = prog_dmabuf(s, 1)) != 0)
+            return val;
+        spin_lock_irqsave(&s->lock, flags);
+        ess_update_ptr(s);
+        abinfo.fragsize = s->dma_adc.fragsize;
+        abinfo.bytes = s->dma_adc.count;
+        abinfo.fragstotal = s->dma_adc.numfrag;
+        abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;      
+        spin_unlock_irqrestore(&s->lock, flags);
+        return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+        
+    case SNDCTL_DSP_NONBLOCK:
+        file->f_flags |= O_NONBLOCK;
+        return 0;
+
+    case SNDCTL_DSP_GETODELAY:
+        if (!(file->f_mode & FMODE_WRITE))
+            return -EINVAL;
+        spin_lock_irqsave(&s->lock, flags);
+        ess_update_ptr(s);
+        val = s->dma_dac.count;
+        spin_unlock_irqrestore(&s->lock, flags);
+        return put_user(val, (int *)arg);
+
+    case SNDCTL_DSP_GETIPTR:
+        if (!(file->f_mode & FMODE_READ))
+            return -EINVAL;
+        spin_lock_irqsave(&s->lock, flags);
+        ess_update_ptr(s);
+        cinfo.bytes = s->dma_adc.total_bytes;
+        cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
+        cinfo.ptr = s->dma_adc.hwptr;
+        if (s->dma_adc.mapped)
+            s->dma_adc.count &= s->dma_adc.fragsize-1;
+        spin_unlock_irqrestore(&s->lock, flags);
+        return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+
+    case SNDCTL_DSP_GETOPTR:
+        if (!(file->f_mode & FMODE_WRITE))
+            return -EINVAL;
+        spin_lock_irqsave(&s->lock, flags);
+        ess_update_ptr(s);
+        cinfo.bytes = s->dma_dac.total_bytes;
+        cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift;
+        cinfo.ptr = s->dma_dac.hwptr;
+        if (s->dma_dac.mapped)
+            s->dma_dac.count &= s->dma_dac.fragsize-1;
+        spin_unlock_irqrestore(&s->lock, flags);
+        return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
+
+    case SNDCTL_DSP_GETBLKSIZE:
+        if (file->f_mode & FMODE_WRITE) {
+            if ((val = prog_dmabuf(s, 0)))
+                return val;
+            return put_user(s->dma_dac.fragsize, (int *)arg);
+        }
+        if ((val = prog_dmabuf(s, 1)))
+            return val;
+        return put_user(s->dma_adc.fragsize, (int *)arg);
+
+    case SNDCTL_DSP_SETFRAGMENT:
+        get_user_ret(val, (int *)arg, -EFAULT);
+        spin_lock_irqsave(&s->lock, flags);
+        if (file->f_mode & FMODE_READ) {
+            s->dma_adc.ossfragshift = val & 0xffff;
+            s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
+            if (s->dma_adc.ossfragshift < 4)
+                s->dma_adc.ossfragshift = 4;
+            if (s->dma_adc.ossfragshift > 15)
+                s->dma_adc.ossfragshift = 15;
+            if (s->dma_adc.ossmaxfrags < 4)
+                s->dma_adc.ossmaxfrags = 4;
+        }
+        if (file->f_mode & FMODE_WRITE) {
+            s->dma_dac.ossfragshift = val & 0xffff;
+            s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
+            if (s->dma_dac.ossfragshift < 4)
+                s->dma_dac.ossfragshift = 4;
+            if (s->dma_dac.ossfragshift > 15)
+                s->dma_dac.ossfragshift = 15;
+            if (s->dma_dac.ossmaxfrags < 4)
+                s->dma_dac.ossmaxfrags = 4;
+        }
+        spin_unlock_irqrestore(&s->lock, flags);
+        return 0;
+
+    case SNDCTL_DSP_SUBDIVIDE:
+        if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
+            (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
+            return -EINVAL;
+
+        get_user_ret(val, (int *)arg, -EFAULT);
+
+        if (val != 1 && val != 2 && val != 4)
+            return -EINVAL;
+        if (file->f_mode & FMODE_READ)
+            s->dma_adc.subdivision = val;
+        if (file->f_mode & FMODE_WRITE)
+            s->dma_dac.subdivision = val;
+        return 0;
+
+    case SOUND_PCM_READ_RATE:
+        return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg);
+
+    case SOUND_PCM_READ_CHANNELS:
+        return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_STEREO << ESS_ADC_SHIFT) 
+                       : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, (int *)arg);
+
+    case SOUND_PCM_READ_BITS:
+        return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_16BIT << ESS_ADC_SHIFT) 
+                       : (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ? 16 : 8, (int *)arg);
+
+    case SOUND_PCM_WRITE_FILTER:
+    case SNDCTL_DSP_SETSYNCRO:
+    case SOUND_PCM_READ_FILTER:
+        return -EINVAL;
+    }
+    return -EINVAL;
+}
+
+static int
+allocate_dmabuf(struct dmabuf *db)
+{
+    int order;
+    unsigned long mapend,map;
+    void *rawbuf = NULL;
+
+    DPRINTK(DPSTR,"allocating for dmabuf %p\n", db);
+
+    /* 
+     * alloc as big a chunk as we can, start with 
+     * 64k 'cause we're insane.
+     */
+    for (order = 16-PAGE_SHIFT; order >= 1; order--)
+        /* XXX might be able to get rid of gfp_dma */
+        if((rawbuf = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA, order)))
+            break;
+
+    if (!rawbuf)
+        return 1;
+
+    /*
+     * can't cross a 64k boundry..
+     */
+    if( ((virt_to_bus(rawbuf) & 0xffff) + ((PAGE_SIZE << order) - 1)) > ~0xffff) {
+        printk(KERN_ERR PFX "DMA buffer crosses 64k: busaddr 0x%lx  size %ld\n",
+            virt_to_bus(rawbuf), PAGE_SIZE << order);
+        kfree(rawbuf);
+        free_pages((unsigned long)db->rawbuf,db->buforder);
+        return 1;
+    }
+
+    DPRINTK(DPSTR,"allocated %ld (%d) bytes at %p\n",
+            PAGE_SIZE<<order, order, rawbuf);
+
+    /* now mark the pages as reserved; otherwise remap_page_range doesn't do what we want */
+    mapend = MAP_NR(rawbuf + (PAGE_SIZE << order) - 1);
+    for (map = MAP_NR(rawbuf); map <= mapend; map++) {
+        set_bit(PG_reserved, &mem_map[map].flags);
+    }
+
+    db->rawbuf = rawbuf;
+    db->buforder = order;
+    db->ready = 0;
+    db->mapped = 0;
+
+    return 0;
+}
+
+static void
+nuke_lists(struct ess_card *card, struct dmabuf *db)
+{
+    m3_remove_list(card, &(card->dma_list), db->dma_index);
+    m3_remove_list(card, &(card->msrc_list), db->msrc_index);
+    db->in_lists = 0;
+}
+
+static void
+free_dmabuf(struct dmabuf *db)
+{
+    unsigned long map, mapend;
+
+    DPRINTK(DPSTR,"freeing %p from dmabuf %p\n",db->rawbuf, db);
+
+    mapend = MAP_NR(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
+    for (map = MAP_NR(db->rawbuf); map <= mapend; map++)
+        clear_bit(PG_reserved, &mem_map[map].flags);    
+
+    free_pages((unsigned long)db->rawbuf,db->buforder);
+
+    db->rawbuf = NULL;
+    db->buforder = 0;
+    db->mapped = 0;
+    db->ready = 0;
+}
+
+static int 
+ess_open(struct inode *inode, struct file *file)
+{
+    int minor = MINOR(inode->i_rdev);
+    struct ess_card *c;
+    struct ess_state *s = NULL;
+    int i;
+    int ret = 0;
+    unsigned char fmtm = ~0, fmts = 0;
+    unsigned long flags;
+
+    /*
+     *    Scan the cards and find the channel. We only
+     *    do this at open time so it is ok
+     */
+    for(c = devs ; c != NULL ; c = c->next) {
+
+        for(i=0;i<NR_DSPS;i++) {
+
+            if(c->channels[i].dev_audio < 0)
+                continue;
+            if((c->channels[i].dev_audio ^ minor) & ~0xf)
+                continue;
+
+            s = &c->channels[i];
+            break;
+        }
+    }
+        
+    if (!s)
+        return -ENODEV;
+        
+    VALIDATE_STATE(s);
+
+    file->private_data = s;
+
+    /* wait for device to become free */
+    down(&s->open_sem);
+    while (s->open_mode & file->f_mode) {
+        if (file->f_flags & O_NONBLOCK) {
+            up(&s->open_sem);
+            return -EWOULDBLOCK;
+        }
+        up(&s->open_sem);
+        interruptible_sleep_on(&s->open_wait);
+        if (signal_pending(current))
+            return -ERESTARTSYS;
+        down(&s->open_sem);
+    }
+
+    spin_lock_irqsave(&s->lock, flags);
+
+    if (file->f_mode & FMODE_READ) {
+        if(allocate_dmabuf(&(s->dma_adc)))  {
+            ret = -ENOMEM;
+            goto out;
+        }
+        fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_ADC_SHIFT);
+        if ((minor & 0xf) == SND_DEV_DSP16)
+            fmts |= ESS_FMT_16BIT << ESS_ADC_SHIFT; 
+
+        s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
+        set_adc_rate(s, 8000);
+    }
+    if (file->f_mode & FMODE_WRITE) {
+        if(allocate_dmabuf(&(s->dma_dac)))  {
+            ret = -ENOMEM;
+            goto out;
+        }
+
+        fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_DAC_SHIFT);
+        if ((minor & 0xf) == SND_DEV_DSP16)
+            fmts |= ESS_FMT_16BIT << ESS_DAC_SHIFT;
+
+        s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
+        set_dac_rate(s, 8000);
+    }
+    set_fmt(s, fmtm, fmts);
+    s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
+
+    MOD_INC_USE_COUNT;
+out:
+    spin_unlock_irqrestore(&s->lock, flags);
+    up(&s->open_sem);
+    return ret;
+}
+
+static int 
+ess_release(struct inode *inode, struct file *file)
+{
+    struct ess_state *s = (struct ess_state *)file->private_data;
+    unsigned long flags;
+
+    VALIDATE_STATE(s);
+    if (file->f_mode & FMODE_WRITE)
+        drain_dac(s, file->f_flags & O_NONBLOCK);
+
+    down(&s->open_sem);
+    spin_lock_irqsave(&s->lock, flags);
+
+    if (file->f_mode & FMODE_WRITE) {
+        stop_dac(s);
+        if(s->dma_dac.in_lists) {
+            m3_remove_list(s->card, &(s->card->mixer_list), s->dma_dac.mixer_index);
+            nuke_lists(s->card, &(s->dma_dac));
+        }
+        free_dmabuf(&(s->dma_dac));
+    }
+    if (file->f_mode & FMODE_READ) {
+        stop_adc(s);
+        if(s->dma_adc.in_lists) {
+            m3_remove_list(s->card, &(s->card->adc1_list), s->dma_adc.adc1_index);
+            nuke_lists(s->card, &(s->dma_adc));
+        }
+        free_dmabuf(&(s->dma_adc));
+    }
+        
+    s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
+
+    spin_unlock_irqrestore(&s->lock, flags);
+    up(&s->open_sem);
+    wake_up(&s->open_wait);
+
+    MOD_DEC_USE_COUNT;
+    return 0;
+}
+
+/*
+ * Wait for the ac97 serial bus to be free.
+ * return nonzero if the bus is still busy.
+ */
+static int m3_ac97_wait(struct ess_card *card)
+{
+    int i = 10000;
+
+    while( (m3_inb(card, 0x30) & 1) && i--) ;
+
+    return i == 0;
+}
+
+u16 m3_ac97_read(struct ac97_codec *codec, u8 reg)
+{
+    u16 ret = 0;
+    struct ess_card *card = codec->private_data;
+
+    spin_lock(&card->ac97_lock);
+
+    if(m3_ac97_wait(card)) {
+        printk(KERN_ERR PFX "serial bus busy reading reg 0x%x\n",reg);
+        goto out;
+    }
+
+    m3_outb(card, 0x80 | (reg & 0x7f), 0x30);
+
+    if(m3_ac97_wait(card)) {
+        printk(KERN_ERR PFX "serial bus busy finishing read reg 0x%x\n",reg);
+        goto out;
+    }
+
+    ret =  m3_inw(card, 0x32);
+    DPRINTK(DPCRAP,"reading 0x%04x from 0x%02x\n",ret, reg);
+
+out:
+    spin_unlock(&card->ac97_lock);
+    return ret;
+}
+
+void m3_ac97_write(struct ac97_codec *codec, u8 reg, u16 val)
+{
+    struct ess_card *card = codec->private_data;
+
+    spin_lock(&card->ac97_lock);
+
+    if(m3_ac97_wait(card)) {
+        printk(KERN_ERR PFX "serial bus busy writing 0x%x to 0x%x\n",val, reg);
+        goto out;
+    }
+    DPRINTK(DPCRAP,"writing 0x%04x  to  0x%02x\n", val, reg);
+
+    m3_outw(card, val, 0x32);
+    m3_outb(card, reg & 0x7f, 0x30);
+out:
+    spin_unlock(&card->ac97_lock);
+}
+/* OSS /dev/mixer file operation methods */
+static int m3_open_mixdev(struct inode *inode, struct file *file)
+{
+    int minor = MINOR(inode->i_rdev);
+    struct ess_card *card = devs;
+
+    MOD_INC_USE_COUNT;
+    for (card = devs; card != NULL; card = card->next) {
+        if((card->ac97 != NULL) && (card->ac97->dev_mixer == minor))
+                break;
+    }
+
+    if (!card) {
+        MOD_DEC_USE_COUNT;
+        return -ENODEV;
+    }
+
+    file->private_data = card->ac97;
+
+    return 0;
+}
+
+static int m3_release_mixdev(struct inode *inode, struct file *file)
+{
+    MOD_DEC_USE_COUNT;
+    return 0;
+}
+
+static int m3_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
+                                    unsigned long arg)
+{
+    struct ac97_codec *codec = (struct ac97_codec *)file->private_data;
+
+    return codec->mixer_ioctl(codec, cmd, arg);
+}
+
+static /*const*/ struct file_operations m3_mixer_fops = {
+llseek:         m3_llseek,
+ioctl:          m3_ioctl_mixdev,
+open:           m3_open_mixdev,
+release:        m3_release_mixdev,
+};
+
+void remote_codec_config(int io, int isremote)
+{
+    isremote = isremote ? 1 : 0;
+
+    outw(  (inw(io + RING_BUS_CTRL_B) & ~SECOND_CODEC_ID_MASK) | isremote,
+            io + RING_BUS_CTRL_B);
+    outw(  (inw(io + SDO_OUT_DEST_CTRL) & ~COMMAND_ADDR_OUT) | isremote,
+            io + SDO_OUT_DEST_CTRL);
+    outw(  (inw(io + SDO_IN_DEST_CTRL) & ~STATUS_ADDR_IN) | isremote,
+            io + SDO_IN_DEST_CTRL);
+}
+
+/* 
+ * hack, returns non zero on err 
+ */
+static int try_read_vendor(struct ess_card *card)
+{
+    u16 ret;
+
+    if(m3_ac97_wait(card)) 
+        return 1;
+
+    m3_outb(card, 0x80 | (AC97_VENDOR_ID1 & 0x7f), 0x30);
+
+    if(m3_ac97_wait(card)) 
+        return 1;
+
+    ret =  m3_inw(card, 0x32);
+
+    return (ret == 0) || (ret == 0xffff);
+}
+
+static void m3_codec_reset(struct ess_card *card, int busywait)
+{
+    u16 dir;
+    int delay1 = 0, delay2 = 0, i;
+    int io = card->iobase;
+
+    switch (card->card_type) {
+        /*
+         * the onboard codec on the allegro seems 
+         * to want to wait a very long time before
+         * coming back to life 
+         */
+        case ESS_ALLEGRO:
+            delay1 = 50;
+            delay2 = 800;
+        break;
+        case ESS_MAESTRO3:
+            delay1 = 20;
+            delay2 = 500;
+        break;
+    }
+
+    for(i = 0; i < 5; i ++) {
+        dir = inw(io + GPIO_DIRECTION);
+        dir |= 0x10; /* assuming pci bus master? */
+
+        remote_codec_config(io, 0);
+
+        outw(IO_SRAM_ENABLE, io + RING_BUS_CTRL_A);
+        udelay(20);
+
+        outw(dir & ~GPO_PRIMARY_AC97 , io + GPIO_DIRECTION);
+        outw(~GPO_PRIMARY_AC97 , io + GPIO_MASK);
+        outw(0, io + GPIO_DATA);
+        outw(dir | GPO_PRIMARY_AC97, io + GPIO_DIRECTION);
+
+        if(busywait)  {
+            mdelay(delay1);
+        } else {
+            current->state = TASK_UNINTERRUPTIBLE;
+            schedule_timeout((delay1 * HZ) / 1000);
+        }
+
+        outw(GPO_PRIMARY_AC97, io + GPIO_DATA);
+        udelay(5);
+        /* ok, bring back the ac-link */
+        outw(IO_SRAM_ENABLE | SERIAL_AC_LINK_ENABLE, io + RING_BUS_CTRL_A);
+        outw(~0, io + GPIO_MASK);
+
+        if(busywait) {
+            mdelay(delay2);
+        } else {
+            current->state = TASK_UNINTERRUPTIBLE;
+            schedule_timeout((delay2 * HZ) / 1000);
+        }
+        if(! try_read_vendor(card))
+            break;
+
+        delay1 += 10;
+        delay2 += 100;
+
+        DPRINTK(DPMOD, "retrying codec reset with delays of %d and %d ms\n",
+                delay1, delay2);
+    }
+
+#if 0
+    /* more gung-ho reset that doesn't
+     * seem to work anywhere :)
+     */
+    tmp = inw(io + RING_BUS_CTRL_A);
+    outw(RAC_SDFS_ENABLE|LAC_SDFS_ENABLE, io + RING_BUS_CTRL_A);
+    mdelay(20);
+    outw(tmp, io + RING_BUS_CTRL_A);
+    mdelay(50);
+#endif
+}
+
+static int __init m3_codec_install(struct ess_card *card)
+{
+    struct ac97_codec *codec;
+
+    if ((codec = kmalloc(sizeof(struct ac97_codec), GFP_KERNEL)) == NULL)
+        return -ENOMEM;
+    memset(codec, 0, sizeof(struct ac97_codec));
+
+    codec->private_data = card;
+    codec->codec_read = m3_ac97_read;
+    codec->codec_write = m3_ac97_write;
+
+    if (ac97_probe_codec(codec) == 0) {
+        printk(KERN_ERR PFX "codec probe failed\n");
+        kfree(codec);
+        return -1;
+    }
+
+    if ((codec->dev_mixer = register_sound_mixer(&m3_mixer_fops, -1)) < 0) {
+        printk(KERN_ERR PFX "couldn't register mixer!\n");
+        kfree(codec);
+        return -1;
+    }
+
+    card->ac97 = codec;
+
+    return 0;
+}
+
+
+#define MINISRC_LPF_LEN 10
+static u16 minisrc_lpf[MINISRC_LPF_LEN] = {
+    0X0743, 0X1104, 0X0A4C, 0XF88D, 0X242C,
+    0X1023, 0X1AA9, 0X0B60, 0XEFDD, 0X186F
+};
+static void m3_assp_init(struct ess_card *card)
+{
+    int i;
+
+    /* zero kernel data */
+    for(i = 0 ; i < (REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA) / 2; i++)
+        m3_assp_write(card, MEMTYPE_INTERNAL_DATA, 
+                KDATA_BASE_ADDR + i, 0);
+
+    /* zero mixer data? */
+    for(i = 0 ; i < (REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA) / 2; i++)
+        m3_assp_write(card, MEMTYPE_INTERNAL_DATA, 
+                KDATA_BASE_ADDR2 + i, 0);
+
+    /* init dma pointer */
+    m3_assp_write(card, MEMTYPE_INTERNAL_DATA, 
+            KDATA_CURRENT_DMA, 
+            KDATA_DMA_XFER0);
+
+    /* write kernel into code memory.. */
+    for(i = 0 ; i < sizeof(assp_kernel_image) / 2; i++) {
+        m3_assp_write(card, MEMTYPE_INTERNAL_CODE, 
+                REV_B_CODE_MEMORY_BEGIN + i, 
+                assp_kernel_image[i]);
+    }
+
+    /*
+     * We only have this one client and we know that 0x400
+     * is free in our kernel's mem map, so lets just
+     * drop it there.  It seems that the minisrc doesn't
+     * need vectors, so we won't bother with them..
+     */
+    for(i = 0 ; i < sizeof(assp_minisrc_image) / 2; i++) {
+        m3_assp_write(card, MEMTYPE_INTERNAL_CODE, 
+                0x400 + i, 
+                assp_minisrc_image[i]);
+    }
+
+    /*
+     * write the coefficients for the low pass filter?
+     */
+    for(i = 0; i < MINISRC_LPF_LEN ; i++) {
+        m3_assp_write(card, MEMTYPE_INTERNAL_CODE,
+            0x400 + MINISRC_COEF_LOC + i,
+            minisrc_lpf[i]);
+    }
+
+    m3_assp_write(card, MEMTYPE_INTERNAL_CODE,
+        0x400 + MINISRC_COEF_LOC + MINISRC_LPF_LEN,
+        0x8000);
+
+    /*
+     * the minisrc is the only thing on
+     * our task list..
+     */
+    m3_assp_write(card, MEMTYPE_INTERNAL_DATA, 
+            KDATA_TASK0, 
+            0x400);
+
+    /*
+     * init the mixer number..
+     */
+
+    m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+            KDATA_MIXER_TASK_NUMBER,0);
+
+    /*
+     * EXTREME KERNEL MASTER VOLUME
+     */
+    m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+        KDATA_DAC_LEFT_VOLUME, ARB_VOLUME);
+    m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+        KDATA_DAC_RIGHT_VOLUME, ARB_VOLUME);
+
+    card->mixer_list.mem_addr = KDATA_MIXER_XFER0;
+    card->mixer_list.max = MAX_VIRTUAL_MIXER_CHANNELS;
+    card->adc1_list.mem_addr = KDATA_ADC1_XFER0;
+    card->adc1_list.max = MAX_VIRTUAL_ADC1_CHANNELS;
+    card->dma_list.mem_addr = KDATA_DMA_XFER0;
+    card->dma_list.max = MAX_VIRTUAL_DMA_CHANNELS;
+    card->msrc_list.mem_addr = KDATA_INSTANCE0_MINISRC;
+    card->msrc_list.max = MAX_INSTANCE_MINISRC;
+}
+
+static int setup_msrc(struct ess_card *card,
+        struct assp_instance *inst, int index)
+{
+    int data_bytes = 2 * ( MINISRC_TMP_BUFFER_SIZE / 2 + 
+            MINISRC_IN_BUFFER_SIZE / 2 +
+            1 + MINISRC_OUT_BUFFER_SIZE / 2 + 1 );
+    int address, i;
+
+    /*
+     * the revb memory map has 0x1100 through 0x1c00
+     * free.  
+     */
+
+    /*
+     * align instance mem so that the shifted list
+     * addresses are aligned.
+     */
+    data_bytes = (data_bytes + 255) & ~255;
+    address = 0x1100 + ((data_bytes/2) * index);
+
+    if((address + (data_bytes/2)) >= 0x1c00) {
+        printk(KERN_ERR PFX "no memory for %d bytes at ind %d (addr 0x%x)\n",
+                data_bytes, index, address);
+        return -1;
+    }
+
+    for(i = 0; i < data_bytes/2 ; i++) 
+        m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
+                address + i, 0);
+
+    inst->code = 0x400;
+    inst->data = address;
+
+    return 0;
+}
+
+static int m3_assp_client_init(struct ess_state *s)
+{
+    setup_msrc(s->card, &(s->dac_inst), s->index * 2);
+    setup_msrc(s->card, &(s->adc_inst), (s->index * 2) + 1);
+
+    return 0;
+}
+
+static void
+m3_amp_enable(struct ess_card *card, int enable)
+{
+    /* 
+     * this works for the reference board, have to find
+     * out about others
+     *
+     * this needs more magic for 4 speaker, but..
+     */
+    int io = card->iobase;
+    u16 gpo, polarity_port, polarity;
+
+    if(!external_amp)
+        return;
+
+    switch (card->card_type) {
+        case ESS_ALLEGRO:
+            polarity_port = 0x1800;
+            break;
+        default:
+            /* presumably this is for all 'maestro3's.. */
+            polarity_port = 0x1100;
+            break;
+    }
+
+    gpo = (polarity_port >> 8) & 0x0F;
+    polarity = polarity_port >> 12;
+    if ( enable )
+        polarity = !polarity;
+    polarity = polarity << gpo;
+    gpo = 1 << gpo;
+
+    outw(~gpo , io + GPIO_MASK);
+
+    outw( inw(io + GPIO_DIRECTION) | gpo ,
+            io + GPIO_DIRECTION);
+
+    outw( (GPO_SECONDARY_AC97 | GPO_PRIMARY_AC97 | polarity) ,
+            io + GPIO_DATA);
+
+    outw(0xffff , io + GPIO_MASK);
+}
+
+static int
+maestro_config(struct ess_card *card) 
+{
+    struct pci_dev *pcidev = card->pcidev;
+    u32 n;
+    u8  t; /* makes as much sense as 'n', no? */
+
+    pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n);
+    n &= REDUCED_DEBOUNCE;
+    n |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING;
+    pci_write_config_dword(pcidev, PCI_ALLEGRO_CONFIG, n);
+
+    outb(RESET_ASSP, card->iobase + ASSP_CONTROL_B);
+    pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n);
+    n &= ~INT_CLK_SELECT;
+    if(card->card_type == ESS_MAESTRO3)  {
+        n &= ~INT_CLK_MULT_ENABLE; 
+        n |= INT_CLK_SRC_NOT_PCI;
+    }
+    n &=  ~( CLK_MULT_MODE_SELECT | CLK_MULT_MODE_SELECT_2 );
+    pci_write_config_dword(pcidev, PCI_ALLEGRO_CONFIG, n);
+
+    if(card->card_type <= ESS_ALLEGRO) {
+        pci_read_config_dword(pcidev, PCI_USER_CONFIG, &n);
+        n |= IN_CLK_12MHZ_SELECT;
+        pci_write_config_dword(pcidev, PCI_USER_CONFIG, n);
+    }
+
+    t = inb(card->iobase + ASSP_CONTROL_A);
+    t &= ~( DSP_CLK_36MHZ_SELECT  | ASSP_CLK_49MHZ_SELECT);
+    switch(global_dsp_speed) {
+        case 33:
+            break;
+        case 36:
+            t |= DSP_CLK_36MHZ_SELECT;
+            break;
+        case 49:
+            t |= ASSP_CLK_49MHZ_SELECT;
+            break;
+    }
+    t |= ASSP_0_WS_ENABLE; 
+    outb(t, card->iobase + ASSP_CONTROL_A);
+
+    outb(RUN_ASSP, card->iobase + ASSP_CONTROL_B); 
+
+    return 0;
+} 
+
+static void
+m3_enable_ints(struct ess_card *card)
+{
+    unsigned long io = card->iobase;
+
+    outw(ASSP_INT_ENABLE, io + HOST_INT_CTRL);
+    outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE,
+            io + ASSP_CONTROL_C);
+}
+
+static struct file_operations ess_audio_fops = {
+    &m3_llseek,
+    &ess_read,
+    &ess_write,
+    NULL,  /* readdir */
+    &ess_poll,
+    &ess_ioctl,
+    &ess_mmap,
+    &ess_open,
+    NULL,    /* flush */
+    &ess_release,
+    NULL,  /* fsync */
+    NULL,  /* fasync */
+    NULL,  /* check_media_change */
+    NULL,  /* revalidate */
+    NULL,  /* lock */
+};
+
+#ifdef CONFIG_APM
+int alloc_dsp_savemem(struct ess_card *card)
+{
+    int len = sizeof(u16) * (REV_B_CODE_MEMORY_LENGTH + REV_B_DATA_MEMORY_LENGTH);
+
+    if( (card->suspend_dsp_mem = vmalloc(len)) == NULL)
+        return 1;
+
+    return 0;
+}
+void free_dsp_savemem(struct ess_card *card)
+{
+   if(card->suspend_dsp_mem)
+       vfree(card->suspend_dsp_mem);
+}
+
+#else
+#define alloc_dsp_savemem(args...) 0
+#define free_dsp_savemem(args...) 
+#endif
+
+/*
+ * great day!  this function is ugly as hell.
+ */
+static int 
+maestro_install(struct pci_dev *pcidev, struct card_type *ct)
+{
+    u32 n;
+    int i;
+    int iobase;
+    struct ess_card *card = NULL;
+    int num = 0;
+
+    /* don't pick up modems */
+    if(((pcidev->class >> 8) & 0xffff) != PCI_CLASS_MULTIMEDIA_AUDIO)
+        return 1;
+
+    DPRINTK(DPMOD, "in maestro_install\n");
+
+    iobase = SILLY_PCI_BASE_ADDRESS(pcidev); 
+
+    if(check_region(iobase, 256))
+    {
+        printk(KERN_WARNING PFX "can't allocate 256 bytes I/O at 0x%4.4x\n", iobase);
+        return 1;
+    }
+    /* stake our claim on the iospace */
+    request_region(iobase, 256, ct->name);
+
+    /* this was tripping up some machines */
+    if(pcidev->irq == 0) 
+        printk(KERN_WARNING PFX "pci subsystem reports irq 0, this might not be correct.\n");
+
+    /* just to be sure */
+    pci_set_master(pcidev);
+
+    card = kmalloc(sizeof(struct ess_card), GFP_KERNEL);
+    if(card == NULL)
+    {
+        printk(KERN_WARNING PFX "out of memory\n");
+        release_region(card->iobase, 256);        
+        return 1;
+    }
+
+    memset(card, 0, sizeof(*card));
+    card->pcidev = pcidev;
+
+    if(alloc_dsp_savemem(card)) {
+        printk(KERN_WARNING PFX "couldn't alloc %d bytes for saving dsp state on suspend\n",
+                REV_B_CODE_MEMORY_LENGTH + REV_B_DATA_MEMORY_LENGTH);
+        release_region(card->iobase, 256);
+        free_dsp_savemem(card);
+        kfree(card);
+        return 1;
+    }
+
+    if (register_reboot_notifier(&maestro_nb)) {
+        printk(KERN_WARNING PFX "reboot notifier registration failed\n");
+        release_region(card->iobase, 256);        
+        free_dsp_savemem(card);
+        kfree(card);
+        return 1;
+    }
+
+    card->iobase = iobase;
+    card->card_type = ct->type;
+    card->irq = pcidev->irq;
+    card->next = devs;
+    card->magic = M3_CARD_MAGIC;
+    spin_lock_init(&card->lock);
+    spin_lock_init(&card->ac97_lock);
+    devs = card;
+
+    printk(KERN_INFO PFX "Configuring %s found at IO 0x%04X IRQ %d\n", 
+        ct->name,iobase,card->irq);
+    pci_read_config_dword(pcidev, PCI_SUBSYSTEM_VENDOR_ID, &n);
+    printk(KERN_INFO PFX " subvendor id: 0x%08x\n",n); 
+
+    maestro_config(card);
+    m3_assp_halt(card);
+
+    m3_codec_reset(card, 0);
+
+    if(m3_codec_install(card))  {
+        unregister_reboot_notifier(&maestro_nb);
+        release_region(card->iobase, 256);        
+        free_dsp_savemem(card);
+        kfree(card);
+        return 1;
+    }
+
+    m3_assp_init(card);
+    m3_amp_enable(card, 1);
+    
+    for(i=0;i<NR_DSPS;i++)
+    {
+        struct ess_state *s=&card->channels[i];
+
+        s->index = i;
+
+        s->card = card;
+        init_waitqueue_head(&s->dma_adc.wait);
+        init_waitqueue_head(&s->dma_dac.wait);
+        init_waitqueue_head(&s->open_wait);
+        spin_lock_init(&s->lock);
+        SILLY_INIT_SEM(s->open_sem);
+        s->magic = M3_STATE_MAGIC;
+
+        m3_assp_client_init(s);
+        
+        if(s->dma_adc.ready || s->dma_dac.ready || s->dma_adc.rawbuf)
+            printk("maestro: BOTCH!\n");
+        /* register devices */
+        if ((s->dev_audio = register_sound_dsp(&ess_audio_fops, -1)) < 0)
+            break;
+    }
+    
+    num = i;
+    
+    /* clear the rest if we ran out of slots to register */
+    for(;i<NR_DSPS;i++)
+    {
+        struct ess_state *s=&card->channels[i];
+        s->dev_audio = -1;
+    }
+
+    
+    if(request_irq(card->irq, ess_interrupt, SA_SHIRQ, ct->name, card))
+    {
+        printk(KERN_ERR PFX "unable to allocate irq %d,\n", card->irq);
+        for(i=0;i<NR_DSPS;i++)
+        {
+            struct ess_state *s = &card->channels[i];
+            if(s->dev_audio != -1)
+                unregister_sound_dsp(s->dev_audio);
+        }
+        unregister_reboot_notifier(&maestro_nb);
+        unregister_sound_mixer(card->ac97->dev_mixer);
+        kfree(card->ac97);
+        release_region(card->iobase, 256);        
+        free_dsp_savemem(card);
+        kfree(card);
+        return 1;
+    }
+
+#ifdef CONFIG_APM
+    if (apm_register_callback(m3_apm_callback)) {
+        printk(KERN_WARNING PFX "couldn't register apm callback, suspend/resume might not work.\n");
+    }
+#endif
+
+    m3_enable_ints(card);
+    m3_assp_continue(card);
+
+    printk(KERN_INFO PFX "%d channels configured.\n", num);
+
+    return 0; 
+}
+
+#ifdef MODULE
+int init_module(void)
+#else
+SILLY_MAKE_INIT(int init_maestro3(void))
+#endif
+{
+    struct pci_dev *pcidev = NULL;
+    int found = 0;
+    int i;
+
+    if (!pci_present())   /* No PCI bus in this machine! */
+        return -ENODEV;
+
+    printk(KERN_INFO PFX "version " DRIVER_VERSION " built at " __TIME__ " " __DATE__ "\n");
+
+    switch(global_dsp_speed) {
+        case 33: case 36: case 49:
+            break;
+        default:
+            printk(KERN_INFO PFX "invalid global_dsp_speed: %d, must be 33, 36, or 49.\n",
+                    global_dsp_speed);
+            return -EINVAL;
+            break;
+    }
+
+#ifdef CONFIG_APM
+    init_waitqueue_head(&suspend_queue);
+#endif
+
+    for(i = 0; i < NUM_CARD_TYPES; i++) {
+        struct card_type *ct = &m3_card_types[i];
+
+        pcidev = NULL;
+        while( (pcidev = pci_find_device(PCI_VENDOR_ESS, ct->pci_id, pcidev)) != NULL ) {
+            if (! maestro_install(pcidev, ct))
+                found++;
+        }
+    }
+
+    printk(KERN_INFO PFX "%d maestros installed.\n",found);
+
+    if(found == 0 ) 
+        return -ENODEV;
+
+    return 0;
+}
+
+void nuke_maestros(void)
+{
+    struct ess_card *card;
+
+    unregister_reboot_notifier(&maestro_nb);
+#ifdef CONFIG_APM
+    apm_unregister_callback(m3_apm_callback);
+#endif
+
+    while ((card = devs)) {
+        int i;
+        devs = devs->next;
+    
+        free_irq(card->irq, card);
+        unregister_sound_mixer(card->ac97->dev_mixer);
+        kfree(card->ac97);
+
+        for(i=0;i<NR_DSPS;i++)
+        {
+            struct ess_state *ess = &card->channels[i];
+            if(ess->dev_audio != -1)
+                unregister_sound_dsp(ess->dev_audio);
+        }
+
+        release_region(card->iobase, 256);
+        free_dsp_savemem(card);
+        kfree(card);
+    }
+    devs = NULL;
+}
+
+static int maestro_notifier(struct notifier_block *nb, unsigned long event, void *buf)
+{
+    /* this notifier is called when the kernel is really shut down. */
+    DPRINTK(DPMOD,"shutting down\n");
+    nuke_maestros();
+    return NOTIFY_OK;
+}
+
+/* --------------------------------------------------------------------- */
+
+#ifdef MODULE
+MODULE_AUTHOR("Zach Brown <zab@zabbo.net>");
+MODULE_DESCRIPTION("ESS Maestro3/Allegro Driver");
+#ifdef M_DEBUG
+MODULE_PARM(debug,"i");
+MODULE_PARM(global_dsp_speed,"i");
+#endif
+MODULE_PARM(external_amp,"i");
+
+void cleanup_module(void) {
+    DPRINTK(DPMOD,"unloading\n");
+    nuke_maestros();
+}
+
+#endif /* MODULE */
+
+#ifdef CONFIG_APM
+void
+check_suspend(void)
+{
+    DECLARE_WAITQUEUE(wait, current);
+
+    if(!in_suspend) 
+        return;
+
+    in_suspend++;
+    add_wait_queue(&suspend_queue, &wait);
+    current->state = TASK_UNINTERRUPTIBLE;
+    schedule();
+    remove_wait_queue(&suspend_queue, &wait);
+    current->state = TASK_RUNNING;
+}
+
+static int 
+m3_suspend(void)
+{
+    struct ess_card *card;
+    unsigned long flags;
+    int index;
+
+    save_flags(flags);
+    cli();
+
+    for (card = devs; card ; card = card->next) {
+        int i;
+
+        DPRINTK(DPMOD, "apm in dev %p\n",card);
+
+        for(i=0;i<NR_DSPS;i++) {
+            struct ess_state *s = &card->channels[i];
+
+            if(s->dev_audio == -1)
+                continue;
+
+            DPRINTK(DPMOD, "stop_adc/dac() device %d\n",i);
+            stop_dac(s);
+            stop_adc(s);
+        }
+
+        mdelay(10); /* give the assp a chance to idle.. */
+
+        m3_assp_halt(card);
+
+        index = 0;
+        DPRINTK(DPMOD, "saving code\n");
+        for(i = REV_B_CODE_MEMORY_BEGIN ; i <= REV_B_CODE_MEMORY_END; i++)
+            card->suspend_dsp_mem[index++] = 
+                m3_assp_read(card, MEMTYPE_INTERNAL_CODE, i);
+        DPRINTK(DPMOD, "saving data\n");
+        for(i = REV_B_DATA_MEMORY_BEGIN ; i <= REV_B_DATA_MEMORY_END; i++)
+            card->suspend_dsp_mem[index++] = 
+                m3_assp_read(card, MEMTYPE_INTERNAL_DATA, i);
+
+        DPRINTK(DPMOD, "powering down apci regs\n");
+        m3_outw(card, 0xffff, 0x54);
+        m3_outw(card, 0xffff, 0x56);
+    }
+    in_suspend=1;
+
+    restore_flags(flags);
+
+    return 0;
+}
+
+static int 
+m3_resume(void)
+{
+    struct ess_card *card;
+    unsigned long flags;
+    int index;
+
+    save_flags(flags); /* paranoia */
+    cli();
+    in_suspend=0;
+
+    DPRINTK(DPMOD, "resuming\n");
+
+    /* first lets just bring everything back. .*/
+    for (card = devs; card ; card = card->next) {
+        int i;
+
+        DPRINTK(DPMOD, "bringing power back on card 0x%p\n",card);
+        m3_outw(card, 0, 0x54);
+        m3_outw(card, 0, 0x56);
+
+        DPRINTK(DPMOD, "restoring pci configs and reseting codec\n");
+        maestro_config(card);
+        m3_assp_halt(card);
+        m3_codec_reset(card, 1);
+
+        DPRINTK(DPMOD, "restoring dsp code\n");
+        index = 0;
+        for(i = REV_B_CODE_MEMORY_BEGIN ; i <= REV_B_CODE_MEMORY_END; i++)
+            m3_assp_write(card, MEMTYPE_INTERNAL_CODE, i, 
+                card->suspend_dsp_mem[index++]);
+        for(i = REV_B_DATA_MEMORY_BEGIN ; i <= REV_B_DATA_MEMORY_END; i++)
+            m3_assp_write(card, MEMTYPE_INTERNAL_DATA, i, 
+                card->suspend_dsp_mem[index++]);
+
+         /* tell the dma engine to restart itself */
+        m3_assp_write(card, MEMTYPE_INTERNAL_DATA, 
+                KDATA_DMA_ACTIVE, 0);
+
+        DPRINTK(DPMOD, "resuming dsp\n");
+        m3_assp_continue(card);
+
+        DPRINTK(DPMOD, "enabling ints\n");
+        m3_enable_ints(card);
+
+        /* bring back the old school flavor */
+        for(i = 0; i < SOUND_MIXER_NRDEVICES ; i++) {
+            int state = card->ac97->mixer_state[i];
+            if (!supported_mixer(card->ac97, i)) 
+                continue;
+
+            card->ac97->write_mixer(card->ac97, i, 
+                    state & 0xff, (state >> 8) & 0xff);
+        }
+
+        m3_amp_enable(card, 1);
+    }
+
+    /* 
+     * now we flip on the music 
+     */
+    for (card = devs; card ; card = card->next) {
+        int i;
+
+
+        for(i=0;i<NR_DSPS;i++) {
+            struct ess_state *s = &card->channels[i];
+            if(s->dev_audio == -1)
+                continue;
+            /*
+             * db->ready makes it so these guys can be
+             * called unconditionally..
+             */
+            DPRINTK(DPMOD, "turning on dacs ind %d\n",i);
+            start_dac(s);    
+            start_adc(s);    
+        }
+    }
+
+    restore_flags(flags);
+
+    /* 
+     * all right, we think things are ready, 
+     * wake up people who were using the device 
+     * when we suspended
+     */
+    wake_up(&suspend_queue);
+
+    return 0;
+}
+
+int 
+m3_apm_callback(apm_event_t ae) {
+
+    DPRINTK(DPMOD, "APM event received: 0x%x\n",ae);
+
+    switch(ae) {
+        case APM_SYS_SUSPEND: 
+        case APM_CRITICAL_SUSPEND: 
+        case APM_USER_SUSPEND: 
+
+            m3_suspend();
+            break;
+
+        case APM_NORMAL_RESUME: 
+        case APM_CRITICAL_RESUME: 
+        case APM_STANDBY_RESUME: 
+
+            m3_resume();
+            break;
+
+        default: 
+            break;
+    }
+
+    return 0;
+}
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/maestro3.h linux.19p18/drivers/sound/maestro3.h
--- linux.vanilla/drivers/sound/maestro3.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/sound/maestro3.h	Wed Jan  3 01:01:13 2001
@@ -0,0 +1,821 @@
+/*
+ *      ESS Technology allegro audio driver.
+ *
+ *      Copyright (C) 1992-2000  Don Kim (don.kim@esstech.com)
+ *
+ *      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.
+ *
+ *      Hacked for the maestro3 driver by zab
+ */
+
+// Allegro PCI configuration registers
+#define PCI_LEGACY_AUDIO_CTRL   0x40
+#define SOUND_BLASTER_ENABLE    0x00000001
+#define FM_SYNTHESIS_ENABLE     0x00000002
+#define GAME_PORT_ENABLE        0x00000004
+#define MPU401_IO_ENABLE        0x00000008
+#define MPU401_IRQ_ENABLE       0x00000010
+#define ALIAS_10BIT_IO          0x00000020
+#define SB_DMA_MASK             0x000000C0
+#define SB_DMA_0                0x00000040
+#define SB_DMA_1                0x00000040
+#define SB_DMA_R                0x00000080
+#define SB_DMA_3                0x000000C0
+#define SB_IRQ_MASK             0x00000700
+#define SB_IRQ_5                0x00000000
+#define SB_IRQ_7                0x00000100
+#define SB_IRQ_9                0x00000200
+#define SB_IRQ_10               0x00000300
+#define MIDI_IRQ_MASK           0x00003800
+#define SERIAL_IRQ_ENABLE       0x00004000
+#define DISABLE_LEGACY          0x00008000
+
+#define PCI_ALLEGRO_CONFIG      0x50
+#define SB_ADDR_240             0x00000004
+#define MPU_ADDR_MASK           0x00000018
+#define MPU_ADDR_330            0x00000000
+#define MPU_ADDR_300            0x00000008
+#define MPU_ADDR_320            0x00000010
+#define MPU_ADDR_340            0x00000018
+#define USE_PCI_TIMING          0x00000040
+#define POSTED_WRITE_ENABLE     0x00000080
+#define DMA_POLICY_MASK         0x00000700
+#define DMA_DDMA                0x00000000
+#define DMA_TDMA                0x00000100
+#define DMA_PCPCI               0x00000200
+#define DMA_WBDMA16             0x00000400
+#define DMA_WBDMA4              0x00000500
+#define DMA_WBDMA2              0x00000600
+#define DMA_WBDMA1              0x00000700
+#define DMA_SAFE_GUARD          0x00000800
+#define HI_PERF_GP_ENABLE       0x00001000
+#define PIC_SNOOP_MODE_0        0x00002000
+#define PIC_SNOOP_MODE_1        0x00004000
+#define SOUNDBLASTER_IRQ_MASK   0x00008000
+#define RING_IN_ENABLE          0x00010000
+#define SPDIF_TEST_MODE         0x00020000
+#define CLK_MULT_MODE_SELECT_2  0x00040000
+#define EEPROM_WRITE_ENABLE     0x00080000
+#define CODEC_DIR_IN            0x00100000
+#define HV_BUTTON_FROM_GD       0x00200000
+#define REDUCED_DEBOUNCE        0x00400000
+#define HV_CTRL_ENABLE          0x00800000
+#define SPDIF_ENABLE            0x01000000
+#define CLK_DIV_SELECT          0x06000000
+#define CLK_DIV_BY_48           0x00000000
+#define CLK_DIV_BY_49           0x02000000
+#define CLK_DIV_BY_50           0x04000000
+#define CLK_DIV_RESERVED        0x06000000
+#define PM_CTRL_ENABLE          0x08000000
+#define CLK_MULT_MODE_SELECT    0x30000000
+#define CLK_MULT_MODE_SHIFT     28
+#define CLK_MULT_MODE_0         0x00000000
+#define CLK_MULT_MODE_1         0x10000000
+#define CLK_MULT_MODE_2         0x20000000
+#define CLK_MULT_MODE_3         0x30000000
+#define INT_CLK_SELECT          0x40000000
+#define INT_CLK_MULT_RESET      0x80000000
+
+// M3
+#define INT_CLK_SRC_NOT_PCI     0x00100000
+#define INT_CLK_MULT_ENABLE     0x80000000
+
+#define PCI_ACPI_CONTROL        0x54
+#define PCI_ACPI_D0             0x00000000
+#define PCI_ACPI_D1             0xB4F70000
+#define PCI_ACPI_D2             0xB4F7B4F7
+
+#define PCI_USER_CONFIG         0x58
+#define EXT_PCI_MASTER_ENABLE   0x00000001
+#define SPDIF_OUT_SELECT        0x00000002
+#define TEST_PIN_DIR_CTRL       0x00000004
+#define AC97_CODEC_TEST         0x00000020
+#define TRI_STATE_BUFFER        0x00000080
+#define IN_CLK_12MHZ_SELECT     0x00000100
+#define MULTI_FUNC_DISABLE      0x00000200
+#define EXT_MASTER_PAIR_SEL     0x00000400
+#define PCI_MASTER_SUPPORT      0x00000800
+#define STOP_CLOCK_ENABLE       0x00001000
+#define EAPD_DRIVE_ENABLE       0x00002000
+#define REQ_TRI_STATE_ENABLE    0x00004000
+#define REQ_LOW_ENABLE          0x00008000
+#define MIDI_1_ENABLE           0x00010000
+#define MIDI_2_ENABLE           0x00020000
+#define SB_AUDIO_SYNC           0x00040000
+#define HV_CTRL_TEST            0x00100000
+#define SOUNDBLASTER_TEST       0x00400000
+
+#define PCI_USER_CONFIG_C       0x5C
+
+#define PCI_DDMA_CTRL           0x60
+#define DDMA_ENABLE             0x00000001
+
+
+// Allegro registers
+#define HOST_INT_CTRL           0x18
+#define SB_INT_ENABLE           0x0001
+#define MPU401_INT_ENABLE       0x0002
+#define ASSP_INT_ENABLE         0x0010
+#define RING_INT_ENABLE         0x0020
+#define HV_INT_ENABLE           0x0040
+#define CLKRUN_GEN_ENABLE       0x0100
+#define HV_CTRL_TO_PME          0x0400
+#define SOFTWARE_RESET_ENABLE   0x8000
+
+/*
+ * should be using the above defines, probably.
+ */
+#define REGB_ENABLE_RESET               0x01
+#define REGB_STOP_CLOCK                 0x10
+
+#define HOST_INT_STATUS         0x1A
+#define SB_INT_PENDING          0x01
+#define MPU401_INT_PENDING      0x02
+#define ASSP_INT_PENDING        0x10
+#define RING_INT_PENDING        0x20
+#define HV_INT_PENDING          0x40
+
+#define HARDWARE_VOL_CTRL       0x1B
+#define SHADOW_MIX_REG_VOICE    0x1C
+#define HW_VOL_COUNTER_VOICE    0x1D
+#define SHADOW_MIX_REG_MASTER   0x1E
+#define HW_VOL_COUNTER_MASTER   0x1F
+
+#define CODEC_COMMAND           0x30
+#define CODEC_READ_B            0x80
+
+#define CODEC_STATUS            0x30
+#define CODEC_BUSY_B            0x01
+
+#define CODEC_DATA              0x32
+
+#define RING_BUS_CTRL_A         0x36
+#define RAC_PME_ENABLE          0x0100
+#define RAC_SDFS_ENABLE         0x0200
+#define LAC_PME_ENABLE          0x0400
+#define LAC_SDFS_ENABLE         0x0800
+#define SERIAL_AC_LINK_ENABLE   0x1000
+#define IO_SRAM_ENABLE          0x2000
+#define IIS_INPUT_ENABLE        0x8000
+
+#define RING_BUS_CTRL_B         0x38
+#define SECOND_CODEC_ID_MASK    0x0003
+#define SPDIF_FUNC_ENABLE       0x0010
+#define SECOND_AC_ENABLE        0x0020
+#define SB_MODULE_INTF_ENABLE   0x0040
+#define SSPE_ENABLE             0x0040
+#define M3I_DOCK_ENABLE         0x0080
+
+#define SDO_OUT_DEST_CTRL       0x3A
+#define COMMAND_ADDR_OUT        0x0003
+#define PCM_LR_OUT_LOCAL        0x0000
+#define PCM_LR_OUT_REMOTE       0x0004
+#define PCM_LR_OUT_MUTE         0x0008
+#define PCM_LR_OUT_BOTH         0x000C
+#define LINE1_DAC_OUT_LOCAL     0x0000
+#define LINE1_DAC_OUT_REMOTE    0x0010
+#define LINE1_DAC_OUT_MUTE      0x0020
+#define LINE1_DAC_OUT_BOTH      0x0030
+#define PCM_CLS_OUT_LOCAL       0x0000
+#define PCM_CLS_OUT_REMOTE      0x0040
+#define PCM_CLS_OUT_MUTE        0x0080
+#define PCM_CLS_OUT_BOTH        0x00C0
+#define PCM_RLF_OUT_LOCAL       0x0000
+#define PCM_RLF_OUT_REMOTE      0x0100
+#define PCM_RLF_OUT_MUTE        0x0200
+#define PCM_RLF_OUT_BOTH        0x0300
+#define LINE2_DAC_OUT_LOCAL     0x0000
+#define LINE2_DAC_OUT_REMOTE    0x0400
+#define LINE2_DAC_OUT_MUTE      0x0800
+#define LINE2_DAC_OUT_BOTH      0x0C00
+#define HANDSET_OUT_LOCAL       0x0000
+#define HANDSET_OUT_REMOTE      0x1000
+#define HANDSET_OUT_MUTE        0x2000
+#define HANDSET_OUT_BOTH        0x3000
+#define IO_CTRL_OUT_LOCAL       0x0000
+#define IO_CTRL_OUT_REMOTE      0x4000
+#define IO_CTRL_OUT_MUTE        0x8000
+#define IO_CTRL_OUT_BOTH        0xC000
+
+#define SDO_IN_DEST_CTRL        0x3C
+#define STATUS_ADDR_IN          0x0003
+#define PCM_LR_IN_LOCAL         0x0000
+#define PCM_LR_IN_REMOTE        0x0004
+#define PCM_LR_RESERVED         0x0008
+#define PCM_LR_IN_BOTH          0x000C
+#define LINE1_ADC_IN_LOCAL      0x0000
+#define LINE1_ADC_IN_REMOTE     0x0010
+#define LINE1_ADC_IN_MUTE       0x0020
+#define MIC_ADC_IN_LOCAL        0x0000
+#define MIC_ADC_IN_REMOTE       0x0040
+#define MIC_ADC_IN_MUTE         0x0080
+#define LINE2_DAC_IN_LOCAL      0x0000
+#define LINE2_DAC_IN_REMOTE     0x0400
+#define LINE2_DAC_IN_MUTE       0x0800
+#define HANDSET_IN_LOCAL        0x0000
+#define HANDSET_IN_REMOTE       0x1000
+#define HANDSET_IN_MUTE         0x2000
+#define IO_STATUS_IN_LOCAL      0x0000
+#define IO_STATUS_IN_REMOTE     0x4000
+
+#define SPDIF_IN_CTRL           0x3E
+#define SPDIF_IN_ENABLE         0x0001
+
+#define GPIO_DATA               0x60
+#define GPIO_DATA_MASK          0x0FFF
+#define GPIO_HV_STATUS          0x3000
+#define GPIO_PME_STATUS         0x4000
+
+#define GPIO_MASK               0x64
+#define GPIO_DIRECTION          0x68
+#define GPO_PRIMARY_AC97        0x0001
+#define GPI_LINEOUT_SENSE       0x0004
+#define GPO_SECONDARY_AC97      0x0008
+#define GPI_VOL_DOWN            0x0010
+#define GPI_VOL_UP              0x0020
+#define GPI_IIS_CLK             0x0040
+#define GPI_IIS_LRCLK           0x0080
+#define GPI_IIS_DATA            0x0100
+#define GPI_DOCKING_STATUS      0x0100
+#define GPI_HEADPHONE_SENSE     0x0200
+#define GPO_EXT_AMP_SHUTDOWN    0x1000
+
+// M3
+#define GPO_M3_EXT_AMP_SHUTDN   0x0002
+
+#define ASSP_INDEX_PORT         0x80
+#define ASSP_MEMORY_PORT        0x82
+#define ASSP_DATA_PORT          0x84
+
+#define MPU401_DATA_PORT        0x98
+#define MPU401_STATUS_PORT      0x99
+
+#define CLK_MULT_DATA_PORT      0x9C
+
+#define ASSP_CONTROL_A          0xA2
+#define ASSP_0_WS_ENABLE        0x01
+#define ASSP_CTRL_A_RESERVED1   0x02
+#define ASSP_CTRL_A_RESERVED2   0x04
+#define ASSP_CLK_49MHZ_SELECT   0x08
+#define FAST_PLU_ENABLE         0x10
+#define ASSP_CTRL_A_RESERVED3   0x20
+#define DSP_CLK_36MHZ_SELECT    0x40
+
+#define ASSP_CONTROL_B          0xA4
+#define RESET_ASSP              0x00
+#define RUN_ASSP                0x01
+#define ENABLE_ASSP_CLOCK       0x00
+#define STOP_ASSP_CLOCK         0x10
+#define RESET_TOGGLE            0x40
+
+#define ASSP_CONTROL_C          0xA6
+#define ASSP_HOST_INT_ENABLE    0x01
+#define FM_ADDR_REMAP_DISABLE   0x02
+#define HOST_WRITE_PORT_ENABLE  0x08
+
+#define ASSP_HOST_INT_STATUS    0xAC
+#define DSP2HOST_REQ_PIORECORD  0x01
+#define DSP2HOST_REQ_I2SRATE    0x02
+#define DSP2HOST_REQ_TIMER      0x04
+
+// AC97 registers
+// XXX fix this crap up
+/*#define AC97_RESET              0x00*/
+
+#define AC97_VOL_MUTE_B         0x8000
+#define AC97_VOL_M              0x1F
+#define AC97_LEFT_VOL_S         8
+
+#define AC97_MASTER_VOL         0x02
+#define AC97_LINE_LEVEL_VOL     0x04
+#define AC97_MASTER_MONO_VOL    0x06
+#define AC97_PC_BEEP_VOL        0x0A
+#define AC97_PC_BEEP_VOL_M      0x0F
+#define AC97_SROUND_MASTER_VOL  0x38
+#define AC97_PC_BEEP_VOL_S      1
+
+/*#define AC97_PHONE_VOL          0x0C
+#define AC97_MIC_VOL            0x0E*/
+#define AC97_MIC_20DB_ENABLE    0x40
+
+/*#define AC97_LINEIN_VOL         0x10
+#define AC97_CD_VOL             0x12
+#define AC97_VIDEO_VOL          0x14
+#define AC97_AUX_VOL            0x16*/
+#define AC97_PCM_OUT_VOL        0x18
+/*#define AC97_RECORD_SELECT      0x1A*/
+#define AC97_RECORD_MIC         0x00
+#define AC97_RECORD_CD          0x01
+#define AC97_RECORD_VIDEO       0x02
+#define AC97_RECORD_AUX         0x03
+#define AC97_RECORD_MONO_MUX    0x02
+#define AC97_RECORD_DIGITAL     0x03
+#define AC97_RECORD_LINE        0x04
+#define AC97_RECORD_STEREO      0x05
+#define AC97_RECORD_MONO        0x06
+#define AC97_RECORD_PHONE       0x07
+
+/*#define AC97_RECORD_GAIN        0x1C*/
+#define AC97_RECORD_VOL_M       0x0F
+
+/*#define AC97_GENERAL_PURPOSE    0x20*/
+#define AC97_POWER_DOWN_CTRL    0x26
+#define AC97_ADC_READY          0x0001
+#define AC97_DAC_READY          0x0002
+#define AC97_ANALOG_READY       0x0004
+#define AC97_VREF_ON            0x0008
+#define AC97_PR0                0x0100
+#define AC97_PR1                0x0200
+#define AC97_PR2                0x0400
+#define AC97_PR3                0x0800
+#define AC97_PR4                0x1000
+
+#define AC97_RESERVED1          0x28
+
+#define AC97_VENDOR_TEST        0x5A
+
+#define AC97_CLOCK_DELAY        0x5C
+#define AC97_LINEOUT_MUX_SEL    0x0001
+#define AC97_MONO_MUX_SEL       0x0002
+#define AC97_CLOCK_DELAY_SEL    0x1F
+#define AC97_DAC_CDS_SHIFT      6
+#define AC97_ADC_CDS_SHIFT      11
+
+#define AC97_MULTI_CHANNEL_SEL  0x74
+
+/*#define AC97_VENDOR_ID1         0x7C
+#define AC97_VENDOR_ID2         0x7E*/
+
+/*
+ * ASSP control regs
+ */
+#define DSP_PORT_TIMER_COUNT    0x06
+
+#define DSP_PORT_MEMORY_INDEX   0x80
+
+#define DSP_PORT_MEMORY_TYPE    0x82
+#define MEMTYPE_INTERNAL_CODE   0x0002
+#define MEMTYPE_INTERNAL_DATA   0x0003
+#define MEMTYPE_MASK            0x0003
+
+#define DSP_PORT_MEMORY_DATA    0x84
+
+#define DSP_PORT_CONTROL_REG_A  0xA2
+#define DSP_PORT_CONTROL_REG_B  0xA4
+#define DSP_PORT_CONTROL_REG_C  0xA6
+
+#define REV_A_CODE_MEMORY_BEGIN         0x0000
+#define REV_A_CODE_MEMORY_END           0x0FFF
+#define REV_A_CODE_MEMORY_UNIT_LENGTH   0x0040
+#define REV_A_CODE_MEMORY_LENGTH        (REV_A_CODE_MEMORY_END - REV_A_CODE_MEMORY_BEGIN + 1)
+
+#define REV_B_CODE_MEMORY_BEGIN         0x0000
+#define REV_B_CODE_MEMORY_END           0x0BFF
+#define REV_B_CODE_MEMORY_UNIT_LENGTH   0x0040
+#define REV_B_CODE_MEMORY_LENGTH        (REV_B_CODE_MEMORY_END - REV_B_CODE_MEMORY_BEGIN + 1)
+
+#define REV_A_DATA_MEMORY_BEGIN         0x1000
+#define REV_A_DATA_MEMORY_END           0x2FFF
+#define REV_A_DATA_MEMORY_UNIT_LENGTH   0x0080
+#define REV_A_DATA_MEMORY_LENGTH        (REV_A_DATA_MEMORY_END - REV_A_DATA_MEMORY_BEGIN + 1)
+
+#define REV_B_DATA_MEMORY_BEGIN         0x1000
+#define REV_B_DATA_MEMORY_END           0x2BFF
+#define REV_B_DATA_MEMORY_UNIT_LENGTH   0x0080
+#define REV_B_DATA_MEMORY_LENGTH        (REV_B_DATA_MEMORY_END - REV_B_DATA_MEMORY_BEGIN + 1)
+
+
+#define NUM_UNITS_KERNEL_CODE          16
+#define NUM_UNITS_KERNEL_DATA           2
+
+#define NUM_UNITS_KERNEL_CODE_WITH_HSP 16
+#define NUM_UNITS_KERNEL_DATA_WITH_HSP  5
+
+/*
+ * Kernel data layout
+ */
+
+#define DP_SHIFT_COUNT                  7
+
+#define KDATA_BASE_ADDR                 0x1000
+#define KDATA_BASE_ADDR2                0x1080
+
+#define KDATA_TASK0                     (KDATA_BASE_ADDR + 0x0000)
+#define KDATA_TASK1                     (KDATA_BASE_ADDR + 0x0001)
+#define KDATA_TASK2                     (KDATA_BASE_ADDR + 0x0002)
+#define KDATA_TASK3                     (KDATA_BASE_ADDR + 0x0003)
+#define KDATA_TASK4                     (KDATA_BASE_ADDR + 0x0004)
+#define KDATA_TASK5                     (KDATA_BASE_ADDR + 0x0005)
+#define KDATA_TASK6                     (KDATA_BASE_ADDR + 0x0006)
+#define KDATA_TASK7                     (KDATA_BASE_ADDR + 0x0007)
+#define KDATA_TASK_ENDMARK              (KDATA_BASE_ADDR + 0x0008)
+
+#define KDATA_CURRENT_TASK              (KDATA_BASE_ADDR + 0x0009)
+#define KDATA_TASK_SWITCH               (KDATA_BASE_ADDR + 0x000A)
+
+#define KDATA_INSTANCE0_POS3D           (KDATA_BASE_ADDR + 0x000B)
+#define KDATA_INSTANCE1_POS3D           (KDATA_BASE_ADDR + 0x000C)
+#define KDATA_INSTANCE2_POS3D           (KDATA_BASE_ADDR + 0x000D)
+#define KDATA_INSTANCE3_POS3D           (KDATA_BASE_ADDR + 0x000E)
+#define KDATA_INSTANCE4_POS3D           (KDATA_BASE_ADDR + 0x000F)
+#define KDATA_INSTANCE5_POS3D           (KDATA_BASE_ADDR + 0x0010)
+#define KDATA_INSTANCE6_POS3D           (KDATA_BASE_ADDR + 0x0011)
+#define KDATA_INSTANCE7_POS3D           (KDATA_BASE_ADDR + 0x0012)
+#define KDATA_INSTANCE8_POS3D           (KDATA_BASE_ADDR + 0x0013)
+#define KDATA_INSTANCE_POS3D_ENDMARK    (KDATA_BASE_ADDR + 0x0014)
+
+#define KDATA_INSTANCE0_SPKVIRT         (KDATA_BASE_ADDR + 0x0015)
+#define KDATA_INSTANCE_SPKVIRT_ENDMARK  (KDATA_BASE_ADDR + 0x0016)
+
+#define KDATA_INSTANCE0_SPDIF           (KDATA_BASE_ADDR + 0x0017)
+#define KDATA_INSTANCE_SPDIF_ENDMARK    (KDATA_BASE_ADDR + 0x0018)
+
+#define KDATA_INSTANCE0_MODEM           (KDATA_BASE_ADDR + 0x0019)
+#define KDATA_INSTANCE_MODEM_ENDMARK    (KDATA_BASE_ADDR + 0x001A)
+
+#define KDATA_INSTANCE0_SRC             (KDATA_BASE_ADDR + 0x001B)
+#define KDATA_INSTANCE1_SRC             (KDATA_BASE_ADDR + 0x001C)
+#define KDATA_INSTANCE_SRC_ENDMARK      (KDATA_BASE_ADDR + 0x001D)
+
+#define KDATA_INSTANCE0_MINISRC         (KDATA_BASE_ADDR + 0x001E)
+#define KDATA_INSTANCE1_MINISRC         (KDATA_BASE_ADDR + 0x001F)
+#define KDATA_INSTANCE2_MINISRC         (KDATA_BASE_ADDR + 0x0020)
+#define KDATA_INSTANCE3_MINISRC         (KDATA_BASE_ADDR + 0x0021)
+#define KDATA_INSTANCE_MINISRC_ENDMARK  (KDATA_BASE_ADDR + 0x0022)
+
+#define KDATA_INSTANCE0_CPYTHRU         (KDATA_BASE_ADDR + 0x0023)
+#define KDATA_INSTANCE1_CPYTHRU         (KDATA_BASE_ADDR + 0x0024)
+#define KDATA_INSTANCE_CPYTHRU_ENDMARK  (KDATA_BASE_ADDR + 0x0025)
+
+#define KDATA_CURRENT_DMA               (KDATA_BASE_ADDR + 0x0026)
+#define KDATA_DMA_SWITCH                (KDATA_BASE_ADDR + 0x0027)
+#define KDATA_DMA_ACTIVE                (KDATA_BASE_ADDR + 0x0028)
+
+#define KDATA_DMA_XFER0                 (KDATA_BASE_ADDR + 0x0029)
+#define KDATA_DMA_XFER1                 (KDATA_BASE_ADDR + 0x002A)
+#define KDATA_DMA_XFER2                 (KDATA_BASE_ADDR + 0x002B)
+#define KDATA_DMA_XFER3                 (KDATA_BASE_ADDR + 0x002C)
+#define KDATA_DMA_XFER4                 (KDATA_BASE_ADDR + 0x002D)
+#define KDATA_DMA_XFER5                 (KDATA_BASE_ADDR + 0x002E)
+#define KDATA_DMA_XFER6                 (KDATA_BASE_ADDR + 0x002F)
+#define KDATA_DMA_XFER7                 (KDATA_BASE_ADDR + 0x0030)
+#define KDATA_DMA_XFER8                 (KDATA_BASE_ADDR + 0x0031)
+#define KDATA_DMA_XFER_ENDMARK          (KDATA_BASE_ADDR + 0x0032)
+
+#define KDATA_I2S_SAMPLE_COUNT          (KDATA_BASE_ADDR + 0x0033)
+#define KDATA_I2S_INT_METER             (KDATA_BASE_ADDR + 0x0034)
+#define KDATA_I2S_ACTIVE                (KDATA_BASE_ADDR + 0x0035)
+
+#define KDATA_TIMER_COUNT_RELOAD        (KDATA_BASE_ADDR + 0x0036)
+#define KDATA_TIMER_COUNT_CURRENT       (KDATA_BASE_ADDR + 0x0037)
+
+#define KDATA_HALT_SYNCH_CLIENT         (KDATA_BASE_ADDR + 0x0038)
+#define KDATA_HALT_SYNCH_DMA            (KDATA_BASE_ADDR + 0x0039)
+#define KDATA_HALT_ACKNOWLEDGE          (KDATA_BASE_ADDR + 0x003A)
+
+#define KDATA_ADC1_XFER0                (KDATA_BASE_ADDR + 0x003B)
+#define KDATA_ADC1_XFER_ENDMARK         (KDATA_BASE_ADDR + 0x003C)
+#define KDATA_ADC1_LEFT_VOLUME			(KDATA_BASE_ADDR + 0x003D)
+#define KDATA_ADC1_RIGHT_VOLUME  		(KDATA_BASE_ADDR + 0x003E)
+#define KDATA_ADC1_LEFT_SUR_VOL			(KDATA_BASE_ADDR + 0x003F)
+#define KDATA_ADC1_RIGHT_SUR_VOL		(KDATA_BASE_ADDR + 0x0040)
+
+#define KDATA_ADC2_XFER0                (KDATA_BASE_ADDR + 0x0041)
+#define KDATA_ADC2_XFER_ENDMARK         (KDATA_BASE_ADDR + 0x0042)
+#define KDATA_ADC2_LEFT_VOLUME			(KDATA_BASE_ADDR + 0x0043)
+#define KDATA_ADC2_RIGHT_VOLUME			(KDATA_BASE_ADDR + 0x0044)
+#define KDATA_ADC2_LEFT_SUR_VOL			(KDATA_BASE_ADDR + 0x0045)
+#define KDATA_ADC2_RIGHT_SUR_VOL		(KDATA_BASE_ADDR + 0x0046)
+
+#define KDATA_CD_XFER0					(KDATA_BASE_ADDR + 0x0047)					
+#define KDATA_CD_XFER_ENDMARK			(KDATA_BASE_ADDR + 0x0048)
+#define KDATA_CD_LEFT_VOLUME			(KDATA_BASE_ADDR + 0x0049)
+#define KDATA_CD_RIGHT_VOLUME			(KDATA_BASE_ADDR + 0x004A)
+#define KDATA_CD_LEFT_SUR_VOL			(KDATA_BASE_ADDR + 0x004B)
+#define KDATA_CD_RIGHT_SUR_VOL			(KDATA_BASE_ADDR + 0x004C)
+
+#define KDATA_MIC_XFER0					(KDATA_BASE_ADDR + 0x004D)
+#define KDATA_MIC_XFER_ENDMARK			(KDATA_BASE_ADDR + 0x004E)
+#define KDATA_MIC_VOLUME				(KDATA_BASE_ADDR + 0x004F)
+#define KDATA_MIC_SUR_VOL				(KDATA_BASE_ADDR + 0x0050)
+
+#define KDATA_I2S_XFER0                 (KDATA_BASE_ADDR + 0x0051)
+#define KDATA_I2S_XFER_ENDMARK          (KDATA_BASE_ADDR + 0x0052)
+
+#define KDATA_CHI_XFER0                 (KDATA_BASE_ADDR + 0x0053)
+#define KDATA_CHI_XFER_ENDMARK          (KDATA_BASE_ADDR + 0x0054)
+
+#define KDATA_SPDIF_XFER                (KDATA_BASE_ADDR + 0x0055)
+#define KDATA_SPDIF_CURRENT_FRAME       (KDATA_BASE_ADDR + 0x0056)
+#define KDATA_SPDIF_FRAME0              (KDATA_BASE_ADDR + 0x0057)
+#define KDATA_SPDIF_FRAME1              (KDATA_BASE_ADDR + 0x0058)
+#define KDATA_SPDIF_FRAME2              (KDATA_BASE_ADDR + 0x0059)
+
+#define KDATA_SPDIF_REQUEST             (KDATA_BASE_ADDR + 0x005A)
+#define KDATA_SPDIF_TEMP                (KDATA_BASE_ADDR + 0x005B)
+
+#define KDATA_SPDIFIN_XFER0             (KDATA_BASE_ADDR + 0x005C)
+#define KDATA_SPDIFIN_XFER_ENDMARK      (KDATA_BASE_ADDR + 0x005D)
+#define KDATA_SPDIFIN_INT_METER         (KDATA_BASE_ADDR + 0x005E)
+
+#define KDATA_DSP_RESET_COUNT           (KDATA_BASE_ADDR + 0x005F)
+#define KDATA_DEBUG_OUTPUT              (KDATA_BASE_ADDR + 0x0060)
+
+#define KDATA_KERNEL_ISR_LIST           (KDATA_BASE_ADDR + 0x0061)
+
+#define KDATA_KERNEL_ISR_CBSR1          (KDATA_BASE_ADDR + 0x0062)
+#define KDATA_KERNEL_ISR_CBER1          (KDATA_BASE_ADDR + 0x0063)
+#define KDATA_KERNEL_ISR_CBCR           (KDATA_BASE_ADDR + 0x0064)
+#define KDATA_KERNEL_ISR_AR0            (KDATA_BASE_ADDR + 0x0065)
+#define KDATA_KERNEL_ISR_AR1            (KDATA_BASE_ADDR + 0x0066)
+#define KDATA_KERNEL_ISR_AR2            (KDATA_BASE_ADDR + 0x0067)
+#define KDATA_KERNEL_ISR_AR3            (KDATA_BASE_ADDR + 0x0068)
+#define KDATA_KERNEL_ISR_AR4            (KDATA_BASE_ADDR + 0x0069)
+#define KDATA_KERNEL_ISR_AR5            (KDATA_BASE_ADDR + 0x006A)
+#define KDATA_KERNEL_ISR_BRCR           (KDATA_BASE_ADDR + 0x006B)
+#define KDATA_KERNEL_ISR_PASR           (KDATA_BASE_ADDR + 0x006C)
+#define KDATA_KERNEL_ISR_PAER           (KDATA_BASE_ADDR + 0x006D)
+
+#define KDATA_CLIENT_SCRATCH0           (KDATA_BASE_ADDR + 0x006E)
+#define KDATA_CLIENT_SCRATCH1           (KDATA_BASE_ADDR + 0x006F)
+#define KDATA_KERNEL_SCRATCH            (KDATA_BASE_ADDR + 0x0070)
+#define KDATA_KERNEL_ISR_SCRATCH        (KDATA_BASE_ADDR + 0x0071)
+
+#define KDATA_OUEUE_LEFT                (KDATA_BASE_ADDR + 0x0072)
+#define KDATA_QUEUE_RIGHT               (KDATA_BASE_ADDR + 0x0073)
+
+#define KDATA_ADC1_REQUEST              (KDATA_BASE_ADDR + 0x0074)
+#define KDATA_ADC2_REQUEST              (KDATA_BASE_ADDR + 0x0075)
+#define KDATA_CD_REQUEST				(KDATA_BASE_ADDR + 0x0076)
+#define KDATA_MIC_REQUEST				(KDATA_BASE_ADDR + 0x0077)
+
+#define KDATA_ADC1_MIXER_REQUEST        (KDATA_BASE_ADDR + 0x0078)
+#define KDATA_ADC2_MIXER_REQUEST        (KDATA_BASE_ADDR + 0x0079)
+#define KDATA_CD_MIXER_REQUEST			(KDATA_BASE_ADDR + 0x007A)
+#define KDATA_MIC_MIXER_REQUEST			(KDATA_BASE_ADDR + 0x007B)
+#define KDATA_MIC_SYNC_COUNTER			(KDATA_BASE_ADDR + 0x007C)
+
+/*
+ * second 'segment' (?) reserved for mixer
+ * buffers..
+ */
+
+#define KDATA_MIXER_WORD0               (KDATA_BASE_ADDR2 + 0x0000)
+#define KDATA_MIXER_WORD1               (KDATA_BASE_ADDR2 + 0x0001)
+#define KDATA_MIXER_WORD2               (KDATA_BASE_ADDR2 + 0x0002)
+#define KDATA_MIXER_WORD3               (KDATA_BASE_ADDR2 + 0x0003)
+#define KDATA_MIXER_WORD4               (KDATA_BASE_ADDR2 + 0x0004)
+#define KDATA_MIXER_WORD5               (KDATA_BASE_ADDR2 + 0x0005)
+#define KDATA_MIXER_WORD6               (KDATA_BASE_ADDR2 + 0x0006)
+#define KDATA_MIXER_WORD7               (KDATA_BASE_ADDR2 + 0x0007)
+#define KDATA_MIXER_WORD8               (KDATA_BASE_ADDR2 + 0x0008)
+#define KDATA_MIXER_WORD9               (KDATA_BASE_ADDR2 + 0x0009)
+#define KDATA_MIXER_WORDA               (KDATA_BASE_ADDR2 + 0x000A)
+#define KDATA_MIXER_WORDB               (KDATA_BASE_ADDR2 + 0x000B)
+#define KDATA_MIXER_WORDC               (KDATA_BASE_ADDR2 + 0x000C)
+#define KDATA_MIXER_WORDD               (KDATA_BASE_ADDR2 + 0x000D)
+#define KDATA_MIXER_WORDE               (KDATA_BASE_ADDR2 + 0x000E)
+#define KDATA_MIXER_WORDF               (KDATA_BASE_ADDR2 + 0x000F)
+
+#define KDATA_MIXER_XFER0               (KDATA_BASE_ADDR2 + 0x0010)
+#define KDATA_MIXER_XFER1               (KDATA_BASE_ADDR2 + 0x0011)
+#define KDATA_MIXER_XFER2               (KDATA_BASE_ADDR2 + 0x0012)
+#define KDATA_MIXER_XFER3               (KDATA_BASE_ADDR2 + 0x0013)
+#define KDATA_MIXER_XFER4               (KDATA_BASE_ADDR2 + 0x0014)
+#define KDATA_MIXER_XFER5               (KDATA_BASE_ADDR2 + 0x0015)
+#define KDATA_MIXER_XFER6               (KDATA_BASE_ADDR2 + 0x0016)
+#define KDATA_MIXER_XFER7               (KDATA_BASE_ADDR2 + 0x0017)
+#define KDATA_MIXER_XFER8               (KDATA_BASE_ADDR2 + 0x0018)
+#define KDATA_MIXER_XFER9               (KDATA_BASE_ADDR2 + 0x0019)
+#define KDATA_MIXER_XFER_ENDMARK        (KDATA_BASE_ADDR2 + 0x001A)
+
+#define KDATA_MIXER_TASK_NUMBER         (KDATA_BASE_ADDR2 + 0x001B)
+#define KDATA_CURRENT_MIXER             (KDATA_BASE_ADDR2 + 0x001C)
+#define KDATA_MIXER_ACTIVE              (KDATA_BASE_ADDR2 + 0x001D)
+#define KDATA_MIXER_BANK_STATUS         (KDATA_BASE_ADDR2 + 0x001E)
+#define KDATA_DAC_LEFT_VOLUME	        (KDATA_BASE_ADDR2 + 0x001F)
+#define KDATA_DAC_RIGHT_VOLUME          (KDATA_BASE_ADDR2 + 0x0020)
+
+#define MAX_INSTANCE_MINISRC            (KDATA_INSTANCE_MINISRC_ENDMARK - KDATA_INSTANCE0_MINISRC)
+#define MAX_VIRTUAL_DMA_CHANNELS        (KDATA_DMA_XFER_ENDMARK - KDATA_DMA_XFER0)
+#define MAX_VIRTUAL_MIXER_CHANNELS      (KDATA_MIXER_XFER_ENDMARK - KDATA_MIXER_XFER0)
+#define MAX_VIRTUAL_ADC1_CHANNELS       (KDATA_ADC1_XFER_ENDMARK - KDATA_ADC1_XFER0)
+
+/*
+ * client data area offsets
+ */
+#define CDATA_INSTANCE_READY            0x00
+
+#define CDATA_HOST_SRC_ADDRL            0x01
+#define CDATA_HOST_SRC_ADDRH            0x02
+#define CDATA_HOST_SRC_END_PLUS_1L      0x03
+#define CDATA_HOST_SRC_END_PLUS_1H      0x04
+#define CDATA_HOST_SRC_CURRENTL         0x05
+#define CDATA_HOST_SRC_CURRENTH         0x06
+
+#define CDATA_IN_BUF_CONNECT            0x07
+#define CDATA_OUT_BUF_CONNECT           0x08
+
+#define CDATA_IN_BUF_BEGIN              0x09
+#define CDATA_IN_BUF_END_PLUS_1         0x0A
+#define CDATA_IN_BUF_HEAD               0x0B
+#define CDATA_IN_BUF_TAIL               0x0C
+#define CDATA_OUT_BUF_BEGIN             0x0D
+#define CDATA_OUT_BUF_END_PLUS_1        0x0E
+#define CDATA_OUT_BUF_HEAD              0x0F
+#define CDATA_OUT_BUF_TAIL              0x10
+
+#define CDATA_DMA_CONTROL               0x11
+#define CDATA_RESERVED                  0x12
+
+#define CDATA_FREQUENCY                 0x13
+#define CDATA_LEFT_VOLUME               0x14
+#define CDATA_RIGHT_VOLUME              0x15
+#define CDATA_LEFT_SUR_VOL              0x16
+#define CDATA_RIGHT_SUR_VOL             0x17
+
+#define CDATA_HEADER_LEN                0x18
+
+#define SRC3_DIRECTION_OFFSET           CDATA_HEADER_LEN
+#define SRC3_MODE_OFFSET                (CDATA_HEADER_LEN + 1)
+#define SRC3_WORD_LENGTH_OFFSET         (CDATA_HEADER_LEN + 2)
+#define SRC3_PARAMETER_OFFSET           (CDATA_HEADER_LEN + 3)
+#define SRC3_COEFF_ADDR_OFFSET          (CDATA_HEADER_LEN + 8)
+#define SRC3_FILTAP_ADDR_OFFSET         (CDATA_HEADER_LEN + 10)
+#define SRC3_TEMP_INBUF_ADDR_OFFSET     (CDATA_HEADER_LEN + 16)
+#define SRC3_TEMP_OUTBUF_ADDR_OFFSET    (CDATA_HEADER_LEN + 17)
+
+#define MINISRC_IN_BUFFER_SIZE   ( 0x50 * 2 )
+#define MINISRC_OUT_BUFFER_SIZE  ( 0x50 * 2 * 2)
+#define MINISRC_OUT_BUFFER_SIZE  ( 0x50 * 2 * 2)
+#define MINISRC_TMP_BUFFER_SIZE  ( 112 + ( MINISRC_BIQUAD_STAGE * 3 + 4 ) * 2 * 2 )
+#define MINISRC_BIQUAD_STAGE    2
+#define MINISRC_COEF_LOC          0X175
+
+#define DMACONTROL_BLOCK_MASK           0x000F
+#define  DMAC_BLOCK0_SELECTOR           0x0000
+#define  DMAC_BLOCK1_SELECTOR           0x0001
+#define  DMAC_BLOCK2_SELECTOR           0x0002
+#define  DMAC_BLOCK3_SELECTOR           0x0003
+#define  DMAC_BLOCK4_SELECTOR           0x0004
+#define  DMAC_BLOCK5_SELECTOR           0x0005
+#define  DMAC_BLOCK6_SELECTOR           0x0006
+#define  DMAC_BLOCK7_SELECTOR           0x0007
+#define  DMAC_BLOCK8_SELECTOR           0x0008
+#define  DMAC_BLOCK9_SELECTOR           0x0009
+#define  DMAC_BLOCKA_SELECTOR           0x000A
+#define  DMAC_BLOCKB_SELECTOR           0x000B
+#define  DMAC_BLOCKC_SELECTOR           0x000C
+#define  DMAC_BLOCKD_SELECTOR           0x000D
+#define  DMAC_BLOCKE_SELECTOR           0x000E
+#define  DMAC_BLOCKF_SELECTOR           0x000F
+#define DMACONTROL_PAGE_MASK            0x00F0
+#define  DMAC_PAGE0_SELECTOR            0x0030
+#define  DMAC_PAGE1_SELECTOR            0x0020
+#define  DMAC_PAGE2_SELECTOR            0x0010
+#define  DMAC_PAGE3_SELECTOR            0x0000
+#define DMACONTROL_AUTOREPEAT           0x1000
+#define DMACONTROL_STOPPED              0x2000
+#define DMACONTROL_DIRECTION            0x0100
+
+
+/*
+ * DSP Code images
+ */
+
+u16 assp_kernel_image[] = {
+    0x7980, 0x0030, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x00FB, 0x7980, 0x00DD, 0x7980, 0x03B4, 
+    0x7980, 0x0332, 0x7980, 0x0287, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4, 
+    0x7980, 0x031A, 0x7980, 0x03B4, 0x7980, 0x022F, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4, 
+    0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x0063, 0x7980, 0x006B, 0x7980, 0x03B4, 0x7980, 0x03B4, 
+    0xBF80, 0x2C7C, 0x8806, 0x8804, 0xBE40, 0xBC20, 0xAE09, 0x1000, 0xAE0A, 0x0001, 0x6938, 0xEB08, 
+    0x0053, 0x695A, 0xEB08, 0x00D6, 0x0009, 0x8B88, 0x6980, 0xE388, 0x0036, 0xBE30, 0xBC20, 0x6909, 
+    0xB801, 0x9009, 0xBE41, 0xBE41, 0x6928, 0xEB88, 0x0078, 0xBE41, 0xBE40, 0x7980, 0x0038, 0xBE41, 
+    0xBE41, 0x903A, 0x6938, 0xE308, 0x0056, 0x903A, 0xBE41, 0xBE40, 0xEF00, 0x903A, 0x6939, 0xE308, 
+    0x005E, 0x903A, 0xEF00, 0x690B, 0x660C, 0xEF8C, 0x690A, 0x660C, 0x620B, 0x6609, 0xEF00, 0x6910, 
+    0x660F, 0xEF04, 0xE388, 0x0075, 0x690E, 0x660F, 0x6210, 0x660D, 0xEF00, 0x690E, 0x660D, 0xEF00, 
+    0xAE70, 0x0001, 0xBC20, 0xAE27, 0x0001, 0x6939, 0xEB08, 0x005D, 0x6926, 0xB801, 0x9026, 0x0026, 
+    0x8B88, 0x6980, 0xE388, 0x00CB, 0x9028, 0x0D28, 0x4211, 0xE100, 0x007A, 0x4711, 0xE100, 0x00A0, 
+    0x7A80, 0x0063, 0xB811, 0x660A, 0x6209, 0xE304, 0x007A, 0x0C0B, 0x4005, 0x100A, 0xBA01, 0x9012, 
+    0x0C12, 0x4002, 0x7980, 0x00AF, 0x7A80, 0x006B, 0xBE02, 0x620E, 0x660D, 0xBA10, 0xE344, 0x007A, 
+    0x0C10, 0x4005, 0x100E, 0xBA01, 0x9012, 0x0C12, 0x4002, 0x1003, 0xBA02, 0x9012, 0x0C12, 0x4000, 
+    0x1003, 0xE388, 0x00BA, 0x1004, 0x7980, 0x00BC, 0x1004, 0xBA01, 0x9012, 0x0C12, 0x4001, 0x0C05, 
+    0x4003, 0x0C06, 0x4004, 0x1011, 0xBFB0, 0x01FF, 0x9012, 0x0C12, 0x4006, 0xBC20, 0xEF00, 0xAE26, 
+    0x1028, 0x6970, 0xBFD0, 0x0001, 0x9070, 0xE388, 0x007A, 0xAE28, 0x0000, 0xEF00, 0xAE70, 0x0300, 
+    0x0C70, 0xB00C, 0xAE5A, 0x0000, 0xEF00, 0x7A80, 0x038A, 0x697F, 0xB801, 0x907F, 0x0056, 0x8B88, 
+    0x0CA0, 0xB008, 0xAF71, 0xB000, 0x4E71, 0xE200, 0x00F3, 0xAE56, 0x1057, 0x0056, 0x0CA0, 0xB008, 
+    0x8056, 0x7980, 0x03A1, 0x0810, 0xBFA0, 0x1059, 0xE304, 0x03A1, 0x8056, 0x7980, 0x03A1, 0x7A80, 
+    0x038A, 0xBF01, 0xBE43, 0xBE59, 0x907C, 0x6937, 0xE388, 0x010D, 0xBA01, 0xE308, 0x010C, 0xAE71, 
+    0x0004, 0x0C71, 0x5000, 0x6936, 0x9037, 0xBF0A, 0x109E, 0x8B8A, 0xAF80, 0x8014, 0x4C80, 0xBF0A, 
+    0x0560, 0xF500, 0xBF0A, 0x0520, 0xB900, 0xBB17, 0x90A0, 0x6917, 0xE388, 0x0148, 0x0D17, 0xE100, 
+    0x0127, 0xBF0C, 0x0578, 0xBF0D, 0x057C, 0x7980, 0x012B, 0xBF0C, 0x0538, 0xBF0D, 0x053C, 0x6900, 
+    0xE308, 0x0135, 0x8B8C, 0xBE59, 0xBB07, 0x90A0, 0xBC20, 0x7980, 0x0157, 0x030C, 0x8B8B, 0xB903, 
+    0x8809, 0xBEC6, 0x013E, 0x69AC, 0x90AB, 0x69AD, 0x90AB, 0x0813, 0x660A, 0xE344, 0x0144, 0x0309, 
+    0x830C, 0xBC20, 0x7980, 0x0157, 0x6955, 0xE388, 0x0157, 0x7C38, 0xBF0B, 0x0578, 0xF500, 0xBF0B, 
+    0x0538, 0xB907, 0x8809, 0xBEC6, 0x0156, 0x10AB, 0x90AA, 0x6974, 0xE388, 0x0163, 0xAE72, 0x0540, 
+    0xF500, 0xAE72, 0x0500, 0xAE61, 0x103B, 0x7A80, 0x02F6, 0x6978, 0xE388, 0x0182, 0x8B8C, 0xBF0C, 
+    0x0560, 0xE500, 0x7C40, 0x0814, 0xBA20, 0x8812, 0x733D, 0x7A80, 0x0380, 0x733E, 0x7A80, 0x0380, 
+    0x8B8C, 0xBF0C, 0x056C, 0xE500, 0x7C40, 0x0814, 0xBA2C, 0x8812, 0x733F, 0x7A80, 0x0380, 0x7340, 
+    0x7A80, 0x0380, 0x6975, 0xE388, 0x018E, 0xAE72, 0x0548, 0xF500, 0xAE72, 0x0508, 0xAE61, 0x1041, 
+    0x7A80, 0x02F6, 0x6979, 0xE388, 0x01AD, 0x8B8C, 0xBF0C, 0x0560, 0xE500, 0x7C40, 0x0814, 0xBA18, 
+    0x8812, 0x7343, 0x7A80, 0x0380, 0x7344, 0x7A80, 0x0380, 0x8B8C, 0xBF0C, 0x056C, 0xE500, 0x7C40, 
+    0x0814, 0xBA24, 0x8812, 0x7345, 0x7A80, 0x0380, 0x7346, 0x7A80, 0x0380, 0x6976, 0xE388, 0x01B9, 
+    0xAE72, 0x0558, 0xF500, 0xAE72, 0x0518, 0xAE61, 0x1047, 0x7A80, 0x02F6, 0x697A, 0xE388, 0x01D8, 
+    0x8B8C, 0xBF0C, 0x0560, 0xE500, 0x7C40, 0x0814, 0xBA08, 0x8812, 0x7349, 0x7A80, 0x0380, 0x734A, 
+    0x7A80, 0x0380, 0x8B8C, 0xBF0C, 0x056C, 0xE500, 0x7C40, 0x0814, 0xBA14, 0x8812, 0x734B, 0x7A80, 
+    0x0380, 0x734C, 0x7A80, 0x0380, 0xBC21, 0xAE1C, 0x1090, 0x8B8A, 0xBF0A, 0x0560, 0xE500, 0x7C40, 
+    0x0812, 0xB804, 0x8813, 0x8B8D, 0xBF0D, 0x056C, 0xE500, 0x7C40, 0x0815, 0xB804, 0x8811, 0x7A80, 
+    0x034A, 0x8B8A, 0xBF0A, 0x0560, 0xE500, 0x7C40, 0x731F, 0xB903, 0x8809, 0xBEC6, 0x01F9, 0x548A, 
+    0xBE03, 0x98A0, 0x7320, 0xB903, 0x8809, 0xBEC6, 0x0201, 0x548A, 0xBE03, 0x98A0, 0x1F20, 0x2F1F, 
+    0x9826, 0xBC20, 0x6935, 0xE388, 0x03A1, 0x6933, 0xB801, 0x9033, 0xBFA0, 0x02EE, 0xE308, 0x03A1, 
+    0x9033, 0xBF00, 0x6951, 0xE388, 0x021F, 0x7334, 0xBE80, 0x5760, 0xBE03, 0x9F7E, 0xBE59, 0x9034, 
+    0x697E, 0x0D51, 0x9013, 0xBC20, 0x695C, 0xE388, 0x03A1, 0x735E, 0xBE80, 0x5760, 0xBE03, 0x9F7E, 
+    0xBE59, 0x905E, 0x697E, 0x0D5C, 0x9013, 0x7980, 0x03A1, 0x7A80, 0x038A, 0xBF01, 0xBE43, 0x6977, 
+    0xE388, 0x024E, 0xAE61, 0x104D, 0x0061, 0x8B88, 0x6980, 0xE388, 0x024E, 0x9071, 0x0D71, 0x000B, 
+    0xAFA0, 0x8010, 0xAFA0, 0x8010, 0x0810, 0x660A, 0xE308, 0x0249, 0x0009, 0x0810, 0x660C, 0xE388, 
+    0x024E, 0x800B, 0xBC20, 0x697B, 0xE388, 0x03A1, 0xBF0A, 0x109E, 0x8B8A, 0xAF80, 0x8014, 0x4C80, 
+    0xE100, 0x0266, 0x697C, 0xBF90, 0x0560, 0x9072, 0x0372, 0x697C, 0xBF90, 0x0564, 0x9073, 0x0473, 
+    0x7980, 0x0270, 0x697C, 0xBF90, 0x0520, 0x9072, 0x0372, 0x697C, 0xBF90, 0x0524, 0x9073, 0x0473, 
+    0x697C, 0xB801, 0x907C, 0xBF0A, 0x10FD, 0x8B8A, 0xAF80, 0x8010, 0x734F, 0x548A, 0xBE03, 0x9880, 
+    0xBC21, 0x7326, 0x548B, 0xBE03, 0x618B, 0x988C, 0xBE03, 0x6180, 0x9880, 0x7980, 0x03A1, 0x7A80, 
+    0x038A, 0x0D28, 0x4711, 0xE100, 0x02BE, 0xAF12, 0x4006, 0x6912, 0xBFB0, 0x0C00, 0xE388, 0x02B6, 
+    0xBFA0, 0x0800, 0xE388, 0x02B2, 0x6912, 0xBFB0, 0x0C00, 0xBFA0, 0x0400, 0xE388, 0x02A3, 0x6909, 
+    0x900B, 0x7980, 0x02A5, 0xAF0B, 0x4005, 0x6901, 0x9005, 0x6902, 0x9006, 0x4311, 0xE100, 0x02ED, 
+    0x6911, 0xBFC0, 0x2000, 0x9011, 0x7980, 0x02ED, 0x6909, 0x900B, 0x7980, 0x02B8, 0xAF0B, 0x4005, 
+    0xAF05, 0x4003, 0xAF06, 0x4004, 0x7980, 0x02ED, 0xAF12, 0x4006, 0x6912, 0xBFB0, 0x0C00, 0xE388, 
+    0x02E7, 0xBFA0, 0x0800, 0xE388, 0x02E3, 0x6912, 0xBFB0, 0x0C00, 0xBFA0, 0x0400, 0xE388, 0x02D4, 
+    0x690D, 0x9010, 0x7980, 0x02D6, 0xAF10, 0x4005, 0x6901, 0x9005, 0x6902, 0x9006, 0x4311, 0xE100, 
+    0x02ED, 0x6911, 0xBFC0, 0x2000, 0x9011, 0x7980, 0x02ED, 0x690D, 0x9010, 0x7980, 0x02E9, 0xAF10, 
+    0x4005, 0xAF05, 0x4003, 0xAF06, 0x4004, 0xBC20, 0x6970, 0x9071, 0x7A80, 0x0078, 0x6971, 0x9070, 
+    0x7980, 0x03A1, 0xBC20, 0x0361, 0x8B8B, 0x6980, 0xEF88, 0x0272, 0x0372, 0x7804, 0x9071, 0x0D71, 
+    0x8B8A, 0x000B, 0xB903, 0x8809, 0xBEC6, 0x0309, 0x69A8, 0x90AB, 0x69A8, 0x90AA, 0x0810, 0x660A, 
+    0xE344, 0x030F, 0x0009, 0x0810, 0x660C, 0xE388, 0x0314, 0x800B, 0xBC20, 0x6961, 0xB801, 0x9061, 
+    0x7980, 0x02F7, 0x7A80, 0x038A, 0x5D35, 0x0001, 0x6934, 0xB801, 0x9034, 0xBF0A, 0x109E, 0x8B8A, 
+    0xAF80, 0x8014, 0x4880, 0xAE72, 0x0550, 0xF500, 0xAE72, 0x0510, 0xAE61, 0x1051, 0x7A80, 0x02F6, 
+    0x7980, 0x03A1, 0x7A80, 0x038A, 0x5D35, 0x0002, 0x695E, 0xB801, 0x905E, 0xBF0A, 0x109E, 0x8B8A, 
+    0xAF80, 0x8014, 0x4780, 0xAE72, 0x0558, 0xF500, 0xAE72, 0x0518, 0xAE61, 0x105C, 0x7A80, 0x02F6, 
+    0x7980, 0x03A1, 0x001C, 0x8B88, 0x6980, 0xEF88, 0x901D, 0x0D1D, 0x100F, 0x6610, 0xE38C, 0x0358, 
+    0x690E, 0x6610, 0x620F, 0x660D, 0xBA0F, 0xE301, 0x037A, 0x0410, 0x8B8A, 0xB903, 0x8809, 0xBEC6, 
+    0x036C, 0x6A8C, 0x61AA, 0x98AB, 0x6A8C, 0x61AB, 0x98AD, 0x6A8C, 0x61AD, 0x98A9, 0x6A8C, 0x61A9, 
+    0x98AA, 0x7C04, 0x8B8B, 0x7C04, 0x8B8D, 0x7C04, 0x8B89, 0x7C04, 0x0814, 0x660E, 0xE308, 0x0379, 
+    0x040D, 0x8410, 0xBC21, 0x691C, 0xB801, 0x901C, 0x7980, 0x034A, 0xB903, 0x8809, 0x8B8A, 0xBEC6, 
+    0x0388, 0x54AC, 0xBE03, 0x618C, 0x98AA, 0xEF00, 0xBC20, 0xBE46, 0x0809, 0x906B, 0x080A, 0x906C, 
+    0x080B, 0x906D, 0x081A, 0x9062, 0x081B, 0x9063, 0x081E, 0x9064, 0xBE59, 0x881E, 0x8065, 0x8166, 
+    0x8267, 0x8368, 0x8469, 0x856A, 0xEF00, 0xBC20, 0x696B, 0x8809, 0x696C, 0x880A, 0x696D, 0x880B, 
+    0x6962, 0x881A, 0x6963, 0x881B, 0x6964, 0x881E, 0x0065, 0x0166, 0x0267, 0x0368, 0x0469, 0x056A, 
+    0xBE3A, 
+};
+
+/*
+ * Mini sample rate converter code image
+ * that is to be loaded at 0x400 on the DSP.
+ */
+u16 assp_minisrc_image[] = {
+
+    0xBF80, 0x101E, 0x906E, 0x006E, 0x8B88, 0x6980, 0xEF88, 0x906F, 0x0D6F, 0x6900, 0xEB08, 0x0412, 
+    0xBC20, 0x696E, 0xB801, 0x906E, 0x7980, 0x0403, 0xB90E, 0x8807, 0xBE43, 0xBF01, 0xBE47, 0xBE41, 
+    0x7A80, 0x002A, 0xBE40, 0x3029, 0xEFCC, 0xBE41, 0x7A80, 0x0028, 0xBE40, 0x3028, 0xEFCC, 0x6907, 
+    0xE308, 0x042A, 0x6909, 0x902C, 0x7980, 0x042C, 0x690D, 0x902C, 0x1009, 0x881A, 0x100A, 0xBA01, 
+    0x881B, 0x100D, 0x881C, 0x100E, 0xBA01, 0x881D, 0xBF80, 0x00ED, 0x881E, 0x050C, 0x0124, 0xB904, 
+    0x9027, 0x6918, 0xE308, 0x04B3, 0x902D, 0x6913, 0xBFA0, 0x7598, 0xF704, 0xAE2D, 0x00FF, 0x8B8D, 
+    0x6919, 0xE308, 0x0463, 0x691A, 0xE308, 0x0456, 0xB907, 0x8809, 0xBEC6, 0x0453, 0x10A9, 0x90AD, 
+    0x7980, 0x047C, 0xB903, 0x8809, 0xBEC6, 0x0460, 0x1889, 0x6C22, 0x90AD, 0x10A9, 0x6E23, 0x6C22, 
+    0x90AD, 0x7980, 0x047C, 0x101A, 0xE308, 0x046F, 0xB903, 0x8809, 0xBEC6, 0x046C, 0x10A9, 0x90A0, 
+    0x90AD, 0x7980, 0x047C, 0xB901, 0x8809, 0xBEC6, 0x047B, 0x1889, 0x6C22, 0x90A0, 0x90AD, 0x10A9, 
+    0x6E23, 0x6C22, 0x90A0, 0x90AD, 0x692D, 0xE308, 0x049C, 0x0124, 0xB703, 0xB902, 0x8818, 0x8B89, 
+    0x022C, 0x108A, 0x7C04, 0x90A0, 0x692B, 0x881F, 0x7E80, 0x055B, 0x692A, 0x8809, 0x8B89, 0x99A0, 
+    0x108A, 0x90A0, 0x692B, 0x881F, 0x7E80, 0x055B, 0x692A, 0x8809, 0x8B89, 0x99AF, 0x7B99, 0x0484, 
+    0x0124, 0x060F, 0x101B, 0x2013, 0x901B, 0xBFA0, 0x7FFF, 0xE344, 0x04AC, 0x901B, 0x8B89, 0x7A80, 
+    0x051A, 0x6927, 0xBA01, 0x9027, 0x7A80, 0x0523, 0x6927, 0xE308, 0x049E, 0x7980, 0x050F, 0x0624, 
+    0x1026, 0x2013, 0x9026, 0xBFA0, 0x7FFF, 0xE304, 0x04C0, 0x8B8D, 0x7A80, 0x051A, 0x7980, 0x04B4, 
+    0x9026, 0x1013, 0x3026, 0x901B, 0x8B8D, 0x7A80, 0x051A, 0x7A80, 0x0523, 0x1027, 0xBA01, 0x9027, 
+    0xE308, 0x04B4, 0x0124, 0x060F, 0x8B89, 0x691A, 0xE308, 0x04EA, 0x6919, 0xE388, 0x04E0, 0xB903, 
+    0x8809, 0xBEC6, 0x04DD, 0x1FA0, 0x2FAE, 0x98A9, 0x7980, 0x050F, 0xB901, 0x8818, 0xB907, 0x8809, 
+    0xBEC6, 0x04E7, 0x10EE, 0x90A9, 0x7980, 0x050F, 0x6919, 0xE308, 0x04FE, 0xB903, 0x8809, 0xBE46, 
+    0xBEC6, 0x04FA, 0x17A0, 0xBE1E, 0x1FAE, 0xBFBF, 0xFF00, 0xBE13, 0xBFDF, 0x8080, 0x99A9, 0xBE47, 
+    0x7980, 0x050F, 0xB901, 0x8809, 0xBEC6, 0x050E, 0x16A0, 0x26A0, 0xBFB7, 0xFF00, 0xBE1E, 0x1EA0, 
+    0x2EAE, 0xBFBF, 0xFF00, 0xBE13, 0xBFDF, 0x8080, 0x99A9, 0x850C, 0x860F, 0x6907, 0xE388, 0x0516, 
+    0x0D07, 0x8510, 0xBE59, 0x881E, 0xBE4A, 0xEF00, 0x101E, 0x901C, 0x101F, 0x901D, 0x10A0, 0x901E, 
+    0x10A0, 0x901F, 0xEF00, 0x101E, 0x301C, 0x9020, 0x731B, 0x5420, 0xBE03, 0x9825, 0x1025, 0x201C, 
+    0x9025, 0x7325, 0x5414, 0xBE03, 0x8B8E, 0x9880, 0x692F, 0xE388, 0x0539, 0xBE59, 0xBB07, 0x6180, 
+    0x9880, 0x8BA0, 0x101F, 0x301D, 0x9021, 0x731B, 0x5421, 0xBE03, 0x982E, 0x102E, 0x201D, 0x902E, 
+    0x732E, 0x5415, 0xBE03, 0x9880, 0x692F, 0xE388, 0x054F, 0xBE59, 0xBB07, 0x6180, 0x9880, 0x8BA0, 
+    0x6918, 0xEF08, 0x7325, 0x5416, 0xBE03, 0x98A0, 0x732E, 0x5417, 0xBE03, 0x98A0, 0xEF00, 0x8BA0, 
+    0xBEC6, 0x056B, 0xBE59, 0xBB04, 0xAA90, 0xBE04, 0xBE1E, 0x99E0, 0x8BE0, 0x69A0, 0x90D0, 0x69A0, 
+    0x90D0, 0x081F, 0xB805, 0x881F, 0x8B90, 0x69A0, 0x90D0, 0x69A0, 0x9090, 0x8BD0, 0x8BD8, 0xBE1F, 
+    0xEF00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
+};
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/sonicvibes.c linux.19p18/drivers/sound/sonicvibes.c
--- linux.vanilla/drivers/sound/sonicvibes.c	Mon Dec 11 22:12:56 2000
+++ linux.19p18/drivers/sound/sonicvibes.c	Tue Dec 19 02:13:08 2000
@@ -77,11 +77,15 @@
  *    24.08.1999   0.19  get rid of the dmaio kludge, replace with allocate_resource
  *    31.08.1999   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)
  *    03.09.1999   0.21  change read semantics for MIDI to match
  *                       OSS more closely; remove possible wakeup race
  *    28.10.1999   0.22  More waitqueue races fixed
+ *    08.01.2000   0.25  Prevent some ioctl's from returning bad count values on underrun/overrun;
+ *                       Tim Janik's BSE (Bedevilled Sound Engine) found this
+ *    21.11.2000   0.27  Initialize dma buffers in poll, otherwise poll may return a bogus mask
+ *    12.12.2000   0.28  More dma buffer initializations, patch from
+ *                       Tjeerd Mulder <tjeerd.mulder@fujitsu-siemens.com>
  *
  */
 
@@ -1543,6 +1547,7 @@
 	unsigned long flags;
         audio_buf_info abinfo;
         count_info cinfo;
+	int count;
 	int val, mapped, ret;
 	unsigned char fmtm, fmtd;
 
@@ -1578,7 +1583,8 @@
 		return 0;
 
         case SNDCTL_DSP_SPEED:
-                get_user_ret(val, (int *)arg, -EFAULT);
+                if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (val >= 0) {
 			if (file->f_mode & FMODE_READ) {
 				stop_adc(s);
@@ -1594,7 +1600,8 @@
 		return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg);
 		
         case SNDCTL_DSP_STEREO:
-                get_user_ret(val, (int *)arg, -EFAULT);
+                if (get_user(val, (int *)arg))
+			return -EFAULT;
 		fmtd = 0;
 		fmtm = ~0;
 		if (file->f_mode & FMODE_READ) {
@@ -1617,7 +1624,8 @@
 		return 0;
 
         case SNDCTL_DSP_CHANNELS:
-                get_user_ret(val, (int *)arg, -EFAULT);
+                if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (val != 0) {
 			fmtd = 0;
 			fmtm = ~0;
@@ -1646,7 +1654,8 @@
                 return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg);
 		
 	case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
-		get_user_ret(val, (int *)arg, -EFAULT);
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (val != AFMT_QUERY) {
 			fmtd = 0;
 			fmtm = ~0;
@@ -1683,7 +1692,8 @@
 		return put_user(val, (int *)arg);
 		
 	case SNDCTL_DSP_SETTRIGGER:
-		get_user_ret(val, (int *)arg, -EFAULT);
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (file->f_mode & FMODE_READ) {
 			if (val & PCM_ENABLE_INPUT) {
 				if (!s->dma_adc.ready && (ret =  prog_dmabuf(s, 1)))
@@ -1705,12 +1715,15 @@
 	case SNDCTL_DSP_GETOSPACE:
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
-		if (!(s->enable & SV_CENABLE_PE) && (val = prog_dmabuf(s, 0)) != 0)
+		if (!s->dma_dac.ready && (val = prog_dmabuf(s, 0)) != 0)
 			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		sv_update_ptr(s);
 		abinfo.fragsize = s->dma_dac.fragsize;
-                abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count;
+		count = s->dma_dac.count;
+		if (count < 0)
+			count = 0;
+                abinfo.bytes = s->dma_dac.dmasize - count;
                 abinfo.fragstotal = s->dma_dac.numfrag;
                 abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;      
 		spin_unlock_irqrestore(&s->lock, flags);
@@ -1719,12 +1732,15 @@
 	case SNDCTL_DSP_GETISPACE:
 		if (!(file->f_mode & FMODE_READ))
 			return -EINVAL;
-		if (!(s->enable & SV_CENABLE_RE) && (val = prog_dmabuf(s, 1)) != 0)
+		if (!s->dma_adc.ready && (val = prog_dmabuf(s, 1)) != 0)
 			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		sv_update_ptr(s);
 		abinfo.fragsize = s->dma_adc.fragsize;
-                abinfo.bytes = s->dma_adc.count;
+		count = s->dma_adc.count;
+		if (count < 0)
+			count = 0;
+                abinfo.bytes = count;
                 abinfo.fragstotal = s->dma_adc.numfrag;
                 abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;      
 		spin_unlock_irqrestore(&s->lock, flags);
@@ -1737,19 +1753,28 @@
         case SNDCTL_DSP_GETODELAY:
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
+		if (!s->dma_dac.ready && (val = prog_dmabuf(s, 0)) != 0)
+			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		sv_update_ptr(s);
-                val = s->dma_dac.count;
+                count = s->dma_dac.count;
 		spin_unlock_irqrestore(&s->lock, flags);
-		return put_user(val, (int *)arg);
+		if (count < 0)
+			count = 0;
+		return put_user(count, (int *)arg);
 
         case SNDCTL_DSP_GETIPTR:
 		if (!(file->f_mode & FMODE_READ))
 			return -EINVAL;
+		if (!s->dma_adc.ready && (val = prog_dmabuf(s, 1)) != 0)
+			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		sv_update_ptr(s);
                 cinfo.bytes = s->dma_adc.total_bytes;
-                cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
+		count = s->dma_adc.count;
+		if (count < 0)
+			count = 0;
+                cinfo.blocks = count >> s->dma_adc.fragshift;
                 cinfo.ptr = s->dma_adc.hwptr;
 		if (s->dma_adc.mapped)
 			s->dma_adc.count &= s->dma_adc.fragsize-1;
@@ -1759,10 +1784,15 @@
         case SNDCTL_DSP_GETOPTR:
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
+		if (!s->dma_dac.ready && (val = prog_dmabuf(s, 0)) != 0)
+			return val;
 		spin_lock_irqsave(&s->lock, flags);
 		sv_update_ptr(s);
                 cinfo.bytes = s->dma_dac.total_bytes;
-                cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift;
+		count = s->dma_dac.count;
+		if (count < 0)
+			count = 0;
+                cinfo.blocks = count >> s->dma_dac.fragshift;
                 cinfo.ptr = s->dma_dac.hwptr;
 		if (s->dma_dac.mapped)
 			s->dma_dac.count &= s->dma_dac.fragsize-1;
@@ -1780,7 +1810,8 @@
 		return put_user(s->dma_adc.fragsize, (int *)arg);
 
         case SNDCTL_DSP_SETFRAGMENT:
-                get_user_ret(val, (int *)arg, -EFAULT);
+                if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (file->f_mode & FMODE_READ) {
 			s->dma_adc.ossfragshift = val & 0xffff;
 			s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
@@ -1807,7 +1838,8 @@
 		if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
 		    (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
 			return -EINVAL;
-                get_user_ret(val, (int *)arg, -EFAULT);
+                if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (val != 1 && val != 2 && val != 4)
 			return -EINVAL;
 		if (file->f_mode & FMODE_READ)
@@ -2432,7 +2464,7 @@
 
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO "sv: version v0.22 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "sv: version v0.28 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");
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/sound_core.c linux.19p18/drivers/sound/sound_core.c
--- linux.vanilla/drivers/sound/sound_core.c	Mon Dec 11 22:12:56 2000
+++ linux.19p18/drivers/sound/sound_core.c	Wed Jan  3 01:01:13 2001
@@ -52,6 +52,7 @@
 	struct sound_unit *next;
 };
 
+extern int init_cmpci(void);
 extern int init_sonicvibes(void);
 extern int init_maestro(void);
 extern int init_trident(void);
@@ -63,7 +64,6 @@
 extern int init_solo1(void);
 extern int init_ymf7xxsb_module(void);
 extern int cs_probe(void);
-extern int init_emu10k1(void);
 extern int cs4281_probe(void);
 extern void init_vwsnd(void);
 extern int ymf_probe(void);
@@ -396,6 +396,9 @@
 	/*
 	 *	Now init non OSS drivers
 	 */
+#ifdef CONFIG_SOUND_CMPCI
+        init_cmpci();
+#endif
 #ifdef CONFIG_SOUND_VWSND
 	init_vwsnd();
 #endif
@@ -411,6 +414,9 @@
 #ifdef CONFIG_SOUND_MAESTRO
 	init_maestro();
 #endif
+#ifdef CONFIG_SOUND_MAESTRO3
+    init_maestro3();
+#endif
 #ifdef CONFIG_SOUND_TRIDENT
 	init_trident();
 #endif
@@ -434,9 +440,6 @@
 #endif
 #ifdef CONFIG_SOUND_CS4281
 	cs4281_probe();
-#endif
-#ifdef CONFIG_SOUND_EMU10K1
-	init_emu10k1();
 #endif
 #ifdef CONFIG_SOUND_YMFPCI
 	ymf_probe();
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/trident.c linux.19p18/drivers/sound/trident.c
--- linux.vanilla/drivers/sound/trident.c	Mon Dec 11 22:12:56 2000
+++ linux.19p18/drivers/sound/trident.c	Wed Jan  3 01:00:48 2001
@@ -2789,7 +2789,7 @@
 	u16 w;
 	unsigned long iobase;
 	struct trident_card *card;
-
+	unsigned long flags;
 
 	iobase = pci_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
 	if (check_region(iobase, 256)) {
@@ -2882,10 +2882,17 @@
 		
 			/* reset command */
 			while (inb(card->iobase + ALI_MPUR1) & 0x40);
+			
+			/* After the out the chip goes into irq jammed on
+			   mode. We have to keep irqs off until it shuts up 
+			   again */
+			save_flags(flags);
+			cli();
 			outb(0xff, card->iobase + ALI_MPUR1);
 			while (inb(card->iobase + ALI_MPUR1) & 0x80);
 			while ((inb(card->iobase + ALI_MPUR0) != 0xfe) && (inb(card->iobase+ALI_MPUR1) != 0x10)) 
 				while (inb(card->iobase + ALI_MPUR1) & 0x80);
+			restore_flags(flags);
 			
 			midi->ird = midi->iwr = midi->icnt = 0;
 		}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/ymf_sb.c linux.19p18/drivers/sound/ymf_sb.c
--- linux.vanilla/drivers/sound/ymf_sb.c	Sat Sep  9 18:42:45 2000
+++ linux.19p18/drivers/sound/ymf_sb.c	Thu Jan  1 01:00:00 1970
@@ -1,995 +0,0 @@
-/*
-  Legacy audio driver for YMF724, 740, 744, 754 series.
-  Copyright 2000 Daisuke Nagano <breeze.nagano@nifty.ne.jp>
-
-  Based on the VIA 82Cxxx driver by Jeff Garzik <jgarzik@pobox.com>
-
-  Distribued under the GNU PUBLIC LICENSE (GPL) Version 2.
-  See the "COPYING" file distributed with kernel source tree for more info.
-
-  -------------------------------------------------------------------------
-
-  It only supports SBPro compatible function of YMF7xx series s.t.
-    * 22.05kHz, 8-bit and stereo sample
-    * OPL3-compatible FM synthesizer
-    * MPU-401 compatible "external" MIDI interface
-
-  and AC'97 mixer of these cards.
-
-  -------------------------------------------------------------------------
-
-  Revision history
-
-   Tue May 14 19:00:00 2000   0.0.1
-   * initial release
-
-   Tue May 16 19:29:29 2000   0.0.2
-
-   * add a little delays for reset devices.
-   * fixed addressing bug.
-
-   Sun May 21 15:14:37 2000   0.0.3
-
-   * Add 'master_vol' module parameter to change 'PCM out Vol' of AC'97.
-   * remove native UART401 support. External MIDI port should be supported 
-     by sb_midi driver.
-   * add support for SPDIF OUT. Module parameter 'spdif_out' is now available.
-
-   Wed May 31 00:13:57 2000   0.0.4
-
-   * remove entries in Hwmcode.h. Now YMF744 / YMF754 sets instructions 
-     in 724hwmcode.h.
-   * fixed wrong legacy_io setting on YMF744/YMF754 .
-
-   Sat Jun  3 23:44:08 2000   0.0.5
-
-   * correct all return value -1 to appropriate -E* value.
-   * add pci_enable_device() for linux-2.3.x.
-
-   Sat Jun  7 00:17:32 2000   0.1.0
-
-   * Remove SBPro mixer support.
-   * Added AC'97 mixer support and remove option 'master_volume'.
-   * Correct all separated valuables into struct ymf_cards.
-
-   Mon Jun 12 21:36:50 2000   0.1.1
-
-   * Invalid dma setting fixed.
-     -- John A. Boyd Jr. <jaboydjr@netwalk.com>
-
-   * ymfsb only compiled as module: fixed
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/version.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-
-#include "sound_config.h"
-#include "soundmodule.h"
-#include "sb.h"
-#include "724hwmcode.h"
-
-#include "ac97.h"
-
-#undef YMF_DEBUG
-
-/* ---------------------------------------------------------------------- */
-
-#ifndef SOUND_LOCK
-# define SOUND_LOCK do {} while (0)
-# define SOUND_LOCK_END do {} while (0)
-#endif
-
-#ifndef PCI_VENDOR_ID_YAMAHA
-# define PCI_VENDOR_ID_YAMAHA  0x1073
-#endif
-#ifndef PCI_DEVICE_ID_YMF724
-# define PCI_DEVICE_ID_YMF724  0x0004
-#endif
-#ifndef PCI_DEVICE_ID_YMF740
-# define PCI_DEVICE_ID_YMF740  0x000A
-#endif
-#ifndef PCI_DEVICE_ID_YMF740C
-# define PCI_DEVICE_ID_YMF740C 0x000C
-#endif
-#ifndef PCI_DEVICE_ID_YMF724F
-# define PCI_DEVICE_ID_YMF724F 0x000D
-#endif
-#ifndef PCI_DEVICE_ID_YMF744
-# define PCI_DEVICE_ID_YMF744  0x0010
-#endif
-#ifndef PCI_DEVICE_ID_YMF754
-# define PCI_DEVICE_ID_YMF754  0x0012
-#endif
-
-/* ---------------------------------------------------------------------- */
-
-#define YMFSB_RESET_DELAY               5
-
-#define YMFSB_REGSIZE                   0x8000
-
-#define YMFSB_AC97TIMEOUT               2000
-
-#define	YMFSB_WORKBITTIMEOUT            250000
-
-#define	YMFSB_DSPLENGTH                 0x0080
-#define	YMFSB_CTRLLENGTH                0x3000
-
-#define YMFSB_PCIR_VENDORID             0x00
-#define YMFSB_PCIR_DEVICEID             0x02
-#define YMFSB_PCIR_CMD                  0x04
-#define YMFSB_PCIR_REVISIONID           0x08
-#define YMFSB_PCIR_BASEADDR             0x10
-#define YMFSB_PCIR_IRQ                  0x3c
-
-#define	YMFSB_PCIR_LEGCTRL              0x40
-#define	YMFSB_PCIR_ELEGCTRL             0x42
-#define	YMFSB_PCIR_DSXGCTRL             0x48
-#define YMFSB_PCIR_OPLADR               0x60
-#define YMFSB_PCIR_SBADR                0x62
-#define YMFSB_PCIR_MPUADR               0x64
-
-#define	YMFSB_INTFLAG                   0x0004
-#define	YMFSB_ACTIVITY                  0x0006
-#define	YMFSB_GLOBALCTRL                0x0008
-#define	YMFSB_ZVCTRL                    0x000A
-#define	YMFSB_TIMERCTRL                 0x0010
-#define	YMFSB_TIMERCOUNT                0x0012
-#define	YMFSB_SPDIFOUTCTRL              0x0018
-#define	YMFSB_SPDIFOUTSTATUS            0x001C
-#define	YMFSB_EEPROMCTRL                0x0020
-#define	YMFSB_SPDIFINCTRL               0x0034
-#define	YMFSB_SPDIFINSTATUS             0x0038
-#define	YMFSB_DSPPROGRAMDL              0x0048
-#define	YMFSB_DLCNTRL                   0x004C
-#define	YMFSB_GPIOININTFLAG             0x0050
-#define	YMFSB_GPIOININTENABLE           0x0052
-#define	YMFSB_GPIOINSTATUS              0x0054
-#define	YMFSB_GPIOOUTCTRL               0x0056
-#define	YMFSB_GPIOFUNCENABLE            0x0058
-#define	YMFSB_GPIOTYPECONFIG            0x005A
-#define	YMFSB_AC97CMDDATA               0x0060
-#define	YMFSB_AC97CMDADR                0x0062
-#define	YMFSB_PRISTATUSDATA             0x0064
-#define	YMFSB_PRISTATUSADR              0x0066
-#define	YMFSB_SECSTATUSDATA             0x0068
-#define	YMFSB_SECSTATUSADR              0x006A
-#define	YMFSB_SECCONFIG                 0x0070
-#define	YMFSB_LEGACYOUTVOL              0x0080
-#define	YMFSB_LEGACYOUTVOLL             0x0080
-#define	YMFSB_LEGACYOUTVOLR             0x0082
-#define	YMFSB_NATIVEDACOUTVOL           0x0084
-#define	YMFSB_NATIVEDACOUTVOLL          0x0084
-#define	YMFSB_NATIVEDACOUTVOLR          0x0086
-#define	YMFSB_SPDIFOUTVOL               0x0088
-#define	YMFSB_SPDIFOUTVOLL              0x0088
-#define	YMFSB_SPDIFOUTVOLR              0x008A
-#define	YMFSB_AC3OUTVOL                 0x008C
-#define	YMFSB_AC3OUTVOLL                0x008C
-#define	YMFSB_AC3OUTVOLR                0x008E
-#define	YMFSB_PRIADCOUTVOL              0x0090
-#define	YMFSB_PRIADCOUTVOLL             0x0090
-#define	YMFSB_PRIADCOUTVOLR             0x0092
-#define	YMFSB_LEGACYLOOPVOL             0x0094
-#define	YMFSB_LEGACYLOOPVOLL            0x0094
-#define	YMFSB_LEGACYLOOPVOLR            0x0096
-#define	YMFSB_NATIVEDACLOOPVOL          0x0098
-#define	YMFSB_NATIVEDACLOOPVOLL         0x0098
-#define	YMFSB_NATIVEDACLOOPVOLR         0x009A
-#define	YMFSB_SPDIFLOOPVOL              0x009C
-#define	YMFSB_SPDIFLOOPVOLL             0x009E
-#define	YMFSB_SPDIFLOOPVOLR             0x009E
-#define	YMFSB_AC3LOOPVOL                0x00A0
-#define	YMFSB_AC3LOOPVOLL               0x00A0
-#define	YMFSB_AC3LOOPVOLR               0x00A2
-#define	YMFSB_PRIADCLOOPVOL             0x00A4
-#define	YMFSB_PRIADCLOOPVOLL            0x00A4
-#define	YMFSB_PRIADCLOOPVOLR            0x00A6
-#define	YMFSB_NATIVEADCINVOL            0x00A8
-#define	YMFSB_NATIVEADCINVOLL           0x00A8
-#define	YMFSB_NATIVEADCINVOLR           0x00AA
-#define	YMFSB_NATIVEDACINVOL            0x00AC
-#define	YMFSB_NATIVEDACINVOLL           0x00AC
-#define	YMFSB_NATIVEDACINVOLR           0x00AE
-#define	YMFSB_BUF441OUTVOL              0x00B0
-#define	YMFSB_BUF441OUTVOLL             0x00B0
-#define	YMFSB_BUF441OUTVOLR             0x00B2
-#define	YMFSB_BUF441LOOPVOL             0x00B4
-#define	YMFSB_BUF441LOOPVOLL            0x00B4
-#define	YMFSB_BUF441LOOPVOLR            0x00B6
-#define	YMFSB_SPDIFOUTVOL2              0x00B8
-#define	YMFSB_SPDIFOUTVOL2L             0x00B8
-#define	YMFSB_SPDIFOUTVOL2R             0x00BA
-#define	YMFSB_SPDIFLOOPVOL2             0x00BC
-#define	YMFSB_SPDIFLOOPVOL2L            0x00BC
-#define	YMFSB_SPDIFLOOPVOL2R            0x00BE
-#define	YMFSB_ADCSLOTSR                 0x00C0
-#define	YMFSB_RECSLOTSR                 0x00C4
-#define	YMFSB_ADCFORMAT                 0x00C8
-#define	YMFSB_RECFORMAT                 0x00CC
-#define	YMFSB_P44SLOTSR                 0x00D0
-#define	YMFSB_STATUS                    0x0100
-#define	YMFSB_CTRLSELECT                0x0104
-#define	YMFSB_MODE                      0x0108
-#define	YMFSB_SAMPLECOUNT               0x010C
-#define	YMFSB_NUMOFSAMPLES              0x0110
-#define	YMFSB_CONFIG                    0x0114
-#define	YMFSB_PLAYCTRLSIZE              0x0140
-#define	YMFSB_RECCTRLSIZE               0x0144
-#define	YMFSB_EFFCTRLSIZE               0x0148
-#define	YMFSB_WORKSIZE                  0x014C
-#define	YMFSB_MAPOFREC                  0x0150
-#define	YMFSB_MAPOFEFFECT               0x0154
-#define	YMFSB_PLAYCTRLBASE              0x0158
-#define	YMFSB_RECCTRLBASE               0x015C
-#define	YMFSB_EFFCTRLBASE               0x0160
-#define	YMFSB_WORKBASE                  0x0164
-#define	YMFSB_DSPINSTRAM                0x1000
-#define	YMFSB_CTRLINSTRAM               0x4000
-
-
-/* ---------------------------------------------------------------------- */
-
-#define MAX_CARDS	4
-
-#define PFX		"ymf_sb: "
-
-#define YMFSB_VERSION	"0.1.1"
-#define YMFSB_CARD_NAME	"YMF7xx Legacy Audio driver " YMFSB_VERSION
-
-#define ymf7xxsb_probe_midi probe_sbmpu
-#define ymf7xxsb_attach_midi attach_sbmpu
-#define ymf7xxsb_unload_midi unload_sbmpu
-
-/* ---------------------------------------------------------------------- */
-
-static struct ymf_card {
-  int                  card;
-  unsigned short      *ymfbase;
-
-  struct address_info sb_data, opl3_data, mpu_data;
-
-  struct ac97_hwint   ac97_dev;
-  int                 mixer_oss_dev;
-} ymf_cards[MAX_CARDS];
-
-static unsigned int cards = 0;
-
-/* ---------------------------------------------------------------------- */
-
-#ifdef MODULE
-static int mpu_io     = 0;
-static int synth_io   = 0;
-static int io         = 0;
-static int dma        = 0;
-static int spdif_out  = 1;
-MODULE_PARM(mpu_io, "i");
-MODULE_PARM(synth_io, "i");
-MODULE_PARM(io,"i");
-MODULE_PARM(dma,"i");
-MODULE_PARM(spdif_out,"i");
-#else
-static int mpu_io     = 0x330;
-static int synth_io   = 0x388;
-static int io         = 0x220;
-static int dma        = 1;
-static int spdif_out  = 1;
-#endif
-
-/* ---------------------------------------------------------------------- */
-
-static int readRegWord( struct ymf_card *card, int adr ) {
-
-	if (card->ymfbase==NULL) return 0;
-
-	return readw(card->ymfbase+adr/2);
-}
-
-static void writeRegWord( struct ymf_card *card, int adr, int val ) {
-
-	if (card->ymfbase==NULL) return;
-
-	writew((unsigned short)(val&0xffff), card->ymfbase + adr/2);
-
-	return;
-}
-
-static int readRegDWord( struct ymf_card *card, int adr ) {
-
-	if (card->ymfbase==NULL) return 0;
-
-	return (readl(card->ymfbase+adr/2));
-}
-
-static void writeRegDWord( struct ymf_card *card, int adr, int val ) {
-
-	if (card->ymfbase==NULL) return;
-
-	writel((unsigned int)(val&0xffffffff), card->ymfbase+adr/2);
-
-	return;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static int checkPrimaryBusy( struct ymf_card *card )
-{
-	int timeout=0;
-
-	while ( timeout++ < YMFSB_AC97TIMEOUT )
-	{
-		if ( (readRegWord(card, YMFSB_PRISTATUSADR) & 0x8000) == 0x0000 )
-			return 0;
-	}
-	return -EBUSY;
-}
-
-static int checkCodec( struct ymf_card *card, struct pci_dev *pcidev )
-{
-	u8 tmp8;
-
-	pci_read_config_byte( pcidev, YMFSB_PCIR_DSXGCTRL, &tmp8 );
-	if ( tmp8 & 0x03 ) {
-		pci_write_config_byte(pcidev, YMFSB_PCIR_DSXGCTRL, tmp8&0xfc);
-		mdelay(YMFSB_RESET_DELAY);
-		pci_write_config_byte(pcidev, YMFSB_PCIR_DSXGCTRL, tmp8|0x03);
-		mdelay(YMFSB_RESET_DELAY);
-		pci_write_config_byte(pcidev, YMFSB_PCIR_DSXGCTRL, tmp8&0xfc);
-		mdelay(YMFSB_RESET_DELAY);
-	}
-
-	if ( checkPrimaryBusy( card ) ) return -EBUSY;
-
-	return 0;
-}
-
-static int setupLegacyIO( struct ymf_card *card, struct pci_dev *pcidev )
-{
-	int v;
-	int sbio=0, mpuio=0, oplio=0,dma=0;
-
-	switch(card->sb_data.io_base) {
-	case 0x220:
-		sbio = 0;
-		break;
-	case 0x240:
-		sbio = 1;
-		break;
-	case 0x260:
-		sbio = 2;
-		break;
-	case 0x280:
-		sbio = 3;
-		break;
-	default:
-		return -EINVAL;
-		break;
-	}
-#ifdef YMF_DEBUG
-	printk(PFX "set SBPro I/O at 0x%x\n",card->sb_data.io_base);
-#endif
-
-	switch(card->mpu_data.io_base) {
-	case 0x330:
-		mpuio = 0;
-		break;
-	case 0x300:
-		mpuio = 1;
-		break;
-	case 0x332:
-		mpuio = 2;
-		break;
-	case 0x334:
-		mpuio = 3;
-		break;
-	default:
-		mpuio = 0;
-		break;
-	}
-#ifdef YMF_DEBUG
-	printk(PFX "set MPU401 I/O at 0x%x\n",card->mpu_data.io_base);
-#endif
-
-	switch(card->opl3_data.io_base) {
-	case 0x388:
-		oplio = 0;
-		break;
-	case 0x398:
-		oplio = 1;
-		break;
-	case 0x3a0:
-		oplio = 2;
-		break;
-	case 0x3a8:
-		oplio = 3;
-		break;
-	default:
-		return -EINVAL;
-		break;
-	}
-#ifdef YMF_DEBUG
-	printk(PFX "set OPL3 I/O at 0x%x\n",card->opl3_data.io_base);
-#endif
-
-	dma = card->sb_data.dma;
-#ifdef YMF_DEBUG
-	printk(PFX "set DMA address at 0x%x\n",card->sb_data.dma);
-#endif
-
-	v = 0x0000 | ((dma&0x03)<<6) | 0x003f;
-	pci_write_config_word(pcidev, YMFSB_PCIR_LEGCTRL, v);
-#ifdef YMF_DEBUG
-	printk(PFX "LEGCTRL: 0x%x\n",v);
-#endif
-	switch( pcidev->device ) {
-	case PCI_DEVICE_ID_YMF724:
-	case PCI_DEVICE_ID_YMF740:
-	case PCI_DEVICE_ID_YMF724F:
-	case PCI_DEVICE_ID_YMF740C:
-		v = 0x8800 | ((mpuio<<4)&0x03) | ((sbio<<2)&0x03) | (oplio&0x03);
-		pci_write_config_word(pcidev, YMFSB_PCIR_ELEGCTRL, v);
-#ifdef YMF_DEBUG
-		printk(PFX "ELEGCTRL: 0x%x\n",v);
-#endif
-		break;
-
-	case PCI_DEVICE_ID_YMF744:
-	case PCI_DEVICE_ID_YMF754:
-		v = 0x8800;
-		pci_write_config_word(pcidev, YMFSB_PCIR_ELEGCTRL, v);
-		pci_write_config_word(pcidev, YMFSB_PCIR_OPLADR, card->opl3_data.io_base);
-		pci_write_config_word(pcidev, YMFSB_PCIR_SBADR,  card->sb_data.io_base);
-		pci_write_config_word(pcidev, YMFSB_PCIR_MPUADR, card->mpu_data.io_base);
-		break;
-
-	default:
-		printk(KERN_ERR PFX "Invalid device ID: %d\n",pcidev->device);
-		return -EINVAL;
-		break;
-	}
-
-	return 0;
-}
-
-/* ---------------------------------------------------------------------- */
-/* AC'97 stuff */
-static int ymfsb_readAC97Reg( struct ac97_hwint *dev, u8 reg )
-{
-	struct ymf_card *card = (struct ymf_card *)dev->driver_private;
-	unsigned long flags;
-	int ret;
-
-	if ( reg > 0x7f ) return -EINVAL;
-
-	save_flags(flags);
-	cli();
-	writeRegWord( card, YMFSB_AC97CMDADR, 0x8000 | reg );
-	if ( checkPrimaryBusy( card ) ) {
-		restore_flags(flags);
-		return -EBUSY;
-	}
-	ret = readRegWord( card, YMFSB_AC97CMDDATA );
-	restore_flags(flags);
-
-	return ret;
-}
-
-static int ymfsb_writeAC97Reg( struct ac97_hwint *dev, u8 reg, u16 value )
-{
-	struct ymf_card *card = (struct ymf_card *)dev->driver_private;
-	unsigned long flags;
-
-	if ( reg > 0x7f ) return -EINVAL;
-
-	save_flags(flags);
-	cli();
-	if ( checkPrimaryBusy( card ) ) {
-	  restore_flags(flags);
-	  return -EBUSY;
-	}
-
-	writeRegWord( card, YMFSB_AC97CMDADR, 0x0000 | reg );
-	writeRegWord( card, YMFSB_AC97CMDDATA, value );
-
-	restore_flags(flags);
-	return 0;
-}
-
-struct initialValues
-{
-    unsigned short port;
-    unsigned short value;
-};
-
-static struct initialValues ymfsb_ac97_initial_values[] =
-{
-    { AC97_RESET,             0x0000 },
-    { AC97_MASTER_VOL_STEREO, 0x0000 },
-    { AC97_HEADPHONE_VOL,     0x8000 },
-    { AC97_PCMOUT_VOL,        0x0606 },
-    { AC97_MASTER_VOL_MONO,   0x0000 },
-    { AC97_PCBEEP_VOL,        0x0000 },
-    { AC97_PHONE_VOL,         0x0008 },
-    { AC97_MIC_VOL,           0x8000 },
-    { AC97_LINEIN_VOL,        0x8808 },
-    { AC97_CD_VOL,            0x8808 },
-    { AC97_VIDEO_VOL,         0x8808 },
-    { AC97_AUX_VOL,           0x8808 },
-    { AC97_RECORD_SELECT,     0x0000 },
-    { AC97_RECORD_GAIN,       0x0B0B },
-    { AC97_GENERAL_PURPOSE,   0x0000 },
-    { 0xffff, 0xffff }
-};
-
-static int ymfsb_resetAC97( struct ac97_hwint *dev )
-{
-	int i;
-
-	for ( i=0 ; ymfsb_ac97_initial_values[i].port != 0xffff ; i++ )
-	{
-		ac97_put_register ( dev,
-				    ymfsb_ac97_initial_values[i].port,
-				    ymfsb_ac97_initial_values[i].value );
-	}
-
-	return 0;
-}
-
-static int ymfsb_ac97_mixer_ioctl( int dev, unsigned int cmd, caddr_t arg )
-{
-	int i;
-
-	for ( i=0 ; i < MAX_CARDS ; i++ )
-	{
-		if ( ymf_cards[i].mixer_oss_dev == dev ) break;
-	}
-
-	if ( i < MAX_CARDS )
-		return ac97_mixer_ioctl(&(ymf_cards[i].ac97_dev), cmd, arg);
-	else
-		return -ENODEV;
-}
-
-static struct mixer_operations ymfsb_ac97_mixer_operations = {
-	"YAMAHA",
-	"YAMAHA PCI",
-	ymfsb_ac97_mixer_ioctl
-};
-
-static struct ac97_mixer_value_list ymfsb_ac97_mixer_defaults[] = {
-    { SOUND_MIXER_VOLUME,  { { 85, 85 } } },
-    { SOUND_MIXER_SPEAKER, { { 100 } } },
-    { SOUND_MIXER_PCM,     { { 65, 65 } } },
-    { SOUND_MIXER_CD,      { { 65, 65 } } },
-    { -1,                  {  { 0,  0 } } }
-};
-
-/* ---------------------------------------------------------------------- */
-
-static void enableDSP( struct ymf_card *card )
-{
-	writeRegDWord( card, YMFSB_CONFIG, 0x00000001 );
-	return;
-}
-
-static void disableDSP( struct ymf_card *card )
-{
-	int val;
-	int i;
-
-	val = readRegDWord( card, YMFSB_CONFIG );
-	if ( val ) {
-		writeRegDWord( card, YMFSB_CONFIG, 0 );
-	}
-
-	i=0;
-	while( ++i < YMFSB_WORKBITTIMEOUT ) {
-		val = readRegDWord( card, YMFSB_STATUS );
-		if ( (val & 0x00000002) == 0x00000000 ) break;
-	}
-
-	return;
-}
-
-static int setupInstruction( struct ymf_card *card, struct pci_dev *pcidev )
-{
-	int i;
-	int val;
-
-	writeRegDWord( card, YMFSB_NATIVEDACOUTVOL, 0 ); /* mute dac */
-	disableDSP( card );
-
-	writeRegDWord( card, YMFSB_MODE, 0x00010000 );
-
-	/* DS-XG Software Reset */
-	writeRegDWord( card, YMFSB_MODE,         0x00000000 );
-	writeRegDWord( card, YMFSB_MAPOFREC,     0x00000000 );
-	writeRegDWord( card, YMFSB_MAPOFEFFECT,  0x00000000 );
-	writeRegDWord( card, YMFSB_PLAYCTRLBASE, 0x00000000 );
-	writeRegDWord( card, YMFSB_RECCTRLBASE,  0x00000000 );
-	writeRegDWord( card, YMFSB_EFFCTRLBASE,  0x00000000 );
-
-	val = readRegWord( card, YMFSB_GLOBALCTRL );
-	writeRegWord( card, YMFSB_GLOBALCTRL, (val&~0x0007) );
-
-	/* setup DSP instruction code */
-	for ( i=0 ; i<YMFSB_DSPLENGTH ; i+=4 ) {
-	  writeRegDWord( card, YMFSB_DSPINSTRAM+i, DspInst[i>>2] );
-	}
-
-	switch( pcidev->device ) {
-	case PCI_DEVICE_ID_YMF724:
-	case PCI_DEVICE_ID_YMF740:
-		/* setup Control instruction code */
-		for ( i=0 ; i<YMFSB_CTRLLENGTH ; i+=4 ) {
-			writeRegDWord( card, YMFSB_CTRLINSTRAM+i, CntrlInst[i>>2] );
-		}
-		break;
-
-	case PCI_DEVICE_ID_YMF724F:
-	case PCI_DEVICE_ID_YMF740C:
-	case PCI_DEVICE_ID_YMF744:
-	case PCI_DEVICE_ID_YMF754:
-		/* setup Control instruction code */
-	
-		for ( i=0 ; i<YMFSB_CTRLLENGTH ; i+=4 ) {
-			writeRegDWord( card, YMFSB_CTRLINSTRAM+i, CntrlInst1E[i>>2] );
-		}
-		break;
-
-	default:
-		return -ENXIO;
-	}
-
-	enableDSP( card );
-
-	return 0;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static int __init ymf7xx_init( struct ymf_card *card, struct pci_dev *pcidev )
-{
-	unsigned short v;
-	int mixer;
-
-	/* Read hardware information */
-#ifdef YMF_DEBUG
-	unsigned int   dv;
-	pci_read_config_word(pcidev, YMFSB_PCIR_VENDORID, &v);
-	printk(KERN_INFO PFX "Vendor ID = 0x%x\n",v);
-	pci_read_config_word(pcidev, YMFSB_PCIR_DEVICEID, &v);
-	printk(KERN_INFO PFX "Device ID = 0x%x\n",v);
-	pci_read_config_word(pcidev, YMFSB_PCIR_REVISIONID, &v);
-	printk(KERN_INFO PFX "Revision ID = 0x%x\n",v&0xff);
-	pci_read_config_dword(pcidev, YMFSB_PCIR_BASEADDR, &dv);
-	printk(KERN_INFO PFX "Base address = 0x%x\n",dv);
-	pci_read_config_word(pcidev, YMFSB_PCIR_IRQ, &v);
-	printk(KERN_INFO PFX "IRQ line = 0x%x\n",v&0xff);
-#endif
-
-	/* enables memory space access / bus mastering */
-	pci_read_config_word(pcidev, YMFSB_PCIR_CMD, &v);
-	pci_write_config_word(pcidev, YMFSB_PCIR_CMD, v|0x06);
-
-	/* check codec */
-#ifdef YMF_DEBUG
-	printk(KERN_INFO PFX "check codec...\n");
-#endif
-	if (checkCodec(card, pcidev)) return -EBUSY;
-
-	/* setup legacy I/O */
-#ifdef YMF_DEBUG
-	printk(KERN_INFO PFX "setup legacy I/O...\n");
-#endif
-	if (setupLegacyIO(card, pcidev)) return -EBUSY;
-	
-	/* setup instruction code */	
-#ifdef YMF_DEBUG
-	printk(KERN_INFO PFX "setup instructions...\n");
-#endif
-	if (setupInstruction(card, pcidev)) return -EBUSY;
-
-	/* AC'97 setup */	
-#ifdef YMF_DEBUG
-	printk(KERN_INFO PFX "setup AC'97...\n");
-#endif
-	if ( ac97_init( &card->ac97_dev ) ) return -EBUSY;
-
-	mixer = sound_alloc_mixerdev();
-	if ( num_mixers >= MAX_MIXER_DEV ) return -EBUSY;
-	
-	mixer_devs[mixer] = &ymfsb_ac97_mixer_operations;
-	card->mixer_oss_dev = mixer;
-	ac97_set_values( &card->ac97_dev, ymfsb_ac97_mixer_defaults );
-
-#ifdef YMF_DEBUG
-	printk(KERN_INFO PFX "setup Legacy Volume...\n");
-#endif
-	/* Legacy Audio Output Volume L & R ch */
-	writeRegDWord( card, YMFSB_LEGACYOUTVOL, 0x3fff3fff );
-
-#ifdef YMF_DEBUG
-	printk(KERN_INFO PFX "setup SPDIF output control...\n");
-#endif
-	/* SPDIF Output control */
-	v = spdif_out != 0 ? 0x0001 : 0x0000;
-	writeRegWord( card, YMFSB_SPDIFOUTCTRL, v );
-	/* no copyright protection, 
-	   sample-rate converted,
-	   re-recorded software comercially available (the 1st generation),
-	   original */
-	writeRegWord( card, YMFSB_SPDIFOUTSTATUS, 0x9a04 );
-
-	return 0;
-}
-
-/* ---------------------------------------------------------------------- */
-
-static void __init ymf7xxsb_attach_sb(struct address_info *hw_config)
-{
-	hw_config->driver_use_1 |= SB_NO_MIXER;
-	if(!sb_dsp_init(hw_config))
-		hw_config->slots[0] = -1;
-}
-
-static int __init ymf7xxsb_probe_sb(struct address_info *hw_config)
-{
-	if (check_region(hw_config->io_base, 16))
-	{
-		printk(KERN_DEBUG PFX "SBPro port 0x%x is already in use\n",
-		       hw_config->io_base);
-		return 0;
-	}
-	return sb_dsp_detect(hw_config, SB_PCI_YAMAHA, 0);
-}
-
-
-static void ymf7xxsb_unload_sb(struct address_info *hw_config, int unload_mpu)
-{
-	if(hw_config->slots[0]!=-1)
-		sb_dsp_unload(hw_config, unload_mpu);
-}
-
-/* ---------------------------------------------------------------------- */
-
-static int __init ymf7xxsb_install (struct pci_dev *pcidev)
-{
-	struct {
-		unsigned short deviceid;
-		char           *devicename;
-	} devicetable[] = 
-	{
-		{ PCI_DEVICE_ID_YMF724,  "YMF724A-E" },
-		{ PCI_DEVICE_ID_YMF724F, "YMF724F" },
-		{ PCI_DEVICE_ID_YMF740,  "YMF740A-B" },
-		{ PCI_DEVICE_ID_YMF740C, "YMF740C" },
-		{ PCI_DEVICE_ID_YMF744,  "YMF744" },
-		{ PCI_DEVICE_ID_YMF754,  "YMF754" },
-	};
-
-	char		*devicename = "unknown";
-	int		i;
-	unsigned long   iobase;
-	struct ymf_card *card;
-
-	if ( pcidev->irq == 0 ) return -ENODEV;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
-	if ( pci_enable_device(pcidev) ) {
-		printk (KERN_ERR PFX "cannot enable PCI device\n");
-		return -EIO;
-	}
-#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,13)
-	iobase = pcidev->base_address[0]&PCI_BASE_ADDRESS_MEM_MASK;
-#else
-	iobase = pcidev->resource[0].start&PCI_BASE_ADDRESS_MEM_MASK;
-#endif
-	if ( iobase == 0x00000000 ) return -ENODEV;
-
-	for ( i=0 ; i<sizeof(devicetable) / sizeof(devicetable[0]); i++ )
-	{
-		if (devicetable[i].deviceid == pcidev->device)
-		{
-			devicename = devicetable[i].devicename;
-			break;
-		}
-	}
-
-	card = &ymf_cards[cards];
-
-	/* remap memory mapped I/O onto kernel virtual memory */
-	if ( (card->ymfbase = ioremap_nocache(iobase, YMFSB_REGSIZE)) == 0 )
-	{
-		printk(KERN_ERR PFX "ioremap (0x%lx) returns zero\n", iobase);
-		return -ENODEV;
-	}
-	printk(KERN_INFO PFX "found %s at 0x%lx\n", devicename, iobase);
-#ifdef YMF_DEBUG
-	printk(KERN_INFO PFX "remappling to 0x%p\n", card->ymfbase);
-#endif
-
-	memset (&card->sb_data,   0, sizeof (struct address_info));
-	memset (&card->opl3_data, 0, sizeof (struct address_info));
-	memset (&card->mpu_data,  0, sizeof (struct address_info));
-	memset (&card->ac97_dev,  0, sizeof (struct ac97_hwint));
-
-	card->card = cards;
-
-	card->sb_data.name   = YMFSB_CARD_NAME;
-	card->opl3_data.name = YMFSB_CARD_NAME;
-	card->mpu_data.name  = YMFSB_CARD_NAME;
-
-	card->sb_data.card_subtype = MDL_YMPCI;
-
-	if ( io == 0 ) io      = 0x220;
-	card->sb_data.io_base = io;
-	card->sb_data.irq     = pcidev->irq;
-	card->sb_data.dma     = dma;
-
-	if ( synth_io == 0 ) synth_io = 0x388;
-	card->opl3_data.io_base = synth_io;
-	card->opl3_data.irq     = -1;
-
-	if ( mpu_io == 0 ) mpu_io = 0x330;
-	card->mpu_data.io_base = mpu_io;
-	card->mpu_data.irq     = -1;
-
-	card->ac97_dev.reset_device   = ymfsb_resetAC97;
-	card->ac97_dev.read_reg       = ymfsb_readAC97Reg;
-	card->ac97_dev.write_reg      = ymfsb_writeAC97Reg;
-	card->ac97_dev.driver_private = (void *)card;
-
-	if ( ymf7xx_init(card, pcidev) ) {
-		printk (KERN_ERR PFX
-			"Cannot initialize %s, aborting\n",
-			devicename);
-		return -ENODEV;
-	}
-
-	/* regist legacy SoundBlaster Pro */
-	if (!ymf7xxsb_probe_sb(&card->sb_data)) {
-		printk (KERN_ERR PFX
-			"SB probe at 0x%X failed, aborting\n",
-			io);
-		return -ENODEV;
-	}
-	ymf7xxsb_attach_sb (&card->sb_data);
-
-	/* regist legacy MIDI */
-	if ( mpu_io > 0 && 0)
-	{
-		if (!ymf7xxsb_probe_midi (&card->mpu_data)) {
-			printk (KERN_ERR PFX
-				"MIDI probe @ 0x%X failed, aborting\n",
-				mpu_io);
-			ymf7xxsb_unload_sb (&card->sb_data, 0);
-			return -ENODEV;
-		}
-		ymf7xxsb_attach_midi (&card->mpu_data);
-	}
-
-	/* regist legacy OPL3 */
-
-	cards++;	
-	return 0;
-}
-
-static int __init probe_ymf7xxsb (void)
-{
-	struct pci_dev *pcidev = NULL;
-	int i;
-
-	for (i=0 ; i<MAX_CARDS ; i++ )
-		ymf_cards[i].ymfbase = NULL;
-
-	while ( pcidev == NULL && (
-	       (pcidev = pci_find_device (PCI_VENDOR_ID_YAMAHA,
-					  PCI_DEVICE_ID_YMF724, pcidev)) ||
-	       (pcidev = pci_find_device (PCI_VENDOR_ID_YAMAHA,
-					  PCI_DEVICE_ID_YMF724F,pcidev)) ||
-	       (pcidev = pci_find_device (PCI_VENDOR_ID_YAMAHA,
-					  PCI_DEVICE_ID_YMF740, pcidev)) ||
-	       (pcidev = pci_find_device (PCI_VENDOR_ID_YAMAHA,
-					  PCI_DEVICE_ID_YMF740C,pcidev)) ||
-	       (pcidev = pci_find_device (PCI_VENDOR_ID_YAMAHA,
-					  PCI_DEVICE_ID_YMF744, pcidev)) ||
-	       (pcidev = pci_find_device (PCI_VENDOR_ID_YAMAHA,
-					  PCI_DEVICE_ID_YMF754, pcidev)))) {
-		  if (ymf7xxsb_install (pcidev)) {
-			  printk (KERN_ERR PFX "audio init failed\n");
-			  return -ENODEV;
-		  }
-
-		  if (cards == MAX_CARDS) {
-		  	  printk (KERN_DEBUG PFX "maximum number of cards reached\n");
-			  break;
-		  }
-	}
-
-	return 0;
-}
-
-static void free_iomaps( void )
-{
-	int i;
-
-	for ( i=0 ; i<MAX_CARDS ; i++ ) {
-		if ( ymf_cards[i].ymfbase!=NULL )
-			iounmap(ymf_cards[i].ymfbase);
-	}
-
-	return;
-}
-
-int __init init_ymf7xxsb_module(void)
-{
-	if (!pci_present ()) {
-		printk (KERN_DEBUG PFX "PCI not present, exiting\n");
-		return -ENODEV;
-	}
-
-	if (probe_ymf7xxsb()) {
-		printk(KERN_ERR PFX "probe failed, aborting\n");
-		/* XXX unload cards registered so far, if any */
-		free_iomaps();
-		return -ENODEV;
-	}
-
-	if (cards == 0) {
-		printk(KERN_DEBUG PFX "No chips found, aborting\n");
-		free_iomaps();
-		return -ENODEV;
-	}
-
-	printk (KERN_INFO PFX YMFSB_CARD_NAME " loaded\n");
-	
-	/*
-	 *	Binds us to the sound subsystem	
-	 */
-	SOUND_LOCK;
-	return 0;
-}
-
-static void cleanup_ymf7xxsb_module(void)
-{
-	int i;
-	
-	for (i = 0; i < cards; i++) {
-		ymf7xxsb_unload_sb (&(ymf_cards[i].sb_data), 0);
-		ymf7xxsb_unload_midi (&(ymf_cards[i].mpu_data));
-		if ( ymf_cards[i].mixer_oss_dev >= 0 ) 
-			sound_unload_mixerdev( ymf_cards[i].mixer_oss_dev );
-	}
-
-	free_iomaps();
-
-	/*
-	 *	Final clean up with the sound layer
-	 */
-	SOUND_LOCK_END;
-}
-
-#ifdef MODULE
-
-MODULE_AUTHOR("Daisuke Nagano, breeze.nagano@nifty.ne.jp");
-MODULE_DESCRIPTION("YMF7xx Legacy Audio Driver");
-
-int init_module(void)
-{
-	return init_ymf7xxsb_module();
-}
-
-void cleanup_module(void)
-{
-	cleanup_ymf7xxsb_module();
-}
-
-#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/ymfpci.c linux.19p18/drivers/sound/ymfpci.c
--- linux.vanilla/drivers/sound/ymfpci.c	Mon Dec 11 22:12:57 2000
+++ linux.19p18/drivers/sound/ymfpci.c	Tue Jan  9 11:52:06 2001
@@ -46,6 +46,9 @@
 #include <asm/dma.h>
 #include <asm/uaccess.h>
 
+#ifdef CONFIG_SOUND_YMFPCI_LEGACY
+# include "sound_config.h"
+#endif
 #include "ymfpci.h"
 
 #define snd_magic_cast(t, p, err)	((t *)(p))
@@ -59,7 +62,7 @@
     int pair, ymfpci_voice_t **rvoice);
 static int ymfpci_voice_free(ymfpci_t *codec, ymfpci_voice_t *pvoice);
 static int ymf_playback_prepare(ymfpci_t *codec, struct ymf_state *state);
-static int ymf_state_alloc(ymfpci_t *unit, int nvirt, int instance);
+static int ymf_state_alloc(ymfpci_t *unit, int nvirt);
 
 static ymfpci_t *ymf_devs = NULL;
 
@@ -600,11 +603,9 @@
 	char silence;
 
 	if ((ypcm = voice->ypcm) == NULL) {
-/* P3 */ printk("ymf_pcm_interrupt: voice %d: no ypcm\n", voice->number);
 		return;
 	}
 	if ((state = ypcm->state) == NULL) {
-/* P3 */ printk("ymf_pcm_interrupt: voice %d: no state\n", voice->number);
 		ypcm->running = 0;	// lock it
 		return;
 	}
@@ -626,7 +627,7 @@
 		if (pos < 0 || pos >= dmabuf->dmasize) {	/* ucode bug */
 			printk(KERN_ERR
 			    "ymfpci%d: %d: runaway: hwptr %d dmasize %d\n",
-			    codec->inst, voice->number,
+			    codec->dev_audio, voice->number,
 			    dmabuf->hwptr, dmabuf->dmasize);
 			pos = 0;
 		}
@@ -643,7 +644,7 @@
 
 		if (dmabuf->count == 0) {
 			printk("ymfpci%d: %d: strain: hwptr %d\n",
-			    codec->inst, voice->number, dmabuf->hwptr);
+			    codec->dev_audio, voice->number, dmabuf->hwptr);
 			ymf_playback_trigger(codec, ypcm, 0);
 		}
 
@@ -662,7 +663,7 @@
 				 */
 				printk("ymfpci%d: %d: lost: delta %d"
 				    " hwptr %d swptr %d distance %d count %d\n",
-				    codec->inst, voice->number, delta,
+				    codec->dev_audio, voice->number, delta,
 				    dmabuf->hwptr, swptr, distance, dmabuf->count);
 			} else {
 				/*
@@ -670,7 +671,7 @@
 				 */
 //				printk("ymfpci%d: %d: done: delta %d"
 //				    " hwptr %d swptr %d distance %d count %d\n",
-//				    codec->inst, voice->number, delta,
+//				    codec->dev_audio, voice->number, delta,
 //				    dmabuf->hwptr, swptr, distance, dmabuf->count);
 			}
 			played = dmabuf->count;
@@ -736,7 +737,6 @@
 {
 
 	if (ypcm->voices[0] == NULL) {
-/* P3 */ printk("ymfpci: trigger %d no voice\n", cmd);
 		return -EINVAL;
 	}
 	if (cmd != 0) {
@@ -826,8 +826,8 @@
 		end >>= 1;
 	if (w_16)
 		end >>= 1;
-/* P3 */ // printk("ymf_pcm_init_voice: %d: Rate %d Format 0x%08x Delta 0x%x End 0x%x\n",
-//  voice->number, rate, format, delta, end);
+/* P3 */ /** printk("ymf_pcm_init_voice: %d: Rate %d Format 0x%08x Delta 0x%x End 0x%x\n",
+  voice->number, rate, format, delta, end); **/
 	for (nbank = 0; nbank < 2; nbank++) {
 		bank = &voice->bank[nbank];
 		bank->format = format;
@@ -909,7 +909,7 @@
 	if ((err = ymfpci_pcm_voice_alloc(ypcm, state->format.voices)) < 0) {
 		/* Cannot be unless we leak voices in ymf_release! */
 		printk(KERN_ERR "ymfpci%d: cannot allocate voice!\n",
-		    codec->inst);
+		    codec->dev_audio);
 		return err;
 	}
 
@@ -1027,6 +1027,12 @@
 			if (voice->interrupt)
 				voice->interrupt(codec, voice);
 		}
+#if HAVE_RECORD
+		for (nvoice = 0; nvoice < 5; nvoice++) {
+			if (codec->capture_substream[nvoice])
+				snd_ymfpci_pcm_capture_interrupt(codec->capture_substream[nvoice]);
+		}
+#endif
 		spin_unlock(&codec->voice_lock);
 	}
 
@@ -1050,7 +1056,7 @@
 	}
 }
 
-static int ymf_state_alloc(ymfpci_t *unit, int nvirt, int instance)
+static int ymf_state_alloc(ymfpci_t *unit, int nvirt)
 {
 	ymfpci_pcm_t *ypcm;
 	struct ymf_state *state;
@@ -1536,12 +1542,13 @@
 		return put_user(SOUND_VERSION, (int *)arg);
 
 	case SNDCTL_DSP_RESET:
-		/* FIXME: spin_lock ? */
 		if (file->f_mode & FMODE_WRITE) {
 			ymf_wait_dac(state);
+			// spin_lock_irqsave(&state->unit->reg_lock, flags);
 			dmabuf->ready = 0;
 			dmabuf->swptr = dmabuf->hwptr = 0;
 			dmabuf->count = dmabuf->total_bytes = 0;
+			// spin_unlock_irqrestore(&state->unit->reg_lock, flags);
 		}
 #if HAVE_RECORD
 		if (file->f_mode & FMODE_READ) {
@@ -1570,9 +1577,7 @@
 
 	case SNDCTL_DSP_SPEED: /* set smaple rate */
 		get_user_ret(val, (int *)arg, -EFAULT);
-	/* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_SPEED %d\n", val); */
 		if (val >= 8000 && val <= 48000) {
-			spin_lock_irqsave(&state->unit->reg_lock, flags);
 			if (file->f_mode & FMODE_WRITE) {
 				ymf_wait_dac(state);
 			}
@@ -1581,6 +1586,7 @@
 				stop_adc(state);
 			}
 #endif
+			spin_lock_irqsave(&state->unit->reg_lock, flags);
 			dmabuf->ready = 0;
 			state->format.rate = val;
 			ymf_pcm_update_shift(&state->format);
@@ -1596,7 +1602,6 @@
 	 */
 	case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
 		get_user_ret(val, (int *)arg, -EFAULT);
-	/* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_STEREO %d\n", val); */
 		if (file->f_mode & FMODE_WRITE) {
 			ymf_wait_dac(state); 
 			spin_lock_irqsave(&state->unit->reg_lock, flags);
@@ -1618,7 +1623,6 @@
 		return 0;
 
 	case SNDCTL_DSP_GETBLKSIZE:
-	/* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_GETBLKSIZE\n"); */
 		if (file->f_mode & FMODE_WRITE) {
 			if ((val = prog_dmabuf(state, 0)))
 				return val;
@@ -1632,14 +1636,11 @@
 		return -EINVAL;
 
 	case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/
-	/* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_GETFMTS\n"); */
 		return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg);
 
 	case SNDCTL_DSP_SETFMT: /* Select sample format */
 		get_user_ret(val, (int *)arg, -EFAULT);
-	/* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_SETFMT 0x%x\n", val); */
 		if (val == AFMT_S16_LE || val == AFMT_U8) {
-			spin_lock_irqsave(&state->unit->reg_lock, flags);
 			if (file->f_mode & FMODE_WRITE) {
 				ymf_wait_dac(state);
 			}
@@ -1648,6 +1649,7 @@
 				stop_adc(state);
 			}
 #endif
+			spin_lock_irqsave(&state->unit->reg_lock, flags);
 			dmabuf->ready = 0;
 			state->format.format = val;
 			ymf_pcm_update_shift(&state->format);
@@ -1657,15 +1659,15 @@
 
 	case SNDCTL_DSP_CHANNELS:
 		get_user_ret(val, (int *)arg, -EFAULT);
-	/* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_CHANNELS 0x%x\n", val); */
 		if (val != 0) {
-			spin_lock_irqsave(&state->unit->reg_lock, flags);
 			if (file->f_mode & FMODE_WRITE) {
 				ymf_wait_dac(state);
 				if (val == 1 || val == 2) {
+					spin_lock_irqsave(&state->unit->reg_lock, flags);
 					dmabuf->ready = 0;
 					state->format.voices = val;
 					ymf_pcm_update_shift(&state->format);
+					spin_unlock_irqrestore(&state->unit->reg_lock, flags);
 				}
 			}
 #if HAVE_RECORD
@@ -1674,7 +1676,6 @@
 				dmabuf->ready = 0;
 			}
 #endif
-			spin_unlock_irqrestore(&state->unit->reg_lock, flags);
 		}
 		return put_user(state->format.voices, (int *)arg);
 
@@ -1690,7 +1691,6 @@
 		 * The paragraph above is a clumsy way to say "flush ioctl".
 		 * This ioctl is used by mpg123.
 		 */
-	/* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_POST\n"); */
 		spin_lock_irqsave(&state->unit->reg_lock, flags);
 		if (dmabuf->count != 0 && !state->ypcm.running) {
 			ymf_start_dac(state);
@@ -1726,7 +1726,6 @@
 		return 0;
 
 	case SNDCTL_DSP_GETOSPACE:
-	/* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_GETOSPACE\n"); */
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
 		if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
@@ -1757,12 +1756,10 @@
 #endif
 
 	case SNDCTL_DSP_NONBLOCK:
-	/* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_NONBLOCK\n"); */
 		file->f_flags |= O_NONBLOCK;
 		return 0;
 
 	case SNDCTL_DSP_GETCAPS:
-	/* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_GETCAPS\n"); */
 		/* return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP,
 			    (int *)arg); */
 		return put_user(0, (int *)arg);
@@ -1814,7 +1811,6 @@
 #endif
 
 	case SNDCTL_DSP_GETOPTR:
-	/* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_GETOPTR\n"); */
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
 		spin_lock_irqsave(&state->unit->reg_lock, flags);
@@ -1828,7 +1824,6 @@
 		return copy_to_user((void *)arg, &cinfo, sizeof(cinfo));
 
 	case SNDCTL_DSP_SETDUPLEX:	/* XXX TODO */
-	/* P3 */ /* printk("ymfpci: ioctl SNDCTL_DSP_SETDUPLEX\n"); */
 		return -EINVAL;
 
 #if 0 /* old */
@@ -1859,7 +1854,7 @@
 		return -ENOTTY;
 
 	default:
-	/* P3 */ printk("ymfpci: ioctl cmd 0x%x\n", cmd);
+	/* P3 */ /* printk("ymfpci: ioctl cmd 0x%x\n", cmd); */
 		/*
 		 * Some programs mix up audio devices and ioctls
 		 * or perhaps they expect "universal" ioctls,
@@ -1870,10 +1865,94 @@
 	return -ENOTTY;
 }
 
+#ifdef CONFIG_SOUND_YMFPCI_LEGACY
+/* MIDI stuff */
+
+/* */
+
+static int ymfpci_setup_legacy( ymfpci_t *codec, struct pci_dev *pcidev )
+{
+	int v;
+	int mpuio=-1, oplio=-1;
+
+	switch(codec->iomidi) {
+	case 0x330:
+		mpuio = 0;
+		break;
+	case 0x300:
+		mpuio = 1;
+		break;
+	case 0x332:
+		mpuio = 2;
+		break;
+	case 0x334:
+		mpuio = 3;
+		break;
+	default:
+		break;
+	}
+
+	switch(codec->iosynth) {
+	case 0x388:
+		oplio = 0;
+		break;
+	case 0x398:
+		oplio = 1;
+		break;
+	case 0x3a0:
+		oplio = 2;
+		break;
+	case 0x3a8:
+		oplio = 3;
+		break;
+	default:
+		break;
+	}
+
+	if ( mpuio >= 0 || oplio >= 0 ) {
+		v = 0x003e;
+		pci_write_config_word(pcidev, PCIR_LEGCTRL, v);
+	
+		switch( pcidev->device ) {
+		case PCI_DEVICE_ID_YAMAHA_724:
+		case PCI_DEVICE_ID_YAMAHA_740:
+		case PCI_DEVICE_ID_YAMAHA_724F:
+		case PCI_DEVICE_ID_YAMAHA_740C:
+			v = 0x8800;
+			if ( mpuio >= 0 ) { v|= mpuio<<4; }
+			if ( oplio >= 0 ) { v|= oplio; }
+			pci_write_config_word(pcidev, PCIR_ELEGCTRL, v);
+			break;
+
+		case PCI_DEVICE_ID_YAMAHA_744:
+		case PCI_DEVICE_ID_YAMAHA_754:
+			v = 0x8800;
+			pci_write_config_word(pcidev, PCIR_ELEGCTRL, v);
+			if ( oplio >= 0 ) {
+				pci_write_config_word(pcidev, PCIR_OPLADR, codec->iosynth);
+			}
+			if ( mpuio >= 0 ) {
+				pci_write_config_word(pcidev, PCIR_MPUADR, codec->iomidi);
+			}
+		break;
+
+		default:
+			printk(KERN_ERR "ymfpci: Invalid device ID: %d\n",pcidev->device);
+			return -EINVAL;
+			break;
+		}
+	}
+
+	return 0;
+}
+#endif /* CONFIG_SOUND_YMFPCI_LEGACY */
+
+/* */
+
 static int ymf_open(struct inode *inode, struct file *file)
 {
 	ymfpci_t *unit;
-	int minor, instance;
+	int minor;
 	struct ymf_state *state;
 	int nvirt;
 	int err;
@@ -1890,21 +1969,21 @@
 	} else {
 		return -ENXIO;
 	}
-	instance = (minor >> 4) & 0x0F;
 	nvirt = 0;			/* Such is the partitioning of minor */
 
-	/* XXX Semaphore here! */
 	for (unit = ymf_devs; unit != NULL; unit = unit->next) {
-		if (unit->inst == instance) break;
+		if (((unit->dev_audio ^ minor) & ~0x0f) == 0) break;
 	}
 	if (unit == NULL) return -ENODEV;
 
+	down(&unit->open_sem);
 	if (unit->states[nvirt] != NULL) {
-		/* P3 */ printk("ymfpci%d: busy\n", unit->inst);
+		up(&unit->open_sem);
 		return -EBUSY;
 	}
 
-	if ((err = ymf_state_alloc(unit, nvirt, instance)) != 0) {
+	if ((err = ymf_state_alloc(unit, nvirt)) != 0) {
+		up(&unit->open_sem);
 		return err;
 	}
 	state = unit->states[nvirt];
@@ -1912,11 +1991,12 @@
 	file->private_data = state;
 
 	/*
-	 * XXX This ymf_playback_prepare is totally unneeded here.
-	 * The question is if we want to allow write to fail if
-	 * prog_dmabuf fails... Say, no memory in DMA zone?
+	 * ymf_read and ymf_write that we borrowed from cs46xx
+	 * allocate buffers with prog_dmabuf(). We call prog_dmabuf
+	 * here so that in case of DMA memory exhaustion open
+	 * fails rather than write.
 	 */
-	if ((err = ymf_playback_prepare(unit, state)) != 0) {
+	if (!state->dmabuf.ready && (err = prog_dmabuf(state, 0))) {
 		/* XXX This recovery is ugly as hell. */
 
 		ymf_pcm_free_substream(&state->ypcm);
@@ -1924,6 +2004,7 @@
 		unit->states[state->virt] = NULL;
 		kfree(state);
 
+		up(&unit->open_sem);
 		return err;
 	}
 
@@ -1933,6 +2014,9 @@
 	    (YDSXGR_TIMERCTRL_TEN|YDSXGR_TIMERCTRL_TIEN));
 #endif
 
+	up(&unit->open_sem);
+	/* XXX Ask Alan why MOD_INC_USE_COUNT is outside the semaphore. */
+
 	MOD_INC_USE_COUNT;
 	return 0;
 }
@@ -1946,14 +2030,14 @@
 	ymfpci_writeb(codec, YDSXGR_TIMERCTRL, 0);
 #endif
 
-	/* XXX Use the semaphore to unrace us with opens */
-
 	if (state != codec->states[state->virt]) {
 		printk(KERN_ERR "ymfpci%d.%d: state mismatch\n",
-		    state->unit->inst, state->virt);
+		    state->unit->dev_audio, state->virt);
 		return -EIO;
 	}
 
+	down(&codec->open_sem);
+
 	/*
 	 * XXX Solve the case of O_NONBLOCK close - don't deallocate here.
 	 * Deallocate when unloading the driver and we can wait.
@@ -1965,6 +2049,8 @@
 	codec->states[state->virt] = NULL;
 	kfree(state);
 
+	up(&codec->open_sem);
+
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
@@ -2057,8 +2143,7 @@
 	if (val)
 		ymfpci_writel(codec, YDSXGR_CONFIG, 0x00000000);
 	while (timeout-- > 0) {
-		val = ymfpci_readl(codec, YDSXGR_CONFIG);
-		if ((val & 0x00000002) == 0)
+		if ((ymfpci_readl(codec, YDSXGR_STATUS) & 2) == 0)
 			break;
 	}
 }
@@ -2135,6 +2220,12 @@
 	ptr += 0x00ff;
 	(long)ptr &= ~0x00ff;
 
+	/*
+	 * Hardware requires only ptr[playback_ctrl_size] zeroed,
+	 * but in our judgement it is a wrong kind of savings, so clear it all.
+	 */
+	memset(ptr, 0, size);
+
 	codec->bank_base_playback = ptr;
 	codec->ctrl_playback = (u32 *)ptr;
 	codec->ctrl_playback[0] = YDSXG_PLAYBACK_VOICES;
@@ -2207,7 +2298,6 @@
 	codec->codec_write = ymfpci_codec_write;
 
 	if (ac97_probe_codec(codec) == 0) {
-		/* Alan does not have this printout. P3 */
 		printk("ymfpci: ac97_probe_codec failed\n");
 		return -ENODEV;
 	}
@@ -2234,6 +2324,20 @@
 	return 0;
 }
 
+/* */
+#ifdef CONFIG_SOUND_YMFPCI_LEGACY
+# ifdef MODULE
+static int mpu_io     = 0;
+static int synth_io   = 0;
+MODULE_PARM(mpu_io, "i");
+MODULE_PARM(synth_io, "i");
+# else
+static int mpu_io     = 0x330;
+static int synth_io   = 0x388;
+# endif
+#endif /* CONFIG_SOUND_YMFPCI_LEGACY */
+/* */
+
 static int /* __init */
 ymf_install(struct pci_dev *pcidev, int instance, int devx)
 {
@@ -2249,17 +2353,17 @@
 
 	spin_lock_init(&codec->reg_lock);
 	spin_lock_init(&codec->voice_lock);
+	codec->open_sem = MUTEX;
 	codec->pci = pcidev;
-	codec->inst = instance;
 	codec->irq = pcidev->irq;
 	codec->device_id = pcidev->device;
-	pci_read_config_byte(pcidev, PCI_REVISION_ID, (u8 *)&codec->rev);
+	pci_read_config_byte(pcidev, PCI_REVISION_ID, &codec->rev);
 	codec->reg_area_phys = pcidev->base_address[0]&PCI_BASE_ADDRESS_MEM_MASK;
 	codec->reg_area_virt = (unsigned long)ioremap(codec->reg_area_phys, 0x8000);
 	pci_set_master(pcidev);
 
-	/* XXX KERN_INFO */
-	printk("ymfpci%d: %s at 0x%lx IRQ %d\n", instance,
+	/* Not printing instance number because we use dev_audio elsewhere. */
+	printk(KERN_INFO "ymfpci: %s at 0x%lx IRQ %d\n",
 	    ymf_devv[devx].name, codec->reg_area_phys, codec->irq);
 
 	ymfpci_aclink_reset(pcidev);
@@ -2268,6 +2372,17 @@
 		return -ENODEV;
 	}
 
+#ifdef CONFIG_SOUND_YMFPCI_LEGACY
+	if (instance == 0) {
+		codec->iomidi = mpu_io;
+		codec->iosynth = synth_io;
+		if (ymfpci_setup_legacy(codec, pcidev) < 0) {
+			ymfpci_free(codec);
+			return -ENODEV;
+		}
+	}
+#endif
+
 	ymfpci_download_image(codec);
 
 	udelay(100); /* seems we need some delay after downloading image.. */
@@ -2280,15 +2395,15 @@
 	/* ymfpci_proc_init(card, codec); */
 
 	if (request_irq(codec->irq, ymf_interrupt, SA_SHIRQ, "ymfpci", codec) != 0) {
-		printk(KERN_ERR "ymfpci%d: unable to request IRQ %d\n",
-		    codec->inst, codec->irq);
+		printk(KERN_ERR "ymfpci: unable to request IRQ %d\n",
+		    codec->irq);
 		ymfpci_free(codec);
 		return -ENODEV;
 	}
 
 	/* register /dev/dsp */
 	if ((codec->dev_audio = register_sound_dsp(&ymf_fops, -1)) < 0) {
-		printk(KERN_ERR "ymfpci%d: unable to register dsp\n", codec->inst);
+		printk(KERN_ERR "ymfpci: unable to register dsp\n");
 		free_irq(codec->irq, codec);
 		ymfpci_free(codec);
 		return -ENODEV;
@@ -2304,6 +2419,24 @@
 		return err;
 	}
 
+#ifdef CONFIG_SOUND_YMFPCI_LEGACY
+
+	codec->opl3_data.name = "ymfpci";
+	codec->mpu_data.name  = "ymfpci";
+
+	codec->opl3_data.io_base = codec->iosynth;
+	codec->opl3_data.irq     = -1;
+
+	codec->mpu_data.io_base  = codec->iomidi;
+	codec->mpu_data.irq      = -1;	/* XXX Make it ours. */
+
+	if (codec->iomidi) {
+		if (probe_uart401(&codec->mpu_data)) {
+			attach_uart401(&codec->mpu_data);
+		}
+	}
+#endif /* CONFIG_SOUND_YMFPCI_LEGACY */
+
 	codec->next = ymf_devs;
 	ymf_devs = codec;
 
@@ -2339,6 +2472,11 @@
 		unregister_sound_mixer(codec->ac97_codec[0]->dev_mixer);
 		kfree(codec->ac97_codec[0]);
 	}
+#ifdef CONFIG_SOUND_YMFPCI_LEGACY
+	if (codec->iomidi) {
+		unload_uart401(&(codec->mpu_data));
+	}
+#endif /* CONFIG_SOUND_YMFPCI_LEGACY */
 	kfree(codec);
 }
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/sound/ymfpci.h linux.19p18/drivers/sound/ymfpci.h
--- linux.vanilla/drivers/sound/ymfpci.h	Mon Dec 11 22:12:57 2000
+++ linux.19p18/drivers/sound/ymfpci.h	Wed Jan  3 14:10:49 2001
@@ -131,7 +131,12 @@
 #define YDSXG_AC97READCMD		0x8000
 #define YDSXG_AC97WRITECMD		0x0000
 
+#define PCIR_LEGCTRL			0x40
+#define PCIR_ELEGCTRL			0x42
 #define PCIR_DSXGCTRL			0x48
+#define PCIR_OPLADR			0x60
+#define PCIR_SBADR			0x62
+#define PCIR_MPUADR			0x64
 
 #define YDSXG_DSPLENGTH			0x0080
 #define YDSXG_CTRLLENGTH		0x3000
@@ -242,27 +247,27 @@
 	ymfpci_pcm_type_t type;
 	struct ymf_state *state;
 	ymfpci_voice_t *voices[2];	/* playback only */
-	int running;			// +
+	int running;
 	int spdif;
 };
 
 struct ymf_unit {
 	unsigned int device_id;	/* PCI device ID */
-	unsigned int rev;	/* PCI revision */
+	unsigned char rev;	/* PCI revision */
 	unsigned long reg_area_phys;
 	unsigned long reg_area_virt;
 
-	void *work_ptr;				// +
+	void *work_ptr;
 
 	unsigned int bank_size_playback;
 	unsigned int bank_size_capture;
 	unsigned int bank_size_effect;
 	unsigned int work_size;
 
-	void *bank_base_playback;		// +
-	void *bank_base_capture;		// +
-	void *bank_base_effect;			// +
-	void *work_base;			// +
+	void *bank_base_playback;
+	void *bank_base_capture;
+	void *bank_base_effect;
+	void *work_base;
 
 	u32 *ctrl_playback;
 	ymfpci_playback_bank_t *bank_playback[YDSXG_PLAYBACK_VOICES][2];
@@ -279,16 +284,22 @@
 
 	struct pci_dev *pci;
 	int irq;
-	int inst;		/* Unit number (instance) */
+
+#ifdef CONFIG_SOUND_YMFPCI_LEGACY
+        /* legacy hardware resources */
+	unsigned int iosynth, iomidi;
+	struct address_info opl3_data, mpu_data;
+#endif
 
 	spinlock_t reg_lock;
 	spinlock_t voice_lock;
 
 	/* soundcore stuff */
 	int dev_audio;
+	struct semaphore open_sem;
 
-	ymfpci_t *next;					// *
-	struct ymf_state *states[1];			// *
+	ymfpci_t *next;
+	struct ymf_state *states[1];
 	/* ypcm may be the same thing as state, but not for record, effects. */
 };
 
@@ -336,16 +347,12 @@
 struct ymf_state {
 	struct ymf_unit *unit;			/* backpointer */
 
-	/* single open lock mechanism, only used for recording */
-	struct semaphore open_sem;
-	struct wait_queue *open_wait;
-
 	/* virtual channel number */
 	int virt;				// * unused a.t.m.
 
-	struct ymf_pcm ypcm;			// *
-	struct ymf_dmabuf dmabuf;		// *
-	struct ymf_pcm_format format;		// *
+	struct ymf_pcm ypcm;
+	struct ymf_dmabuf dmabuf;
+	struct ymf_pcm_format format;
 };
 
 #endif				/* __YMFPCI_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/Config.in linux.19p18/drivers/usb/Config.in
--- linux.vanilla/drivers/usb/Config.in	Mon Dec 11 22:12:58 2000
+++ linux.19p18/drivers/usb/Config.in	Mon Feb 12 15:05:30 2001
@@ -10,7 +10,6 @@
 
 comment 'Miscellaneous USB options'
    bool '  Preliminary USB device filesystem' CONFIG_USB_DEVICEFS
-   bool '  Support for hot-pluggable USB devices' CONFIG_HOTPLUG
    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       bool '  Enforce USB bandwidth allocation (EXPERIMENTAL)' CONFIG_USB_BANDWIDTH
    else
@@ -26,75 +25,58 @@
    fi
    dep_tristate '  OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB
 
-comment 'USB Devices'
-   dep_tristate '  USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
-   dep_tristate '  USB Scanner support' CONFIG_USB_SCANNER $CONFIG_USB
+   comment 'USB Device Class drivers'
    dep_tristate '  USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND
-   dep_tristate '  USB Modem (CDC ACM) support' CONFIG_USB_ACM $CONFIG_USB
-   dep_tristate '  USB Serial Converter support' CONFIG_USB_SERIAL $CONFIG_USB
-   if [ "$CONFIG_USB_SERIAL" != "n" ]; then
-      bool '    USB Generic Serial Driver' CONFIG_USB_SERIAL_GENERIC $CONFIG_USB_SERIAL
-      dep_tristate '    USB Handspring Visor Driver' CONFIG_USB_SERIAL_VISOR $CONFIG_USB_SERIAL
-      dep_tristate '    USB Digi International AccelePort USB Serial Driver' CONFIG_USB_SERIAL_DIGI_ACCELEPORT $CONFIG_USB_SERIAL
-      if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
-         dep_tristate '    USB ConnectTech WhiteHEAT Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_WHITEHEAT $CONFIG_USB_SERIAL
-         dep_tristate '    USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO $CONFIG_USB_SERIAL
-         dep_tristate '    USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA $CONFIG_USB_SERIAL
-         dep_tristate '    USB Keyspan USA-xxx Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN $CONFIG_USB_SERIAL
-         if [ "$CONFIG_USB_SERIAL_KEYSPAN" != "n" ]; then
-            bool '      USB Keyspan USA-28 Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28
-            bool '      USB Keyspan USA-28X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28X
-            bool '      USB Keyspan USA-19 Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19
-            bool '      USB Keyspan USA-18X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA18X
-            bool '      USB Keyspan USA-19W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19W
-         fi
-         dep_tristate '    USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_OMNINET $CONFIG_USB_SERIAL
-         dep_tristate '    USB Belkin and Peracom Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_BELKIN $CONFIG_USB_SERIAL
-      fi
-      bool '    USB Serial Converter verbose debug' CONFIG_USB_SERIAL_DEBUG $CONFIG_USB_SERIAL
-   fi
-   dep_tristate '  USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB $CONFIG_VIDEO_DEV
-   dep_tristate '  USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB $CONFIG_VIDEO_DEV
-   dep_tristate '  USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB
-   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-	   dep_tristate '  USB Mustek MDC800 Digital Camera support (EXPERIMENTAL)' CONFIG_USB_MDC800 $CONFIG_USB
-      dep_tristate '  USB Mass Storage support (EXPERIMENTAL)' CONFIG_USB_STORAGE $CONFIG_USB $CONFIG_SCSI
-      if [ "$CONFIG_USB_STORAGE" != "n" ]; then
-         bool '    USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG
-      fi
-   fi
-#   dep_tristate '  USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT
-   dep_tristate '  DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB
-   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-      dep_tristate '  PLUSB Prolific USB-Network driver (EXPERIMENTAL)' CONFIG_USB_PLUSB $CONFIG_USB $CONFIG_NET
-      dep_tristate '  USB ADMtek Pegasus-based device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB $CONFIG_NET
-      dep_tristate '  USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB
-      dep_tristate '  D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV
-#      dep_tristate '  Microtek X6USB scanner support (EXPERIMENTAL)' CONFIG_USB_MICROTEK $CONFIG_SCSI
-      dep_tristate '  USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB
-   fi
-   if [ "$CONFIG_NET" = "y" ]; then
-      dep_tristate '  Kawasaki USB-ethernet controller' CONFIG_USB_KAWETH $CONFIG_USB
+   dep_tristate '  USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB $CONFIG_EXPERIMENTAL
+   dep_tristate '  USB Mass Storage support (EXPERIMENTAL)' CONFIG_USB_STORAGE $CONFIG_USB $CONFIG_SCSI $CONFIG_EXPERIMENTAL
+   if [ "$CONFIG_USB_STORAGE" = "y" -o "$CONFIG_USB_STORAGE" = "m" ]; then
+      bool '    USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG
    fi
+   dep_tristate '  USB Modem (CDC ACM) support' CONFIG_USB_ACM $CONFIG_USB
+   dep_tristate '  USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
 
-comment 'USB HID'
-   dep_tristate '  USB Human Interface Device (HID) support' CONFIG_USB_HID $CONFIG_USB
+   comment 'USB Human Interface Devices (HID)'
+   dep_tristate '  USB Human Interface Device (full HID) support' CONFIG_USB_HID $CONFIG_USB
    if [ "$CONFIG_USB_HID" != "y" ]; then
-      dep_tristate '  USB HIDBP Keyboard support' CONFIG_USB_KBD $CONFIG_USB
-      dep_tristate '  USB HIDBP Mouse support' CONFIG_USB_MOUSE $CONFIG_USB
+      dep_tristate '  USB HIDBP Keyboard (basic) support' CONFIG_USB_KBD $CONFIG_USB
+      dep_tristate '  USB HIDBP Mouse (basic) support' CONFIG_USB_MOUSE $CONFIG_USB
    fi
-   dep_tristate '  Wacom Intuos/Graphire tablet support' CONFIG_USB_WACOM $CONFIG_USB
-   dep_tristate '  Logitech WingMan Force joystick support' CONFIG_USB_WMFORCE $CONFIG_USB
    if [ "$CONFIG_VT" = "y" ]; then
-      dep_tristate '  Keyboard support' CONFIG_INPUT_KEYBDEV $CONFIG_USB 
+      dep_tristate '  Keyboard support' CONFIG_INPUT_KEYBDEV $CONFIG_USB $CONFIG_USB_HID
    fi
-   dep_tristate '  Mouse support' CONFIG_INPUT_MOUSEDEV $CONFIG_USB
-   if [ "$CONFIG_INPUT_MOUSEDEV" != "n" ]; then
+   dep_tristate '  Mouse support' CONFIG_INPUT_MOUSEDEV $CONFIG_USB $CONFIG_USB_HID
+   if [ "$CONFIG_INPUT_MOUSEDEV" = "y" -o "$CONFIG_INPUT_MOUSEDEV" = "m" ]; then
       int '   Horizontal screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024
       int '   Vertical screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768
    fi
-   dep_tristate '  Joystick support' CONFIG_INPUT_JOYDEV $CONFIG_USB
-   dep_tristate '  Event interface support' CONFIG_INPUT_EVDEV $CONFIG_USB
+   dep_tristate '  Joystick support' CONFIG_INPUT_JOYDEV $CONFIG_USB $CONFIG_USB_HID
+   dep_tristate '  Logitech WingMan Force joystick support' CONFIG_USB_WMFORCE $CONFIG_USB $CONFIG_USB_HID
+   dep_tristate '  Wacom Intuos/Graphire tablet support' CONFIG_USB_WACOM $CONFIG_USB $CONFIG_USB_HID
+   dep_tristate '  Event interface support' CONFIG_INPUT_EVDEV $CONFIG_USB $CONFIG_USB_HID
+
+   comment 'USB Imaging devices'
+   dep_tristate '  USB Kodak DC-2xx Camera support' CONFIG_USB_DC2XX $CONFIG_USB
+   dep_tristate '  USB Mustek MDC800 Digital Camera support (EXPERIMENTAL)' CONFIG_USB_MDC800 $CONFIG_USB $CONFIG_EXPERIMENTAL
+   dep_tristate '  USB Scanner support' CONFIG_USB_SCANNER $CONFIG_USB
+   dep_tristate '  Microtek X6USB scanner support (EXPERIMENTAL)' CONFIG_USB_MICROTEK $CONFIG_USB $CONFIG_SCSI $CONFIG_EXPERIMENTAL
+
+   comment 'USB Multimedia devices'
+   dep_tristate '  USB IBM (Xirlink) C-it Camera support' CONFIG_USB_IBMCAM $CONFIG_USB $CONFIG_VIDEO_DEV
+   dep_tristate '  USB OV511 Camera support' CONFIG_USB_OV511 $CONFIG_USB $CONFIG_VIDEO_DEV
+   dep_tristate '  D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL
+   dep_tristate '  DABUSB driver' CONFIG_USB_DABUSB $CONFIG_USB
+
+   comment 'USB Network adaptors'
+   dep_tristate '  Kawasaki USB-ethernet controller' CONFIG_USB_KAWETH $CONFIG_USB
+   dep_tristate '  PLUSB Prolific USB-Network driver (EXPERIMENTAL)' CONFIG_USB_PLUSB $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
+   dep_tristate '  USB ADMtek Pegasus-based ethernet device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
+
+   comment 'USB port drivers'
+#   dep_tristate '  USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT
+   source drivers/usb/serial/Config.in
+
+   comment 'USB misc drivers'
+   dep_tristate '  USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB $CONFIG_EXPERIMENTAL
 fi
 
 endmenu
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/acm.c linux.19p18/drivers/usb/acm.c
--- linux.vanilla/drivers/usb/acm.c	Mon Dec 11 22:12:58 2000
+++ linux.19p18/drivers/usb/acm.c	Thu Feb  1 14:55:59 2001
@@ -503,12 +503,12 @@
 		if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints != 2) {
 			ifcom = cfacm->interface[1].altsetting + 0;
 			ifdata = cfacm->interface[0].altsetting + 0;
-			if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints != 2)
+			if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints < 2)
 				continue;
 		}
 
 		if (ifcom->bInterfaceClass != 2 || ifcom->bInterfaceSubClass != 2 ||
-		    ifcom->bInterfaceProtocol != 1 || ifcom->bNumEndpoints != 1)
+		    ifcom->bInterfaceProtocol != 1 || ifcom->bNumEndpoints < 1)
 			continue;
 
 		epctrl = ifcom->endpoint + 0;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/audio.c linux.19p18/drivers/usb/audio.c
--- linux.vanilla/drivers/usb/audio.c	Mon Dec 11 22:12:58 2000
+++ linux.19p18/drivers/usb/audio.c	Tue Jan  9 12:07:39 2001
@@ -174,6 +174,7 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/sched.h>
+#include <linux/smp_lock.h>
 #include <linux/module.h>
 #include <linux/sound.h>
 #include <linux/soundcard.h>
@@ -562,7 +563,8 @@
 		rem = db->dmasize - ptr;
 		if (pgrem > rem)
 			pgrem = rem;
-		copy_from_user_ret((db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), buffer, pgrem, -EFAULT);
+		if (copy_from_user((db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), buffer, pgrem))
+			return -EFAULT;
 		size -= pgrem;
 		(char *)buffer += pgrem;
 		ptr += pgrem;
@@ -586,7 +588,8 @@
 		rem = db->dmasize - ptr;
 		if (pgrem > rem)
 			pgrem = rem;
-		copy_to_user_ret(buffer, (db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), pgrem, -EFAULT);
+		if (copy_to_user(buffer, (db->sgbuf[ptr >> PAGE_SHIFT]) + (ptr & (PAGE_SIZE-1)), pgrem))
+			return -EFAULT;
 		size -= pgrem;
 		(char *)buffer += pgrem;
 		ptr += pgrem;
@@ -1957,10 +1960,13 @@
 static int usb_audio_release_mixdev(struct inode *inode, struct file *file)
 {
 	struct usb_mixerdev *ms = (struct usb_mixerdev *)file->private_data;
-	struct usb_audio_state *s = ms->state;
+	struct usb_audio_state *s;
 
+	lock_kernel();
+	s = ms->state;
 	down(&open_sem);
 	release(s);
+	unlock_kernel();
 	return 0;
 }
 
@@ -2038,7 +2044,8 @@
 	ms->modcnt++;
 	switch (_IOC_NR(cmd)) {
 	case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
-		get_user_ret(val, (int *)arg, -EFAULT);
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
 		return set_rec_src(ms, val);
 
 	default:
@@ -2048,7 +2055,8 @@
 		for (j = 0; j < ms->numch && ms->ch[j].osschannel != i; j++);
 		if (j >= ms->numch)
 			return -EINVAL;
-		get_user_ret(val, (int *)arg, -EFAULT);
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (wrmixer(ms, j, val))
 			return -EIO;
 		return put_user(ms->ch[j].value, (int *)arg);
@@ -2295,20 +2303,24 @@
 {
 	struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
 	struct dmabuf *db;
-	int ret;
+	int ret = -EINVAL;
 
+	lock_kernel();
 	if (vma->vm_flags & VM_WRITE) {
 		if ((ret = prog_dmabuf_out(as)) != 0)
-			return ret;
+			goto out;
 		db = &as->usbout.dma;
 	} else if (vma->vm_flags & VM_READ) {
 		if ((ret = prog_dmabuf_in(as)) != 0)
-			return ret;
+			goto out;
 		db = &as->usbin.dma;
 	} else
-		return -EINVAL;
+		goto out;
 
-	return dmabuf_mmap(db,  vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot);
+	ret = dmabuf_mmap(db,  vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot);
+out:
+	unlock_kernel();
+	return ret;
 }
 
 static int usb_audio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
@@ -2352,7 +2364,8 @@
 		return 0;
 
 	case SNDCTL_DSP_SPEED:
-		get_user_ret(val, (int *)arg, -EFAULT);
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (val >= 0) {
 			if (val < 4000)
 				val = 4000;
@@ -2370,7 +2383,8 @@
 		return 0;
 
 	case SNDCTL_DSP_CHANNELS:
-		get_user_ret(val, (int *)arg, -EFAULT);
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (val != 0) {
 			val2 = (file->f_mode & FMODE_READ) ? as->usbin.dma.format : as->usbout.dma.format;
 			if (val == 1)
@@ -2388,7 +2402,8 @@
 				AFMT_S8 | AFMT_S16_LE | AFMT_S16_BE, (int *)arg);
 
 	case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
-		get_user_ret(val, (int *)arg, -EFAULT);
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (val != AFMT_QUERY) {
 			if (hweight32(val) != 1)
 				return -EINVAL;
@@ -2415,7 +2430,8 @@
 		return put_user(val, (int *)arg);
 
 	case SNDCTL_DSP_SETTRIGGER:
-		get_user_ret(val, (int *)arg, -EFAULT);
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (file->f_mode & FMODE_READ) {
 			if (val & PCM_ENABLE_INPUT) {
 				if (!as->usbin.dma.ready && (ret = prog_dmabuf_in(as)))
@@ -2509,7 +2525,8 @@
 		return put_user(as->usbin.dma.fragsize, (int *)arg);
 
 	case SNDCTL_DSP_SETFRAGMENT:
-		get_user_ret(val, (int *)arg, -EFAULT);
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (file->f_mode & FMODE_READ) {
 			as->usbin.dma.ossfragshift = val & 0xffff;
 			as->usbin.dma.ossmaxfrags = (val >> 16) & 0xffff;
@@ -2536,7 +2553,8 @@
 		if ((file->f_mode & FMODE_READ && as->usbin.dma.subdivision) ||
 		    (file->f_mode & FMODE_WRITE && as->usbout.dma.subdivision))
 			return -EINVAL;
-		get_user_ret(val, (int *)arg, -EFAULT);
+		if (get_user(val, (int *)arg))
+			return -EFAULT;
 		if (val != 1 && val != 2 && val != 4)
 			return -EINVAL;
 		if (file->f_mode & FMODE_READ)
@@ -2624,10 +2642,13 @@
 static int usb_audio_release(struct inode *inode, struct file *file)
 {
 	struct usb_audiodev *as = (struct usb_audiodev *)file->private_data;
-	struct usb_audio_state *s = as->state;
-	struct usb_device *dev = s->usbdev;
+	struct usb_audio_state *s;
+	struct usb_device *dev;
 	struct usb_interface *iface;
 
+	lock_kernel();
+	s = as->state;
+	dev = s->usbdev;
 	if (file->f_mode & FMODE_WRITE)
 		drain_out(as, file->f_flags & O_NONBLOCK);
 	down(&open_sem);
@@ -2652,6 +2673,7 @@
 	as->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
 	release(s);
 	wake_up(&open_wait);
+	unlock_kernel();
 	return 0;
 }
 
@@ -2672,12 +2694,10 @@
 static void usb_audio_disconnect(struct usb_device *dev, void *ptr);
 
 static struct usb_driver usb_audio_driver = {
-	"audio",
-	usb_audio_probe,
-	usb_audio_disconnect,
-	LIST_HEAD_INIT(usb_audio_driver.driver_list), 
-	NULL,
-	0
+	name:		"audio",
+	probe:		usb_audio_probe,
+	disconnect:	usb_audio_disconnect,
+	driver_list:	LIST_HEAD_INIT(usb_audio_driver.driver_list), 
 };
 
 static void *find_descriptor(void *descstart, unsigned int desclen, void *after, 
@@ -3641,6 +3661,7 @@
 #endif
 		return NULL;
 	}
+
 	/*
 	 * audiocontrol interface found
 	 * find which configuration number is active
@@ -3721,21 +3742,21 @@
 	wake_up(&open_wait);
 }
 
-int usb_audio_init(void)
+static int __init usb_audio_init(void)
 {
 	usb_register(&usb_audio_driver);
 	return 0;
 }
 
-#ifdef MODULE
-int init_module(void)
-{
-	return usb_audio_init();
-}
 
-void cleanup_module(void)
+static void __exit usb_audio_cleanup(void)
 {
 	usb_deregister(&usb_audio_driver);
 }
 
-#endif
+module_init(usb_audio_init);
+module_exit(usb_audio_cleanup);
+
+MODULE_AUTHOR("Alan Cox <alan@lxorguk.ukuu.org.uk>, Thomas Sailer (sailer@ife.ee.ethz.ch)");
+MODULE_DESCRIPTION("USB Audio Class driver");
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/bluetooth.c linux.19p18/drivers/usb/bluetooth.c
--- linux.vanilla/drivers/usb/bluetooth.c	Mon Dec 11 22:12:58 2000
+++ linux.19p18/drivers/usb/bluetooth.c	Sat Mar 10 23:06:51 2001
@@ -1,11 +1,15 @@
 /*
- * bluetooth.c   Version 0.6
+ * bluetooth.c   Version 0.7
  *
  * Copyright (c) 2000 Greg Kroah-Hartman	<greg@kroah.com>
  * Copyright (c) 2000 Mark Douglas Corner	<mcorner@umich.edu>
  *
  * USB Bluetooth driver, based on the Bluetooth Spec version 1.0B
  *
+ * (11/29/2000) Version 0.7 gkh
+ *	Fixed problem with overrunning the tty flip buffer.
+ *	Removed unneeded NULL pointer initialization.
+ *
  * (10/05/2000) Version 0.6 gkh
  *	Fixed bug with urb->dev not being set properly, now that the usb
  *	core needs it.
@@ -73,9 +77,9 @@
 #include <linux/init.h>
 #include <linux/malloc.h>
 #include <linux/fcntl.h>
+#include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
-#include <linux/tty.h>
 #include <linux/module.h>
 #include <linux/devfs_fs_kernel.h>
 
@@ -199,8 +203,7 @@
 static struct tty_struct *	bluetooth_tty[BLUETOOTH_TTY_MINORS];
 static struct termios *		bluetooth_termios[BLUETOOTH_TTY_MINORS];
 static struct termios *		bluetooth_termios_locked[BLUETOOTH_TTY_MINORS];
-static struct usb_bluetooth	*bluetooth_table[BLUETOOTH_TTY_MINORS] = {NULL, };
-
+static struct usb_bluetooth	*bluetooth_table[BLUETOOTH_TTY_MINORS];
 
 
 static inline int bluetooth_paranoia_check (struct usb_bluetooth *bluetooth, const char *function)
@@ -315,6 +318,11 @@
 	tty->driver_data = bluetooth;
 	bluetooth->tty = tty;
 
+	/* force low_latency on so that our tty_push actually forces the data through, 
+	 * otherwise it is scheduled, and with high data rates (like with OHCI) data
+	 * can get lost. */
+	bluetooth->tty->low_latency = 1;
+	
 	bluetooth->active = 1;
 
 	/* Reset the packet position counters */
@@ -774,9 +782,14 @@
 		return;
 	}
 
-	if (packet_size + EVENT_HDR_SIZE == bluetooth->int_packet_pos){
-		for (i = 0; i < bluetooth->int_packet_pos; ++i)
+	if (packet_size + EVENT_HDR_SIZE == bluetooth->int_packet_pos) {
+		for (i = 0; i < bluetooth->int_packet_pos; ++i) {
+			/* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them */
+			if (bluetooth->tty->flip.count >= TTY_FLIPBUF_SIZE) {
+				tty_flip_buffer_push(bluetooth->tty);
+			}
 			tty_insert_flip_char(bluetooth->tty, bluetooth->int_buffer[i], 0);
+		}
 		tty_flip_buffer_push(bluetooth->tty);
 
 		bluetooth->int_packet_pos = 0;
@@ -888,8 +901,13 @@
 	}
 
 	if (packet_size + ACL_HDR_SIZE == bluetooth->bulk_packet_pos) {
-		for (i = 0; i < bluetooth->bulk_packet_pos; ++i)
+		for (i = 0; i < bluetooth->bulk_packet_pos; ++i) {
+			/* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */
+			if (bluetooth->tty->flip.count >= TTY_FLIPBUF_SIZE) {
+				tty_flip_buffer_push(bluetooth->tty);
+			}
 			tty_insert_flip_char(bluetooth->tty, bluetooth->bulk_buffer[i], 0);
+		}
 		tty_flip_buffer_push(bluetooth->tty);
 		bluetooth->bulk_packet_pos = 0;
 	}	
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/dabusb.c linux.19p18/drivers/usb/dabusb.c
--- linux.vanilla/drivers/usb/dabusb.c	Mon Dec 11 22:12:58 2000
+++ linux.19p18/drivers/usb/dabusb.c	Tue Dec 19 02:13:08 2000
@@ -173,8 +173,8 @@
 
 	// process if URB was not killed
 	if (purb->status != -ENOENT) {
-		unsigned int pipe = usb_rcvisocpipe (purb->dev, _DABUSB_ISOPIPE);
-		int pipesize = usb_maxpacket (purb->dev, pipe, usb_pipeout (pipe));
+		unsigned int pipe = usb_rcvisocpipe (s->usbdev, _DABUSB_ISOPIPE);
+		int pipesize = usb_maxpacket (s->usbdev, pipe, usb_pipeout (pipe));
 		for (i = 0; i < purb->number_of_packets; i++)
 			if (!purb->iso_frame_desc[i].status) {
 				len = purb->iso_frame_desc[i].actual_length;
@@ -455,6 +455,8 @@
 			dbg("submitting: end:%p s->rec_buff_list:%p", s->rec_buff_list.prev, &s->rec_buff_list);
 
 			end = list_entry (s->rec_buff_list.prev, buff_t, buff_list);
+
+			end->purb->dev=s->usbdev;
 
 			ret = usb_submit_urb (end->purb);
 			if (ret) {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/dc2xx.c linux.19p18/drivers/usb/dc2xx.c
--- linux.vanilla/drivers/usb/dc2xx.c	Mon Dec 11 22:12:58 2000
+++ linux.19p18/drivers/usb/dc2xx.c	Sat Mar 10 23:07:18 2001
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1999-2000 by David Brownell <david-b@pacbell.net>
+ * Copyright (C) 1999-2000 by David Brownell <dbrownell@users.sourceforge.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
@@ -59,13 +59,17 @@
 #include <linux/init.h>
 #include <linux/malloc.h>
 #include <linux/module.h>
-#undef DEBUG
+#ifdef CONFIG_USB_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
 #include <linux/usb.h>
 
 
 
 /* current USB framework handles max of 16 USB devices per driver */
-#define	MAX_CAMERAS		8
+#define	MAX_CAMERAS		16
 
 /* USB char devs use USB_MAJOR and from USB_CAMERA_MINOR_BASE up */
 #define	USB_CAMERA_MINOR_BASE	80
@@ -90,6 +94,8 @@
 	/* These have the same application level protocol */  
     { 0x040a, 0x0120 },		// Kodak DC-240
     { 0x040a, 0x0130 },		// Kodak DC-280
+    { 0x040a, 0x0131 },		// Kodak DC-5000
+    { 0x040a, 0x0132 },		// Kodak DC-3400
 
 	/* These have a different application level protocol which
 	 * is part of the Flashpoint "DigitaOS".  That supports some
@@ -435,7 +441,8 @@
 		goto error;
 	}
 
-	info ("USB Camera #%d connected", camera->subminor);
+	info ("USB Camera #%d connected, major/minor %d/%d", camera->subminor,
+		USB_MAJOR, USB_CAMERA_MINOR_BASE + camera->subminor);
 
 	camera->dev = dev;
 	usb_inc_dev_use (dev);
@@ -475,12 +482,13 @@
 }
 
 static /* const */ struct usb_driver camera_driver = {
-	"dc2xx",
-	camera_probe,
-	camera_disconnect,
-	{ NULL, NULL },
-	&usb_camera_fops,
-	USB_CAMERA_MINOR_BASE
+	name:		"dc2xx",
+
+	probe:		camera_probe,
+	disconnect:	camera_disconnect,
+
+	fops:		&usb_camera_fops,
+	minor:		USB_CAMERA_MINOR_BASE
 };
 
 
@@ -497,7 +505,7 @@
 }
 
 
-MODULE_AUTHOR("David Brownell, david-b@pacbell.net");
+MODULE_AUTHOR("David Brownell, dbrownell@users.sourceforge.net");
 MODULE_DESCRIPTION("USB Camera Driver for Kodak DC-2xx series cameras");
 
 module_init (usb_dc2xx_init);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/devices.c linux.19p18/drivers/usb/devices.c
--- linux.vanilla/drivers/usb/devices.c	Mon Dec 11 22:12:58 2000
+++ linux.19p18/drivers/usb/devices.c	Tue Jan  9 12:08:12 2001
@@ -496,8 +496,10 @@
 	lock_kernel();
 	if (!st) {
 		st = kmalloc(sizeof(struct usb_device_status), GFP_KERNEL);
-		if (!st)
+		if (!st) {
+			unlock_kernel();
 			return POLLIN;
+		}
 		/*
 		 * need to prevent the module from being unloaded, since
 		 * proc_unregister does not call the release method and
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/devio.c linux.19p18/drivers/usb/devio.c
--- linux.vanilla/drivers/usb/devio.c	Mon Dec 11 22:12:58 2000
+++ linux.19p18/drivers/usb/devio.c	Sat Dec 30 20:00:54 2000
@@ -55,113 +55,6 @@
         urb_t urb;
 };
 
-/*
- * my own sync control and bulk methods. Here to experiment
- * and because the kernel ones set the process to TASK_UNINTERRUPTIBLE.
- */
-
-struct sync {
-	wait_queue_head_t wait;
-};
-
-static void sync_completed(purb_t urb)
-{
-        struct sync *s = (struct sync *)urb->context;
- 
-        wake_up(&s->wait);	
-}
-
-static int do_sync(purb_t urb, int timeout)
-{
-        DECLARE_WAITQUEUE(wait, current);
-	unsigned long tm;
-	signed long tmdiff;
-	struct sync s;
-	int ret;
-
-	tm = jiffies+timeout;
-	init_waitqueue_head(&s.wait);
-	add_wait_queue(&s.wait, &wait);
-	urb->context = &s;
-	urb->complete = sync_completed;
-	set_current_state(TASK_INTERRUPTIBLE);
-	if ((ret = usb_submit_urb(urb)))
-		goto out;
-	while (urb->status == -EINPROGRESS) {
-		tmdiff = tm - jiffies;
-		if (tmdiff <= 0) {
-			ret = -ETIMEDOUT;
-			goto out;
-		}
-		if (signal_pending(current)) {
-			ret = -EINTR;
-			goto out;
-		}
-		schedule_timeout(tmdiff);
-	}
-	ret = urb->status;
- out:
-	set_current_state(TASK_RUNNING);
-	usb_unlink_urb(urb);
-	remove_wait_queue(&s.wait, &wait);
-	return ret;
-}
-
-static int my_usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype,
-			      __u16 value, __u16 index, void *data, __u16 size, int timeout)
-{
-	urb_t *urb;
-	int ret;
-
-	if (!(urb = usb_alloc_urb(0)))
-		return -ENOMEM;
-	if (!(urb->setup_packet = kmalloc(8, GFP_KERNEL))) {
-		usb_free_urb(urb);
-		return -ENOMEM;
-	}
-	urb->setup_packet[0] = requesttype;
-	urb->setup_packet[1] = request;
-	urb->setup_packet[2] = value;
-	urb->setup_packet[3] = value >> 8;
-	urb->setup_packet[4] = index;
-	urb->setup_packet[5] = index >> 8;
-	urb->setup_packet[6] = size;
-	urb->setup_packet[7] = size >> 8;
-	urb->dev = dev;
-        urb->pipe = pipe;
-        urb->transfer_buffer = data;
-        urb->transfer_buffer_length = size;
-	ret = do_sync(urb, timeout);
-	//if (ret >= 0)
-	//	ret = urb->status;
-	if (ret >= 0)
-		ret = urb->actual_length;
-	kfree(urb->setup_packet);
-	usb_free_urb(urb);
-	return ret;
-}
-
-static int my_usb_bulk_msg(struct usb_device *dev, unsigned int pipe, 
-			   void *data, int len, int *actual_length, int timeout)
-{
-	urb_t *urb;
-	int ret;
-
-	if (!(urb = usb_alloc_urb(0)))
-		return -ENOMEM;
-        urb->dev = dev;
-        urb->pipe = pipe;
-        urb->transfer_buffer = data;
-        urb->transfer_buffer_length = len;
-	ret = do_sync(urb, timeout);
-	//if (ret >= 0)
-	//	ret = urb->status;
-	if (ret >= 0 && actual_length != NULL)
-		*actual_length = urb->actual_length;
-	usb_free_urb(urb);
-	return ret;
-}
-
 static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
 {
 	switch (orig) {
@@ -289,6 +182,8 @@
 {
         if (as->urb.transfer_buffer)
                 kfree(as->urb.transfer_buffer);
+        if (as->urb.setup_packet)
+                kfree(as->urb.setup_packet);
         kfree(as);
 }
 
@@ -536,6 +431,28 @@
 }
 #endif
 
+static int check_ctrlrecip(struct dev_state *ps, unsigned int recip, unsigned int index)
+{
+	int ret;
+
+	switch (recip & USB_RECIP_MASK) {
+	case USB_RECIP_ENDPOINT:
+		if ((ret = findintfep(ps->dev, index & 0xff)) < 0)
+			return ret;
+		if ((ret = checkintf(ps, ret)))
+			return ret;
+		break;
+
+	case USB_RECIP_INTERFACE:
+		if ((ret = findintfif(ps->dev, index & 0xff)) < 0)
+			return ret;
+		if ((ret = checkintf(ps, ret)))
+			return ret;
+		break;
+	}
+	return 0;
+}
+
 /*
  * file operations
  */
@@ -609,21 +526,8 @@
 
 	if (copy_from_user(&ctrl, (void *)arg, sizeof(ctrl)))
 		return -EFAULT;
-	switch (ctrl.requesttype & 0x1f) {
-	case USB_RECIP_ENDPOINT:
-		if ((ret = findintfep(ps->dev, ctrl.index & 0xff)) < 0)
-			return ret;
-		if ((ret = checkintf(ps, ret)))
-			return ret;
-		break;
-
-	case USB_RECIP_INTERFACE:
-		if ((ret = findintfif(ps->dev, ctrl.index & 0xff)) < 0)
-			return ret;
-		if ((ret = checkintf(ps, ret)))
-			return ret;
-		break;
-	}
+	if ((ret = check_ctrlrecip(ps, ctrl.requesttype, ctrl.index)))
+		return ret;
 	if (ctrl.length > PAGE_SIZE)
 		return -EINVAL;
 	if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
@@ -634,7 +538,7 @@
 			free_page((unsigned long)tbuf);
 			return -EINVAL;
 		}
-		i = my_usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.request, ctrl.requesttype,
+		i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.request, ctrl.requesttype,
 				       ctrl.value, ctrl.index, tbuf, ctrl.length, tmo);
 		if ((i > 0) && ctrl.length) {
 			if (copy_to_user(ctrl.data, tbuf, ctrl.length)) {
@@ -649,7 +553,7 @@
 				return -EFAULT;
 			}
 		}
-		i = my_usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.request, ctrl.requesttype,
+		i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.request, ctrl.requesttype,
 				       ctrl.value, ctrl.index, tbuf, ctrl.length, tmo);
 	}
 	free_page((unsigned long)tbuf);
@@ -683,7 +587,7 @@
 		return -EINVAL;
 	len1 = bulk.len;
 	if (len1 > PAGE_SIZE)
-		len1 = PAGE_SIZE;
+		return -EINVAL;
 	if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL)))
 		return -ENOMEM;
 	tmo = (bulk.timeout * HZ + 999) / 1000;
@@ -692,7 +596,7 @@
 			free_page((unsigned long)tbuf);
 			return -EINVAL;
 		}
-		i = my_usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
+		i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
 		if (!i && len2) {
 			if (copy_to_user(bulk.data, tbuf, len2)) {
 				free_page((unsigned long)tbuf);
@@ -706,7 +610,7 @@
 				return -EFAULT;
 			}
 		}
-		i = my_usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
+		i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
 	}
 	free_page((unsigned long)tbuf);
 	if (i < 0) {
@@ -847,23 +751,61 @@
 {
 	struct usbdevfs_urb uurb;
 	struct usbdevfs_iso_packet_desc *isopkt = NULL;
+	struct usb_endpoint_descriptor *ep_desc;
 	struct async *as;
+	devrequest *dr = NULL;
 	unsigned int u, totlen, isofrmlen;
 	int ret;
 
 	if (copy_from_user(&uurb, arg, sizeof(uurb)))
 		return -EFAULT;
-	if (uurb.flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_DISABLE_SPD))
+	if (uurb.flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_DISABLE_SPD|USBDEVFS_URB_QUEUE_BULK))
 		return -EINVAL;
 	if (!uurb.buffer)
 		return -EINVAL;
 	if (uurb.signr != 0 && (uurb.signr < SIGRTMIN || uurb.signr > SIGRTMAX))
 		return -EINVAL;
-	if ((ret = findintfep(ps->dev, uurb.endpoint)) < 0)
-		return ret;
-	if ((ret = checkintf(ps, ret)))
-		return ret;
+	if (!(uurb.type == USBDEVFS_URB_TYPE_CONTROL && (uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) {
+		if ((ret = findintfep(ps->dev, uurb.endpoint)) < 0)
+			return ret;
+		if ((ret = checkintf(ps, ret)))
+			return ret;
+	}
 	switch(uurb.type) {
+	case USBDEVFS_URB_TYPE_CONTROL:
+		if ((uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) != 0) {
+			if (!(ep_desc = usb_epnum_to_ep_desc(ps->dev, uurb.endpoint)))
+				return -ENOENT;
+			if ((ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_CONTROL)
+				return -EINVAL;
+		}
+		/* min 8 byte setup packet, max arbitrary */
+		if (uurb.buffer_length < 8 || uurb.buffer_length > PAGE_SIZE)
+			return -EINVAL;
+		if (!(dr = kmalloc(sizeof(devrequest), GFP_KERNEL)))
+			return -ENOMEM;
+		if (copy_from_user(dr, (unsigned char*)uurb.buffer, 8)) {
+			kfree(dr);
+			return -EFAULT;
+		}
+		if (uurb.buffer_length < (le16_to_cpup(&dr->length) + 8)) {
+			kfree(dr);
+			return -EINVAL;
+		}
+		if ((ret = check_ctrlrecip(ps, dr->requesttype, le16_to_cpup(&dr->index)))) {
+			kfree(dr);
+			return ret;
+		}
+		uurb.endpoint = (uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->requesttype & USB_ENDPOINT_DIR_MASK);
+		uurb.number_of_packets = 0;
+		uurb.buffer_length = le16_to_cpup(&dr->length);
+		uurb.buffer += 8;
+		if (!access_ok((uurb.endpoint & USB_DIR_IN) ?  VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length)) {
+			kfree(dr);
+			return -EFAULT;
+		}
+		break;
+
 	case USBDEVFS_URB_TYPE_BULK:
 		uurb.number_of_packets = 0;
 		if (uurb.buffer_length > 16384)
@@ -903,11 +845,15 @@
 	if (!(as = alloc_async(uurb.number_of_packets))) {
 		if (isopkt)
 			kfree(isopkt);
+		if (dr)
+			kfree(dr);
 		return -ENOMEM;
 	}
 	if (!(as->urb.transfer_buffer = kmalloc(uurb.buffer_length, GFP_KERNEL))) {
 		if (isopkt)
 			kfree(isopkt);
+		if (dr)
+			kfree(dr);
 		free_async(as);
 		return -ENOMEM;
 	}
@@ -916,6 +862,7 @@
         as->urb.pipe = (uurb.type << 30) | __create_pipe(ps->dev, uurb.endpoint & 0xf) | (uurb.endpoint & USB_DIR_IN);
         as->urb.transfer_flags = uurb.flags;
 	as->urb.transfer_buffer_length = uurb.buffer_length;
+	as->urb.setup_packet = (unsigned char*)dr;
 	as->urb.start_frame = uurb.start_frame;
 	as->urb.number_of_packets = uurb.number_of_packets;
         as->urb.context = as;
@@ -1089,17 +1036,19 @@
 	int			retval = 0;
 
 	/* get input parameters and alloc buffer */
-	if (copy_from_user (&ctrl, (void *) arg, sizeof (ctrl)))
+	if (copy_from_user(&ctrl, (void *) arg, sizeof (ctrl)))
 		return -EFAULT;
 	if ((size = _IOC_SIZE (ctrl.ioctl_code)) > 0) {
 		if ((buf = kmalloc (size, GFP_KERNEL)) == 0)
 			return -ENOMEM;
-		if ((_IOC_DIR (ctrl.ioctl_code) & _IOC_WRITE) != 0
-				&& copy_from_user (buf, ctrl.data, size) != 0) {
-			kfree (buf);
-			return -EFAULT;
-		} else
-			memset (arg, 0, size);
+		if ((_IOC_DIR(ctrl.ioctl_code) & _IOC_WRITE)) {
+			if (copy_from_user (buf, ctrl.data, size)) {
+				kfree (buf);
+				return -EFAULT;
+			}
+		} else {
+			memset (buf, 0, size);
+		}
 	}
 
 	/* ioctl to device */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/hid.c linux.19p18/drivers/usb/hid.c
--- linux.vanilla/drivers/usb/hid.c	Mon Dec 11 22:12:58 2000
+++ linux.19p18/drivers/usb/hid.c	Mon Feb 19 18:20:23 2001
@@ -698,7 +698,7 @@
 static __inline__ __u32 s32ton(__s32 value, unsigned n)
 {
 	__s32 a = value >> (n - 1);
-	if (a && a != -1) return value > 0 ? 1 << (n - 1) : (1 << n) - 1;
+	if (a && a != -1) return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1;
 	return value & ((1 << n) - 1);
 }
 
@@ -856,7 +856,7 @@
 		case HID_UP_CONSUMER:	/* USB HUT v1.1, pages 56-62 */
 			
 			switch (usage->hid & HID_USAGE) {
-
+				case 0x000: usage->code = 0; break; 
 				case 0x034: usage->code = KEY_SLEEP;		break;
 				case 0x036: usage->code = BTN_MISC;		break;
 				case 0x08a: usage->code = KEY_WWW;		break;
@@ -981,6 +981,9 @@
 		input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a) >> 3));
 	}
 
+	if((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UKNOWN */
+		return;
+
 	input_event(input, usage->type, usage->code, value);
 
 	if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY))
@@ -1013,9 +1016,15 @@
 	__s32 max = field->logical_maximum;
 	__s32 value[count]; /* WARNING: gcc specific */
    
-	for (n = 0; n < count; n++)
+	for (n = 0; n < count; n++) {
 			value[n] = min < 0 ? snto32(extract(data, offset + n * size, size), size) : 
 						    extract(data, offset + n * size, size);
+			/* Handle the ErrorRollOver code (1) by simply ignoring this report */
+			if (!(field->flags & HID_MAIN_ITEM_VARIABLE)
+			    && value[n] >= min && value[n] <= max
+			    && field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1)
+				return;
+	}
 
 	for (n = 0; n < count; n++) {
 
@@ -1228,9 +1237,10 @@
 
 static int hid_submit_out(struct hid_device *hid)
 {
-	hid->urbout.transfer_buffer_length = hid->out[hid->outtail].dr.length;
+	hid->urbout.transfer_buffer_length = le16_to_cpup(&hid->out[hid->outtail].dr.length);
 	hid->urbout.transfer_buffer = hid->out[hid->outtail].buffer;
 	hid->urbout.setup_packet = (void *) &(hid->out[hid->outtail].dr);
+	hid->urbout.dev = hid->dev;
 
 	if (usb_submit_urb(&hid->urbout)) {
 		err("usb_submit_urb(out) failed");
@@ -1267,8 +1277,8 @@
 	hid_set_field(field, offset, value);
 	hid_output_report(field->report, hid->out[hid->outhead].buffer);
 
-	hid->out[hid->outhead].dr.value = 0x200 | field->report->id;
-	hid->out[hid->outhead].dr.length = ((field->report->size - 1) >> 3) + 1;
+	hid->out[hid->outhead].dr.value = cpu_to_le16(0x200 | field->report->id);
+	hid->out[hid->outhead].dr.length = cpu_to_le16((field->report->size + 7) >> 3);
 
 	hid->outhead = (hid->outhead + 1) & (HID_CONTROL_FIFO_SIZE - 1);
 
@@ -1288,7 +1298,9 @@
 	if (hid->open++)
 		return 0;
 
-	 if (usb_submit_urb(&hid->urb))
+	hid->urb.dev = hid->dev;
+
+	if (usb_submit_urb(&hid->urb))
 		return -EIO;
 
 	return 0;
@@ -1442,7 +1454,7 @@
 	for (n = 0; n < HID_CONTROL_FIFO_SIZE; n++) {
 		hid->out[n].dr.requesttype = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
 		hid->out[n].dr.request = USB_REQ_SET_REPORT;
-		hid->out[n].dr.index = hid->ifnum;
+		hid->out[n].dr.index = cpu_to_le16(hid->ifnum);
 	}
 
 	hid->input.name = hid->name;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/hub.h linux.19p18/drivers/usb/hub.h
--- linux.vanilla/drivers/usb/hub.h	Mon Dec 11 22:12:58 2000
+++ linux.19p18/drivers/usb/hub.h	Sun Feb 25 23:04:57 2001
@@ -111,7 +111,8 @@
 	/* Interrupt polling pipe */
 	struct urb *urb;
 
-	char buffer[USB_MAXCHILDREN / 8];
+	char buffer[(USB_MAXCHILDREN + 1 + 7) / 8]; /* add 1 bit for hub status change */
+					/* and add 7 bits to round up to byte boundary */
 
 	/* List of hubs */
 	struct list_head hub_list;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/keybdev.c linux.19p18/drivers/usb/keybdev.c
--- linux.vanilla/drivers/usb/keybdev.c	Mon Dec 11 22:12:58 2000
+++ linux.19p18/drivers/usb/keybdev.c	Thu Feb  1 15:33:01 2001
@@ -60,6 +60,7 @@
 };
 
 #ifdef CONFIG_INPUT_ADBHID
+#ifdef CONFIG_MAC_ADBKEYCODES
 extern int mac_hid_keyboard_sends_linux_keycodes(void);
 
 static unsigned char mac_keycodes[256] = {
@@ -76,19 +77,20 @@
 	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 	  0,  0,  0,  0,  0, 94,  0, 93,  0,  0,  0,  0,  0,  0,104,102
 };
-
-#ifdef CONFIG_INPUT_MOUSEDEV
+#endif /* CONFIG_MAC_ADBKEYCODES */
+#ifdef CONFIG_MAC_EMUMOUSEBTN
 extern int mac_hid_mouse_emulate_buttons(int, unsigned int, int);
-#endif /* CONFIG_INPUT_MOUSEDEV */
+#endif /* CONFIG_MAC_EMUMOUSEBTN */
 #endif /* CONFIG_INPUT_ADBHID */
 
 static int emulate_raw(unsigned int keycode, int down)
 {
 #ifdef CONFIG_INPUT_ADBHID
-#ifdef CONFIG_INPUT_MOUSEDEV
+#ifdef CONFIG_MAC_EMUMOUSEBTN
 	if (mac_hid_mouse_emulate_buttons(1, keycode, down))
 		return 0;
-#endif /* CONFIG_INPUT_MOUSEDEV */
+#endif /* CONFIG_MAC_EMUMOUSEBTN */
+#ifdef CONFIG_MAC_ADBKEYCODES
 	if (!mac_hid_keyboard_sends_linux_keycodes()) {
 		if (keycode > 255 || !mac_keycodes[keycode])
 			return -1;
@@ -97,6 +99,7 @@
 
 		return 0;
 	}
+#endif /* CONFIG_MAC_ADBKEYCODES */
 #endif /* CONFIG_INPUT_ADBHID */
 	if (keycode > 255 || !x86_keycodes[keycode])
 		return -1; 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/printer.c linux.19p18/drivers/usb/printer.c
--- linux.vanilla/drivers/usb/printer.c	Mon Dec 11 22:12:59 2000
+++ linux.19p18/drivers/usb/printer.c	Thu Feb 15 16:21:23 2001
@@ -17,6 +17,7 @@
  *	v0.4 - fixes in unidirectional mode
  *	v0.5 - add DEVICE_ID string support
  *	v0.6 - never time out
+ *	v0.? - fixed bulk-IN read and poll (David Paschal, paschal@rcsis.com)
  */
 
 /*
@@ -52,6 +53,7 @@
 
 #define IOCNR_GET_DEVICE_ID	1
 #define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len)	/* get device_id string */
+#define LPGETSTATUS		0x060b		/* same as in drivers/char/lp.c */
 
 /*
  * A DEVICE_ID string may include the printer's serial number.
@@ -81,6 +83,7 @@
 	int			readcount;		/* Counter for reads */
 	int			ifnum;			/* Interface number */
 	int			minor;			/* minor number of device */
+	unsigned int		quirks;			/* quirks flags */
 	unsigned char		used;			/* True if open */
 	unsigned char		bidir;			/* interface is bidirectional */
 	unsigned char		*device_id_string;	/* IEEE 1284 DEVICE ID string (ptr) */
@@ -89,6 +92,26 @@
 
 static struct usblp *usblp_table[USBLP_MINORS];
 
+/* Quirks: various printer quirks are handled by this table & its flags. */
+
+struct quirk_printer_struct {
+	__u16 vendorId;
+	__u16 productId;
+	unsigned int quirks;
+};
+
+#define USBLP_QUIRK_BIDIR	0x1	/* reports bidir but requires unidirectional mode (no INs/reads) */
+#define USBLP_QUIRK_USB_INIT	0x2	/* needs vendor USB init string */
+
+static struct quirk_printer_struct quirk_printers[] = {
+	{ 0x03f0, 0x0004, USBLP_QUIRK_BIDIR }, /* HP DeskJet 895C */
+	{ 0x03f0, 0x0104, USBLP_QUIRK_BIDIR }, /* HP DeskJet 880C */
+	{ 0x03f0, 0x0204, USBLP_QUIRK_BIDIR }, /* HP DeskJet 815C */
+	{ 0x03f0, 0x0304, USBLP_QUIRK_BIDIR }, /* HP DeskJet 810C/812C */
+	{ 0x03f0, 0x0404, USBLP_QUIRK_BIDIR }, /* HP DeskJet 830C */
+	{ 0, 0 }
+};
+
 /*
  * Functions for usblp control messages.
  */
@@ -179,10 +202,19 @@
 	if (usblp->used)
 		goto out;
 
+	/*
+	 * TODO: need to implement LP_ABORTOPEN + O_NONBLOCK as in drivers/char/lp.c ???
+	 * This is #if 0-ed because we *don't* want to fail an open
+	 * just because the printer is off-line.
+	 */
+#if 0
 	if ((retval = usblp_check_status(usblp, 0))) {
 		retval = retval > 1 ? -EIO : -ENOSPC;
 		goto out;
 	}
+#else
+	retval = 0;	
+#endif
 
 	usblp->used = 1;
 	file->private_data = usblp;
@@ -192,6 +224,7 @@
 
 	if (usblp->bidir) {
 		usblp->readcount = 0;
+		usblp->readurb.dev = usblp->dev;
 		usb_submit_urb(&usblp->readurb);
 	}
 out:
@@ -224,37 +257,66 @@
 {
 	struct usblp *usblp = file->private_data;
 	poll_wait(file, &usblp->wait, wait);
-	return ((usblp->bidir || usblp->readurb.status  == -EINPROGRESS) ? 0 : POLLIN  | POLLRDNORM)
-	     		      | (usblp->writeurb.status == -EINPROGRESS  ? 0 : POLLOUT | POLLWRNORM);
+ 	return ((!usblp->bidir || usblp->readurb.status  == -EINPROGRESS) ? 0 : POLLIN  | POLLRDNORM)
+ 			       | (usblp->writeurb.status == -EINPROGRESS  ? 0 : POLLOUT | POLLWRNORM);
 }
 
 static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	struct usblp *usblp = file->private_data;
-	int length;
-
-	if ((_IOC_TYPE(cmd) != 'P') || (_IOC_DIR(cmd) != _IOC_READ))
-		return -EINVAL;
-
-	switch (_IOC_NR(cmd)) {
+	int length, err;
+	unsigned char status;
 
-		case IOCNR_GET_DEVICE_ID: /* get the DEVICE_ID string */
+	if (_IOC_TYPE(cmd) == 'P')	/* new-style ioctl number */
+	
+		switch (_IOC_NR(cmd)) {
+
+			case IOCNR_GET_DEVICE_ID: /* get the DEVICE_ID string */
+				if (_IOC_DIR(cmd) != _IOC_READ)
+					return -EINVAL;
+
+				err = usblp_get_id(usblp, 0, usblp->device_id_string, DEVICE_ID_SIZE - 1);
+				if (err < 0) {
+					dbg ("usblp%d: error = %d reading IEEE-1284 Device ID string",
+						usblp->minor, err);
+					usblp->device_id_string[0] = usblp->device_id_string[1] = '\0';
+					return -EIO;
+				}
+
+				length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; /* big-endian */
+				if (length < DEVICE_ID_SIZE)
+					usblp->device_id_string[length] = '\0';
+				else
+					usblp->device_id_string[DEVICE_ID_SIZE - 1] = '\0';
+
+				dbg ("usblp%d Device ID string [%d/max %d]='%s'",
+					usblp->minor, length, _IOC_SIZE(cmd), &usblp->device_id_string[2]);
+
+				if (length > _IOC_SIZE(cmd)) length = _IOC_SIZE(cmd); /* truncate */
 
-			length = (usblp->device_id_string[0] << 8) + usblp->device_id_string[1]; /* big-endian */
+				if (copy_to_user((unsigned char *) arg, usblp->device_id_string, (unsigned long) length))
+					return -EFAULT;
 
-			dbg ("usblp_ioctl GET_DEVICE_ID actlen: %d, size: %d, string: '%s'",
-				length, _IOC_SIZE(cmd), &usblp->device_id_string[2]);
+				break;
 
-			if (length > _IOC_SIZE(cmd)) length = _IOC_SIZE(cmd); /* truncate */
+			default:
+				return -EINVAL;
+		}
+	else	/* old-style ioctl value */
+		switch (cmd) {
 
-			if (copy_to_user((unsigned char *) arg, usblp->device_id_string, (unsigned long) length))
-				return -EFAULT;
+			case LPGETSTATUS:
+				if (usblp_read_status(usblp, &status)) {
+					err("usblp%d: failed reading printer status", usblp->minor);
+					return -EIO;
+				}
+				if (copy_to_user ((unsigned char *)arg, &status, 1))
+					return -EFAULT;
+				break;
 
-			break;
-
-		default:
-			return -EINVAL;
-	}
+			default:
+				return -EINVAL;
+		}
 
 	return 0;
 }
@@ -285,8 +347,17 @@
 			return -ENODEV;
 
 		if (usblp->writeurb.status) {
-			err = usblp_check_status(usblp, err);
-			continue;
+			if (usblp->quirks & USBLP_QUIRK_BIDIR) {
+				if (usblp->writeurb.status != -EINPROGRESS)
+					err("usblp%d: error %d writing to printer",
+						usblp->minor, usblp->writeurb.status);
+				err = usblp->writeurb.status;
+				continue;
+			}
+			else {
+				err = usblp_check_status(usblp, err);
+				continue;
+			}
 		}
 
 		writecount += usblp->writeurb.transfer_buffer_length;
@@ -301,6 +372,7 @@
 		if (copy_from_user(usblp->writeurb.transfer_buffer, buffer + writecount,
 				usblp->writeurb.transfer_buffer_length)) return -EFAULT;
 
+		usblp->writeurb.dev = usblp->dev;
 		usb_submit_urb(&usblp->writeurb);
 	}
 
@@ -332,6 +404,8 @@
 	if (usblp->readurb.status) {
 		err("usblp%d: error %d reading from printer",
 			usblp->minor, usblp->readurb.status);
+		usblp->readurb.dev = usblp->dev;
+ 		usblp->readcount = 0;
 		usb_submit_urb(&usblp->readurb);
 		return -EIO;
 	}
@@ -342,21 +416,55 @@
 	if (copy_to_user(buffer, usblp->readurb.transfer_buffer + usblp->readcount, count))
 		return -EFAULT;
 
-	if ((usblp->readcount += count) == usblp->readurb.actual_length)
+	if ((usblp->readcount += count) == usblp->readurb.actual_length) {
+		usblp->readcount = 0;
+		usblp->readurb.dev = usblp->dev;
 		usb_submit_urb(&usblp->readurb);
+	}
 
 	return count;
 }
 
+/*
+ * Checks for printers that have quirks, such as requiring unidirectional
+ * communication but reporting bidirectional; currently some HP printers
+ * have this flaw (HP 810, 880, 895, etc.), or needing an init string
+ * sent at each open (like some Epsons).
+ * Returns 1 if found, 0 if not found.
+ *
+ * HP recommended that we use the bidirectional interface but
+ * don't attempt any bulk IN transfers from the IN endpoint.
+ * Here's some more detail on the problem:
+ * The problem is not that it isn't bidirectional though. The problem
+ * is that if you request a device ID, or status information, while
+ * the buffers are full, the return data will end up in the print data
+ * buffer. For example if you make sure you never request the device ID
+ * while you are sending print data, and you don't try to query the
+ * printer status every couple of milliseconds, you will probably be OK.
+ */
+static unsigned int usblp_quirks (__u16 vendor, __u16 product)
+{
+	int i;
+
+	for (i = 0; quirk_printers[i].vendorId; i++) {
+		if (vendor == quirk_printers[i].vendorId &&
+		    product == quirk_printers[i].productId)
+			return quirk_printers[i].quirks;
+ 	}
+	return 0;
+}
+
 static void *usblp_probe(struct usb_device *dev, unsigned int ifnum)
 {
 	struct usb_interface_descriptor *interface;
 	struct usb_endpoint_descriptor *epread, *epwrite;
 	struct usblp *usblp;
-	int minor, i, alts = -1, bidir = 0;
+	int minor, i, bidir = 0, quirks;
+	int alts = dev->actconfig->interface[ifnum].act_altsetting;
 	int length, err;
 	char *buf;
 
+	/* If a bidirectional interface exists, use it. */
 	for (i = 0; i < dev->actconfig->interface[ifnum].num_altsetting; i++) {
 
 		interface = &dev->actconfig->interface[ifnum].altsetting[i];
@@ -366,18 +474,13 @@
 		   (interface->bInterfaceProtocol > 1 && interface->bNumEndpoints < 2))
 			continue;
 
-		if (alts == -1)
-			alts = i;
-
-		if (!bidir && interface->bInterfaceProtocol > 1) {
+		if (interface->bInterfaceProtocol > 1) {
 			bidir = 1;
 			alts = i;
+			break;
 		}
 	}
 
-	if (alts == -1)
-		return NULL;
-
 	interface = &dev->actconfig->interface[ifnum].altsetting[alts];
 	if (usb_set_interface(dev, ifnum, alts))
 		err("can't set desired altsetting %d on interface %d", alts, ifnum);
@@ -410,10 +513,21 @@
 	}
 	memset(usblp, 0, sizeof(struct usblp));
 
+	/* lookup quirks for this printer */
+	quirks = usblp_quirks(dev->descriptor.idVendor, dev->descriptor.idProduct);
+
+	if (bidir && (quirks & USBLP_QUIRK_BIDIR)) {
+		bidir = 0;
+		epread = NULL;
+		info ("Disabling reads from problem bidirectional printer on usblp%d",
+			minor);
+	}
+
 	usblp->dev = dev;
 	usblp->ifnum = ifnum;
 	usblp->minor = minor;
 	usblp->bidir = bidir;
+	usblp->quirks = quirks;
 
 	init_waitqueue_head(&usblp->wait);
 
@@ -455,7 +569,7 @@
 	}
 
 #ifdef DEBUG
-	usblp_check_status(usblp);
+	usblp_check_status(usblp, 0);
 #endif
 
 	info("usblp%d: USB %sdirectional printer dev %d if %d alt %d",
@@ -503,7 +617,7 @@
 	probe:		usblp_probe,
 	disconnect:	usblp_disconnect,
 	fops:		&usblp_fops,
-	minor:		USBLP_MINOR_BASE
+	minor:		USBLP_MINOR_BASE,
 };
 
 static int __init usblp_init(void)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/rio500.c linux.19p18/drivers/usb/rio500.c
--- linux.vanilla/drivers/usb/rio500.c	Mon Dec 11 22:12:59 2000
+++ linux.19p18/drivers/usb/rio500.c	Tue Jan  9 12:09:16 2001
@@ -36,6 +36,7 @@
 #include <linux/malloc.h>
 #include <linux/spinlock.h>
 #include <linux/usb.h>
+#include <linux/smp_lock.h>
 
 #include "rio500_usb.h"
 
@@ -57,6 +58,7 @@
         char *obuf, *ibuf;              /* transfer buffers */
         char bulk_in_ep, bulk_out_ep;   /* Endpoint assignments */
         wait_queue_head_t wait_q;       /* for timeouts */
+	struct semaphore lock;          /* general race avoidance */
 };
 
 static struct rio_usb_data rio_instance;
@@ -65,7 +67,10 @@
 {
 	struct rio_usb_data *rio = &rio_instance;
 
+	lock_kernel();
+
 	if (rio->isopen || !rio->present) {
+		unlock_kernel();
 		return -EBUSY;
 	}
 	rio->isopen = 1;
@@ -74,6 +79,8 @@
 
 	MOD_INC_USE_COUNT;
 
+	unlock_kernel();
+
 	info("Rio opened.");
 
 	return 0;
@@ -101,6 +108,7 @@
 	unsigned char *buffer;
 	int result, requesttype;
 	int retries;
+	int retval;
 
         /* Sanity check to make sure rio is connected, powered, etc */
         if ( rio == NULL ||
@@ -120,8 +128,10 @@
 		buffer = (unsigned char *) __get_free_page(GFP_KERNEL);
 		if (buffer == NULL)
 			return -ENOMEM;
-		if (copy_from_user(buffer, rio_cmd.buffer, rio_cmd.length))
+		if (copy_from_user(buffer, rio_cmd.buffer, rio_cmd.length)) {
+			free_page((unsigned long) buffer);
 			return -EFAULT;
+		}
 
 		requesttype = rio_cmd.requesttype | USB_DIR_IN |
 		    USB_TYPE_VENDOR | USB_RECIP_DEVICE;
@@ -131,6 +141,7 @@
 		     rio_cmd.index, rio_cmd.length);
 		/* Send rio control message */
 		retries = 3;
+		down(&(rio->lock));
 		while (retries) {
 			result = usb_control_msg(rio->rio_dev,
 						 usb_rcvctrlpipe(rio-> rio_dev, 0),
@@ -151,8 +162,12 @@
 				     le32_to_cpu(result),
 				     le32_to_cpu(*((long *) buffer)));
 				if (copy_to_user(rio_cmd.buffer, buffer,
-						 rio_cmd.length))
-					return -EFAULT;
+						 rio_cmd.length)) {
+					up(&(rio->lock));
+					free_page((unsigned long) buffer);
+					retval = -EFAULT;
+					goto err_out;
+				}
 				retries = 0;
 			}
 
@@ -164,6 +179,7 @@
 			   be swapped at the app level */
 
 		}
+		up(&(rio->lock));
 		free_page((unsigned long) buffer);
 		break;
 
@@ -178,8 +194,10 @@
 		buffer = (unsigned char *) __get_free_page(GFP_KERNEL);
 		if (buffer == NULL)
 			return -ENOMEM;
-		if (copy_from_user(buffer, rio_cmd.buffer, rio_cmd.length))
+		if (copy_from_user(buffer, rio_cmd.buffer, rio_cmd.length)) {
+			free_page((unsigned long)buffer);
 			return -EFAULT;
+		}
 
 		requesttype = rio_cmd.requesttype | USB_DIR_OUT |
 		    USB_TYPE_VENDOR | USB_RECIP_DEVICE;
@@ -188,6 +206,7 @@
 		     rio_cmd.index, rio_cmd.length);
 		/* Send rio control message */
 		retries = 3;
+		down(&(rio->lock));
 		while (retries) {
 			result = usb_control_msg(rio->rio_dev,
 						 usb_sndctrlpipe(rio-> rio_dev, 0),
@@ -211,6 +230,7 @@
 			}
 
 		}
+		up(&(rio->lock));
 		free_page((unsigned long) buffer);
 		break;
 
@@ -220,6 +240,10 @@
 	}
 
 	return 0;
+
+err_out:
+	up(&(rio->lock));
+	return retval;
 }
 
 static ssize_t
@@ -234,6 +258,7 @@
 
 	int result = 0;
 	int maxretry;
+	int errn = 0;
 
         /* Sanity check to make sure rio is connected, powered, etc */
         if ( rio == NULL ||
@@ -241,19 +266,26 @@
              rio->rio_dev == NULL )
           return -1;
 
+	down(&(rio->lock));
+
 	do {
 		unsigned long thistime;
 		char *obuf = rio->obuf;
 
 		thistime = copy_size =
 		    (count >= OBUF_SIZE) ? OBUF_SIZE : count;
-		if (copy_from_user(rio->obuf, buffer, copy_size))
-			return -EFAULT;
+		if (copy_from_user(rio->obuf, buffer, copy_size)) {
+			errn = -EFAULT;
+			goto error;
+		}
 		maxretry = 5;
 		while (thistime) {
-			if (!rio->rio_dev)
-				return -ENODEV;
+			if (!rio->rio_dev) {
+				errn = -ENODEV;
+				goto error;
+			}
 			if (signal_pending(current)) {
+				up(&(rio->lock));
 				return bytes_written ? bytes_written : -EINTR;
 			}
 
@@ -266,7 +298,8 @@
 
 			if (result == USB_ST_TIMEOUT) {	/* NAK - so hold for a while */
 				if (!maxretry--) {
-					return -ETIME;
+					errn = -ETIME;
+					goto error;
 				}
 				interruptible_sleep_on_timeout(&rio-> wait_q, NAK_TIMEOUT);
 				continue;
@@ -278,14 +311,21 @@
 		};
 		if (result) {
 			err("Write Whoops - %x", result);
-			return -EIO;
+			errn = -EIO;
+			goto error;
 		}
 		bytes_written += copy_size;
 		count -= copy_size;
 		buffer += copy_size;
 	} while (count > 0);
 
+	up(&(rio->lock));
+
 	return bytes_written ? bytes_written : -EIO;
+
+error:
+	up(&(rio->lock));
+	return errn;
 }
 
 static ssize_t
@@ -307,12 +347,17 @@
 
 	read_count = 0;
 
+	down(&(rio->lock));
+
 	while (count > 0) {
 		if (signal_pending(current)) {
+			up(&(rio->lock));
 			return read_count ? read_count : -EINTR;
 		}
-		if (!rio->rio_dev)
+		if (!rio->rio_dev) {
+			up(&(rio->lock));
 			return -ENODEV;
+		}
 		this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count;
 
 		result = usb_bulk_msg(rio->rio_dev,
@@ -327,6 +372,7 @@
 			count = this_read = partial;
 		} else if (result == USB_ST_TIMEOUT || result == 15) {	/* FIXME: 15 ??? */
 			if (!maxretry--) {
+				up(&(rio->lock));
 				err("read_rio: maxretry timeout");
 				return -ETIME;
 			}
@@ -334,21 +380,26 @@
 						       NAK_TIMEOUT);
 			continue;
 		} else if (result != USB_ST_DATAUNDERRUN) {
+			up(&(rio->lock));
 			err("Read Whoops - result:%u partial:%u this_read:%u",
 			     result, partial, this_read);
 			return -EIO;
 		} else {
+			up(&(rio->lock));
 			return (0);
 		}
 
 		if (this_read) {
-			if (copy_to_user(buffer, ibuf, this_read))
+			if (copy_to_user(buffer, ibuf, this_read)) {
+				up(&(rio->lock));
 				return -EFAULT;
+			}
 			count -= this_read;
 			read_count += this_read;
 			buffer += this_read;
 		}
 	}
+	up(&(rio->lock));
 	return read_count;
 }
 
@@ -383,6 +434,8 @@
 	}
 	dbg("probe_rio: ibuf address:%p", rio->ibuf);
 
+	init_MUTEX(&(rio->lock));
+
 	return rio;
 }
 
@@ -415,12 +468,11 @@
 
 static struct
 usb_driver rio_driver = {
-	"rio500",
-	probe_rio,
-	disconnect_rio,
-	{NULL, NULL},
-	&usb_rio_fops,
-	RIO_MINOR
+	name:		"rio500",
+	probe:		probe_rio,
+	disconnect:	disconnect_rio,
+	fops:		&usb_rio_fops,
+	minor:		RIO_MINOR,
 };
 
 int usb_rio_init(void)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/scanner.h linux.19p18/drivers/usb/scanner.h
--- linux.vanilla/drivers/usb/scanner.h	Mon Dec 11 22:12:59 2000
+++ linux.19p18/drivers/usb/scanner.h	Sat Mar 10 23:29:15 2001
@@ -151,6 +151,7 @@
 		{ 0x04b8, 0x0101 },	/* Perfection 636U and 636Photo */
 		{ 0x04b8, 0x0103 },	/* Perfection 610 */
 		{ 0x04b8, 0x0104 },	/* Perfection 1200U and 1200Photo */
+		{ 0x04b8, 0x010b },	/* Perfection 1240U and 1240Photo */
 	/* Umax */
 		{ 0x1606, 0x0010 },	/* Astra 1220U */
 		{ 0x1606, 0x0002 },	/* Astra 1236U */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/Config.in linux.19p18/drivers/usb/serial/Config.in
--- linux.vanilla/drivers/usb/serial/Config.in	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/usb/serial/Config.in	Mon Feb 19 18:30:46 2001
@@ -0,0 +1,30 @@
+#
+# USB Serial device configuration
+#
+mainmenu_option next_comment
+comment 'USB Serial Converter support'
+
+tristate 'USB Serial Converter support' CONFIG_USB_SERIAL $CONFIG_USB
+if [ "$CONFIG_USB_SERIAL" != "n" ]; then
+  bool '  USB Serial Converter verbose debug' CONFIG_USB_SERIAL_DEBUG
+  bool '  USB Generic Serial Driver' CONFIG_USB_SERIAL_GENERIC
+  dep_tristate '  USB Belkin and Peracom Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_BELKIN $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+  dep_tristate '  USB ConnectTech WhiteHEAT Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_WHITEHEAT $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+  dep_tristate '  USB Digi International AccelePort USB Serial Driver' CONFIG_USB_SERIAL_DIGI_ACCELEPORT $CONFIG_USB_SERIAL
+  dep_tristate '  USB Empeg empeg-car Mark I/II Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EMPEG $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+  dep_tristate '  USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+  dep_tristate '  USB Handspring Visor Driver' CONFIG_USB_SERIAL_VISOR $CONFIG_USB_SERIAL
+  dep_tristate '  USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+  dep_tristate '  USB Keyspan USA-xxx Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+  if [ "$CONFIG_USB_SERIAL_KEYSPAN" = "y" -o "$CONFIG_USB_SERIAL_KEYSPAN" = "m" ]; then
+     bool '    USB Keyspan USA-28 Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28
+     bool '    USB Keyspan USA-28X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA28X
+     bool '    USB Keyspan USA-19 Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19
+     bool '    USB Keyspan USA-18X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA18X
+     bool '    USB Keyspan USA-19W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19W
+     bool '    USB Keyspan USA-49W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA49W
+  fi
+  dep_tristate '  USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_OMNINET $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
+fi
+
+endmenu
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/Makefile linux.19p18/drivers/usb/serial/Makefile
--- linux.vanilla/drivers/usb/serial/Makefile	Mon Dec 11 22:13:00 2000
+++ linux.19p18/drivers/usb/serial/Makefile	Tue Dec 19 02:30:27 2000
@@ -23,6 +23,7 @@
 obj-$(CONFIG_USB_SERIAL_OMNINET)		+= omninet.o
 obj-$(CONFIG_USB_SERIAL_DIGI_ACCELEPORT)	+= digi_acceleport.o
 obj-$(CONFIG_USB_SERIAL_BELKIN)			+= belkin_sa.o
+obj-$(CONFIG_USB_SERIAL_EMPEG)			+= empeg.o
  
 # Objects that export symbols.
 export-objs	:= usbserial.o
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/empeg.c linux.19p18/drivers/usb/serial/empeg.c
--- linux.vanilla/drivers/usb/serial/empeg.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/usb/serial/empeg.c	Sat Mar 10 23:07:43 2001
@@ -0,0 +1,703 @@
+/*
+ * USB Empeg empeg-car player driver
+ *
+ *	Copyright (C) 2000
+ *	    Gary Brubaker (xavyer@ix.netcom.com)
+ *
+ *	Copyright (C) 1999, 2000
+ *	    Greg Kroah-Hartman (greg@kroah.com)
+ *
+ *	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, version 2.
+ *
+ * See Documentation/usb/usb-serial.txt for more information on using this driver
+ * 
+ * (01/22/2001) gb
+ *	Added write_room() and chars_in_buffer() support. 
+ * 
+ * (12/21/2000) gb
+ *	Moved termio stuff inside the port->active check.
+ *	Moved MOD_DEC_USE_COUNT to end of empeg_close().
+ * 
+ * (12/03/2000) gb
+ *	Added port->tty->ldisc.set_termios(port->tty, NULL) to empeg_open()
+ *	This notifies the tty driver that the termios have changed.
+ * 
+ * (11/13/2000) gb
+ *	Moved tty->low_latency = 1 from empeg_read_bulk_callback() to empeg_open()
+ *	(It only needs to be set once - Doh!)
+ * 
+ * (11/11/2000) gb
+ *	Updated to work with id_table structure.
+ * 
+ * (11/04/2000) gb
+ *	Forked this from visor.c, and hacked it up to work with an
+ *	Empeg ltd. empeg-car player.  Constructive criticism welcomed.
+ *	I would like to say, 'Thank You' to Greg Kroah-Hartman for the
+ *	use of his code, and for his guidance, advice and patience. :)
+ *	A 'Thank You' is in order for John Ripley of Empeg ltd for his
+ *	advice, and patience too.
+ * 
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#ifdef CONFIG_USB_SERIAL_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
+#include <linux/usb.h>
+
+#include "usb-serial.h"
+
+#define EMPEG_VENDOR_ID			0x084f
+#define EMPEG_PRODUCT_ID		0x0001
+
+#define MIN(a,b)		(((a)<(b))?(a):(b))
+
+/* function prototypes for an empeg-car player */
+static int  empeg_open			(struct usb_serial_port *port, struct file *filp);
+static void empeg_close			(struct usb_serial_port *port, struct file *filp);
+static int  empeg_write			(struct usb_serial_port *port,
+					int from_user,
+					const unsigned char *buf,
+					int count);
+static int  empeg_write_room		(struct usb_serial_port *port);
+static int  empeg_chars_in_buffer	(struct usb_serial_port *port);
+static void empeg_throttle		(struct usb_serial_port *port);
+static void empeg_unthrottle		(struct usb_serial_port *port);
+static int  empeg_startup		(struct usb_serial *serial);
+static void empeg_shutdown		(struct usb_serial *serial);
+static int  empeg_ioctl			(struct usb_serial_port *port,
+					struct file * file,
+					unsigned int cmd,
+					unsigned long arg);
+static void empeg_set_termios		(struct usb_serial_port *port, struct termios *old_termios);
+static void empeg_write_bulk_callback	(struct urb *urb);
+static void empeg_read_bulk_callback	(struct urb *urb);
+
+static __u16	empeg_vendor_id		= EMPEG_VENDOR_ID;
+static __u16	empeg_product_id	= EMPEG_PRODUCT_ID;
+struct usb_serial_device_type empeg_device = {
+	name:			"Empeg",
+	idVendor:		&empeg_vendor_id,
+	idProduct:		&empeg_product_id,
+	needs_interrupt_in:	MUST_HAVE_NOT,	/* must not have an interrupt in endpoint */
+	needs_bulk_in:		MUST_HAVE,	/* must have a bulk in endpoint */
+	needs_bulk_out:		MUST_HAVE,	/* must have a bulk out endpoint */
+	num_interrupt_in:	0,
+	num_bulk_in:		1,
+	num_bulk_out:		1,
+	num_ports:		1,
+	open:			empeg_open,
+	close:			empeg_close,
+	throttle:		empeg_throttle,
+	unthrottle:		empeg_unthrottle,
+	startup:		empeg_startup,
+	shutdown:		empeg_shutdown,
+	ioctl:			empeg_ioctl,
+	set_termios:		empeg_set_termios,
+	write:			empeg_write,
+	write_room:		empeg_write_room,
+	chars_in_buffer:	empeg_chars_in_buffer,
+	write_bulk_callback:	empeg_write_bulk_callback,
+	read_bulk_callback:	empeg_read_bulk_callback,
+};
+
+#define NUM_URBS			16
+#define URB_TRANSFER_BUFFER_SIZE	4096
+
+static struct urb	*write_urb_pool[NUM_URBS];
+static spinlock_t	write_urb_pool_lock;
+static int		bytes_in;
+static int		bytes_out;
+
+/******************************************************************************
+ * Empeg specific driver functions
+ ******************************************************************************/
+static int empeg_open (struct usb_serial_port *port, struct file *filp)
+{
+	struct usb_serial *serial = port->serial;
+	unsigned long flags;
+	int result;
+
+	if (port_paranoia_check (port, __FUNCTION__))
+		return -ENODEV;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	spin_lock_irqsave (&port->port_lock, flags);
+
+	++port->open_count;
+	MOD_INC_USE_COUNT;
+
+	if (!port->active) {
+
+		/* gb - 2000/11/05
+		 * personally, I think these termios should be set in
+		 * empeg_startup(), but it appears doing so leads to one
+		 * of those chicken/egg problems. :)
+		 */
+		port->tty->termios->c_iflag
+			&= ~(IGNBRK
+			| BRKINT
+			| PARMRK
+			| ISTRIP
+			| INLCR
+			| IGNCR
+			| ICRNL
+			| IXON);
+
+		port->tty->termios->c_oflag
+			&= ~OPOST;
+
+		port->tty->termios->c_lflag
+			&= ~(ECHO
+			| ECHONL
+			| ICANON
+			| ISIG
+			| IEXTEN);
+
+		port->tty->termios->c_cflag
+			&= ~(CSIZE
+			| PARENB);
+
+		port->tty->termios->c_cflag
+			|= CS8;
+
+		/* gb - 2000/12/03
+		 * Contributed by Borislav Deianov
+		 * Notify the tty driver that the termios have changed!!
+		 */
+		port->tty->ldisc.set_termios(port->tty, NULL);
+
+		/* gb - 2000/11/05
+		 * force low_latency on
+		 *
+		 * The tty_flip_buffer_push()'s in empeg_read_bulk_callback() will actually
+		 * force the data through if low_latency is set.  Otherwise the pushes are
+		 * scheduled; this is bad as it opens up the possibility of dropping bytes
+		 * on the floor.  We are trying to sustain high data transfer rates; and
+		 * don't want to drop bytes on the floor.
+		 * Moral: use low_latency - drop no bytes - life is good. :)
+		 */
+		port->tty->low_latency = 1;
+
+		port->active = 1;
+		bytes_in = 0;
+		bytes_out = 0;
+
+		/* Start reading from the device */
+		FILL_BULK_URB(
+			port->read_urb,
+			serial->dev, 
+			usb_rcvbulkpipe(serial->dev,
+				port->bulk_in_endpointAddress),
+			port->read_urb->transfer_buffer,
+			port->read_urb->transfer_buffer_length,
+			empeg_read_bulk_callback,
+			port);
+
+		port->read_urb->transfer_flags |= USB_QUEUE_BULK;
+
+		result = usb_submit_urb(port->read_urb);
+
+		if (result)
+			err(__FUNCTION__ " - failed submitting read urb, error %d", result);
+
+	}
+
+	spin_unlock_irqrestore (&port->port_lock, flags);
+
+	return 0;
+}
+
+
+static void empeg_close (struct usb_serial_port *port, struct file * filp)
+{
+	struct usb_serial *serial;
+	unsigned char *transfer_buffer;
+	unsigned long flags;
+
+	if (port_paranoia_check (port, __FUNCTION__))
+		return;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	serial = get_usb_serial (port, __FUNCTION__);
+	if (!serial)
+		return;
+
+	spin_lock_irqsave (&port->port_lock, flags);
+
+	--port->open_count;
+
+	if (port->open_count <= 0) {
+		transfer_buffer =  kmalloc (0x12, GFP_KERNEL);
+
+		if (!transfer_buffer) {
+			err(__FUNCTION__ " - kmalloc(%d) failed.", 0x12);
+		} else {
+			kfree (transfer_buffer);
+		}
+
+		/* shutdown our bulk read */
+		usb_unlink_urb (port->read_urb);
+		port->active = 0;
+		port->open_count = 0;
+	}
+
+	spin_unlock_irqrestore (&port->port_lock, flags);
+
+	/* Uncomment the following line if you want to see some statistics in your syslog */
+	/* info ("Bytes In = %d  Bytes Out = %d", bytes_in, bytes_out); */
+
+	MOD_DEC_USE_COUNT;
+
+}
+
+
+static int empeg_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count)
+{
+	struct usb_serial *serial = port->serial;
+	struct urb *urb;
+	const unsigned char *current_position = buf;
+	unsigned long flags;
+	int status;
+	int i;
+	int bytes_sent = 0;
+	int transfer_size;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	usb_serial_debug_data (__FILE__, __FUNCTION__, count, buf);
+
+	while (count > 0) {
+
+		/* try to find a free urb in our list of them */
+		urb = NULL;
+
+		spin_lock_irqsave (&write_urb_pool_lock, flags);
+
+		for (i = 0; i < NUM_URBS; ++i) {
+			if (write_urb_pool[i]->status != -EINPROGRESS) {
+				urb = write_urb_pool[i];
+				break;
+			}
+		}
+
+		spin_unlock_irqrestore (&write_urb_pool_lock, flags);
+
+		if (urb == NULL) {
+			dbg (__FUNCTION__ " - no more free urbs");
+			goto exit;
+		}
+
+		if (urb->transfer_buffer == NULL) {
+			urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
+			if (urb->transfer_buffer == NULL) {
+				err(__FUNCTION__" no more kernel memory...");
+				goto exit;
+			}
+		}
+
+		transfer_size = MIN (count, URB_TRANSFER_BUFFER_SIZE);
+
+		if (from_user) {
+			copy_from_user (urb->transfer_buffer, current_position, transfer_size);
+		} else {
+			memcpy (urb->transfer_buffer, current_position, transfer_size);
+		}
+
+		/* build up our urb */
+		FILL_BULK_URB (
+			urb,
+			serial->dev,
+			usb_sndbulkpipe(serial->dev,
+				port->bulk_out_endpointAddress), 
+			urb->transfer_buffer,
+			transfer_size,
+			empeg_write_bulk_callback,
+			port);
+
+		urb->transfer_flags |= USB_QUEUE_BULK;
+
+		/* send it down the pipe */
+		status = usb_submit_urb(urb);
+		if (status)
+			dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status);
+
+		current_position += transfer_size;
+		bytes_sent += transfer_size;
+		count -= transfer_size;
+		bytes_out += transfer_size;
+
+	}
+
+exit:
+	return bytes_sent;
+
+} 
+
+
+static int empeg_write_room (struct usb_serial_port *port)
+{
+	unsigned long flags;
+	int i;
+	int room = 0;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	spin_lock_irqsave (&port->port_lock, flags);
+
+	/* tally up the number of bytes available */
+	for (i = 0; i < NUM_URBS; ++i) {
+		if (write_urb_pool[i]->status != -EINPROGRESS) {
+			room += URB_TRANSFER_BUFFER_SIZE;
+		}
+	} 
+
+	spin_unlock_irqrestore (&port->port_lock, flags);
+
+	dbg(__FUNCTION__ " - returns %d", room);
+
+	return (room);
+
+}
+
+
+static int empeg_chars_in_buffer (struct usb_serial_port *port)
+{
+	unsigned long flags;
+	int i;
+	int chars = 0;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	spin_lock_irqsave (&port->port_lock, flags);
+
+	/* tally up the number of bytes waiting */
+	for (i = 0; i < NUM_URBS; ++i) {
+		if (write_urb_pool[i]->status == -EINPROGRESS) {
+			chars += URB_TRANSFER_BUFFER_SIZE;
+		}
+	}
+
+	spin_unlock_irqrestore (&port->port_lock, flags);
+
+	dbg (__FUNCTION__ " - returns %d", chars);
+
+	return (chars);
+
+}
+
+
+static void empeg_write_bulk_callback (struct urb *urb)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+
+	if (port_paranoia_check (port, __FUNCTION__))
+		return;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	if (urb->status) {
+		dbg(__FUNCTION__ " - nonzero write bulk status received: %d", urb->status);
+		return;
+	}
+
+	queue_task(&port->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+
+	return;
+
+}
+
+
+static void empeg_read_bulk_callback (struct urb *urb)
+{
+	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
+	struct tty_struct *tty;
+	unsigned char *data = urb->transfer_buffer;
+	int i;
+	int result;
+
+	if (port_paranoia_check (port, __FUNCTION__))
+		return;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	if (!serial) {
+		dbg(__FUNCTION__ " - bad serial pointer, exiting");
+		return;
+	}
+
+	if (urb->status) {
+		dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+		return;
+	}
+
+	usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
+
+	tty = port->tty;
+
+	if (urb->actual_length) {
+		for (i = 0; i < urb->actual_length ; ++i) {
+			/* gb - 2000/11/13
+			 * If we insert too many characters we'll overflow the buffer.
+			 * This means we'll lose bytes - Decidedly bad.
+			 */
+			if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
+				tty_flip_buffer_push(tty);
+				}
+			tty_insert_flip_char(tty, data[i], 0);
+		}
+		/* gb - 2000/11/13
+		 * Goes straight through instead of scheduling - if tty->low_latency is set.
+		 */
+		tty_flip_buffer_push(tty);
+		bytes_in += urb->actual_length;
+	}
+
+	/* Continue trying to always read  */
+	FILL_BULK_URB(
+		port->read_urb,
+		serial->dev, 
+		usb_rcvbulkpipe(serial->dev,
+			port->bulk_in_endpointAddress),
+		port->read_urb->transfer_buffer,
+		port->read_urb->transfer_buffer_length,
+		empeg_read_bulk_callback,
+		port);
+
+	port->read_urb->transfer_flags |= USB_QUEUE_BULK;
+
+	result = usb_submit_urb(port->read_urb);
+
+	if (result)
+		err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
+
+	return;
+
+}
+
+
+static void empeg_throttle (struct usb_serial_port *port)
+{
+	unsigned long flags;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	spin_lock_irqsave (&port->port_lock, flags);
+
+	usb_unlink_urb (port->read_urb);
+
+	spin_unlock_irqrestore (&port->port_lock, flags);
+
+	return;
+
+}
+
+
+static void empeg_unthrottle (struct usb_serial_port *port)
+{
+	unsigned long flags;
+	int result;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	spin_lock_irqsave (&port->port_lock, flags);
+
+	port->read_urb->dev = port->serial->dev;
+
+	result = usb_submit_urb(port->read_urb);
+
+	if (result)
+		err(__FUNCTION__ " - failed submitting read urb, error %d", result);
+
+	spin_unlock_irqrestore (&port->port_lock, flags);
+
+	return;
+
+}
+
+
+static int  empeg_startup (struct usb_serial *serial)
+{
+
+	dbg(__FUNCTION__);
+
+	dbg(__FUNCTION__ " - Set config to 1");
+	usb_set_configuration (serial->dev, 1);
+
+	/* continue on with initialization */
+	return 0;
+
+}
+
+
+static void empeg_shutdown (struct usb_serial *serial)
+{
+	int i;
+
+	dbg (__FUNCTION__);
+
+	/* stop reads and writes on all ports */
+	for (i=0; i < serial->num_ports; ++i) {
+		while (serial->port[i].open_count > 0) {
+			empeg_close (&serial->port[i], NULL);
+		}
+	}
+
+}
+
+
+static int empeg_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
+{
+	dbg(__FUNCTION__ " - port %d, cmd 0x%.4x", port->number, cmd);
+
+	return -ENOIOCTLCMD;
+}
+
+
+/* This function is all nice and good, but we don't change anything based on it :) */
+static void empeg_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+{
+	unsigned int cflag = port->tty->termios->c_cflag;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	/* check that they really want us to change something */
+	if (old_termios) {
+		if ((cflag == old_termios->c_cflag) &&
+		    (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
+			dbg(__FUNCTION__ " - nothing to change...");
+			return;
+		}
+	}
+
+	if ((!port->tty) || (!port->tty->termios)) {
+		dbg(__FUNCTION__" - no tty structures");
+		return;
+	}
+
+	/* get the byte size */
+	switch (cflag & CSIZE) {
+		case CS5:	dbg(__FUNCTION__ " - data bits = 5");   break;
+		case CS6:	dbg(__FUNCTION__ " - data bits = 6");   break;
+		case CS7:	dbg(__FUNCTION__ " - data bits = 7");   break;
+		default:
+		case CS8:	dbg(__FUNCTION__ " - data bits = 8");   break;
+	}
+
+	/* determine the parity */
+	if (cflag & PARENB)
+		if (cflag & PARODD)
+			dbg(__FUNCTION__ " - parity = odd");
+		else
+			dbg(__FUNCTION__ " - parity = even");
+	else
+		dbg(__FUNCTION__ " - parity = none");
+
+	/* figure out the stop bits requested */
+	if (cflag & CSTOPB)
+		dbg(__FUNCTION__ " - stop bits = 2");
+	else
+		dbg(__FUNCTION__ " - stop bits = 1");
+
+	/* figure out the flow control settings */
+	if (cflag & CRTSCTS)
+		dbg(__FUNCTION__ " - RTS/CTS is enabled");
+	else
+		dbg(__FUNCTION__ " - RTS/CTS is disabled");
+
+	/* determine software flow control */
+	if (I_IXOFF(port->tty))
+		dbg(__FUNCTION__ " - XON/XOFF is enabled, XON = %2x, XOFF = %2x", START_CHAR(port->tty), STOP_CHAR(port->tty));
+	else
+		dbg(__FUNCTION__ " - XON/XOFF is disabled");
+
+	/* get the baud rate wanted */
+	dbg(__FUNCTION__ " - baud rate = %d", tty_get_baud_rate(port->tty));
+
+	return;
+
+}
+
+
+static int __init empeg_init (void)
+{
+	struct urb *urb;
+	int i;
+
+	usb_serial_register (&empeg_device);
+
+	/* create our write urb pool and transfer buffers */ 
+	spin_lock_init (&write_urb_pool_lock);
+	for (i = 0; i < NUM_URBS; ++i) {
+		urb = usb_alloc_urb(0);
+		write_urb_pool[i] = urb;
+		if (urb == NULL) {
+			err("No more urbs???");
+			continue;
+		}
+
+		urb->transfer_buffer = NULL;
+		urb->transfer_buffer = kmalloc (URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
+		if (!urb->transfer_buffer) {
+			err (__FUNCTION__ " - out of memory for urb buffers.");
+			continue;
+		}
+	}
+
+	return 0;
+
+}
+
+
+static void __exit empeg_exit (void)
+{
+	int i;
+	unsigned long flags;
+
+	usb_serial_deregister (&empeg_device);
+
+	spin_lock_irqsave (&write_urb_pool_lock, flags);
+
+	for (i = 0; i < NUM_URBS; ++i) {
+		if (write_urb_pool[i]) {
+			/* FIXME - uncomment the following usb_unlink_urb call when
+			 * the host controllers get fixed to set urb->dev = NULL after
+			 * the urb is finished.  Otherwise this call oopses. */
+			/* usb_unlink_urb(write_urb_pool[i]); */
+			if (write_urb_pool[i]->transfer_buffer)
+				kfree(write_urb_pool[i]->transfer_buffer);
+			usb_free_urb (write_urb_pool[i]);
+		}
+	}
+
+	spin_unlock_irqrestore (&write_urb_pool_lock, flags);
+
+}
+
+
+module_init(empeg_init);
+module_exit(empeg_exit);
+
+MODULE_AUTHOR("Gary Brubaker <xavyer@ix.netcom.com>");
+MODULE_DESCRIPTION("USB Empeg Mark I/II Driver");
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/ftdi_sio.c linux.19p18/drivers/usb/serial/ftdi_sio.c
--- linux.vanilla/drivers/usb/serial/ftdi_sio.c	Mon Dec 11 22:13:01 2000
+++ linux.19p18/drivers/usb/serial/ftdi_sio.c	Tue Jan  9 11:55:48 2001
@@ -12,6 +12,28 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
+ * See http://reality.sgi.com/bryder_wellington/ftdi_sio for upto date testing info
+ *     and extra documentation
+ *       
+ * (12/3/2000) Bill Ryder
+ *     Added support for 8U232AM device.
+ *     Moved PID and VIDs into header file only.
+ *     Turned on low-latency for the tty (device will do high baudrates)
+ *     Added shutdown routine to close files when device removed.
+ *     More debug and error message cleanups.
+ *     
+ *
+ * (11/13/2000) Bill Ryder
+ *     Added spinlock protected open code and close code.
+ *     Multiple opens work (sort of - see webpage mentioned above).
+ *     Cleaned up comments. Removed multiple PID/VID definitions.
+ *     Factorised cts/dtr code
+ *     Made use of __FUNCTION__ in dbg's
+ *      
+ * (10/05/2000) gkh
+ *	Fixed bug with urb->dev not being set properly, now that the usb
+ *	core needs it.
+ * 
  * (09/11/2000) gkh
  *	Removed DEBUG #ifdefs with call to usb_serial_debug_data
  *
@@ -20,11 +42,11 @@
  *	driver is a loadable module now.
  *
  * (04/04/2000) Bill Ryder 
- *         Fixed bugs in TCGET/TCSET ioctls (by removing them - they are 
- *             handled elsewhere in the serial driver chain).
+ *      Fixed bugs in TCGET/TCSET ioctls (by removing them - they are 
+ *        handled elsewhere in the tty io driver chain).
  *
  * (03/30/2000) Bill Ryder 
- *         Implemented lots of ioctls
+ *      Implemented lots of ioctls
  * 	Fixed a race condition in write
  * 	Changed some dbg's to errs
  *
@@ -36,6 +58,7 @@
 /* Bill Ryder - bryder@sgi.com - wrote the FTDI_SIO implementation */
 /* Thanx to FTDI for so kindly providing details of the protocol required */
 /*   to talk to the device */
+/* Thanx to gkh and the rest of the usb dev group for all code I have assimilated :-) */
 
 
 #include <linux/config.h>
@@ -64,11 +87,19 @@
 
 #include "ftdi_sio.h"
 
-#define FTDI_VENDOR_ID			0x0403
-#define FTDI_SIO_SERIAL_CONVERTER_ID	0x8372
 
+
+
+struct ftdi_private {
+	ftdi_type_t ftdi_type;
+	char last_status_byte; /* device sends this every 40ms when open */
+	
+	
+};
 /* function prototypes for a FTDI serial converter */
 static int  ftdi_sio_startup		(struct usb_serial *serial);
+static int  ftdi_8U232AM_startup	(struct usb_serial *serial);
+static void ftdi_sio_shutdown		(struct usb_serial *serial);
 static int  ftdi_sio_open		(struct usb_serial_port *port, struct file *filp);
 static void ftdi_sio_close		(struct usb_serial_port *port, struct file *filp);
 static int  ftdi_sio_write		(struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
@@ -78,8 +109,9 @@
 static int  ftdi_sio_ioctl		(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
 
 /* All of the device info needed for the FTDI SIO serial converter */
-static __u16	ftdi_vendor_id		= FTDI_VENDOR_ID;
-static __u16	ftdi_sio_product_id	= FTDI_SIO_SERIAL_CONVERTER_ID;
+static __u16	ftdi_vendor_id		= FTDI_VID;
+static __u16	ftdi_sio_product_id	= FTDI_SIO_PID;
+static __u16	ftdi_8U232AM_product_id	= FTDI_8U232AM_PID;
 struct usb_serial_device_type ftdi_sio_device = {
 	name:			"FTDI SIO",
 	idVendor:		&ftdi_vendor_id,	/* the FTDI vendor ID */
@@ -99,6 +131,29 @@
 	ioctl:			ftdi_sio_ioctl,
 	set_termios:		ftdi_sio_set_termios,
 	startup:		ftdi_sio_startup,
+        shutdown:               ftdi_sio_shutdown,
+};
+
+struct usb_serial_device_type ftdi_8U232AM_device = {
+	name:			"FTDI 8U232AM",
+	idVendor:		&ftdi_vendor_id,	/* the FTDI vendor ID */
+	idProduct:		&ftdi_8U232AM_product_id,
+	needs_interrupt_in:	DONT_CARE,
+	needs_bulk_in:		MUST_HAVE,
+	needs_bulk_out:		MUST_HAVE,
+	num_interrupt_in:	0,
+	num_bulk_in:		1,
+	num_bulk_out:		1,
+	num_ports:		1,
+	open:			ftdi_sio_open,
+	close:			ftdi_sio_close,
+	write:			ftdi_sio_write,
+	read_bulk_callback:	ftdi_sio_read_bulk_callback,
+	write_bulk_callback:	ftdi_sio_write_bulk_callback,
+	ioctl:			ftdi_sio_ioctl,
+	set_termios:		ftdi_sio_set_termios,
+	startup:		ftdi_8U232AM_startup,
+        shutdown:               ftdi_sio_shutdown,
 };
 
 
@@ -106,119 +161,151 @@
  * ***************************************************************************
  * FTDI SIO Serial Converter specific driver functions
  * ***************************************************************************
- *
- * Bill Ryder bryder@sgi.com of Silicon Graphics, Inc. did the FTDI_SIO code
- * Thanx to FTDI for so kindly providing details of the protocol required
- *   to talk to the device - http://www.ftdi.co.uk
- *
- * Tested as at this version - other stuff might work
- * 23 March 2000
- *     Works:
- *      Baudrates - 9600, 38400,19200, 57600, 115200  
- *      TIOCMBIC - TIOCM_DTR / TIOCM_RTS 
- *      TIOCMBIS - TIOCM_DTR / TIOCM_RTS 
- *      TIOCMSET - DTR on/RTSon  / DTR off, RTS off 
- *      no parity:CS8 even parity:CS7 odd parity:CS7 
- *      CRTSCTS flow control 
- *     
- *      Pilot-xfer zillions of times
- *  
- *      cu works with dir option 
- *
- *   Not Tested (ie might not work): 
- *      xon/xoff flow control 
- *      ppp (modem handling in general) 
- *
- *   KNOWN BUGS:
- *    Multiple Opens
- *    ==============
- *      Seems to have problem when opening an already open port, 
- *      Get I/O error on first attempt, then it lets you in. 
- *      Need to do proper usage counting - keep registered callbacks for first opener.
- *     
- *     Reproduce with: 
- *       cu -l /dev/ttyUSB0 dir 
- *       whilst cu is running do:
- *        stty -a < /dev/ttyUSB0  
- *
- *     from stty get: 'bash: /dev/ttyUSB0: Invalid argument ' 
- *     from cu get 
- *        write: Invalid argument 
- *    
- *    Initialisation Problem
- *    ======================
- *    Pilot transfer required me to run the serial_loopback program before it would work.
- *    Still working on this. See the webpage http://reality.sgi.com/bryder_wellington/ftdi_sio
- *
  */
 
 #define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
 
-/* do some startup allocations not currently performed by usb_serial_probe() */
+/* utility functions to set and unset dtr and rts */
+#define HIGH 1
+#define LOW 0
+static int set_rts(struct usb_device *dev, 
+		   unsigned int pipe,
+		   int high_or_low)
+{
+	static char buf[1];
+	unsigned ftdi_high_or_low = (high_or_low? FTDI_SIO_SET_RTS_HIGH : 
+				FTDI_SIO_SET_RTS_LOW);
+	return(usb_control_msg(dev, pipe,
+			       FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
+			       FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+			       ftdi_high_or_low, 0, 
+			       buf, 0, WDR_TIMEOUT));
+}
+static int set_dtr(struct usb_device *dev, 
+		   unsigned int pipe,
+		   int high_or_low)
+{
+	static char buf[1];
+	unsigned ftdi_high_or_low = (high_or_low? FTDI_SIO_SET_DTR_HIGH : 
+				FTDI_SIO_SET_DTR_LOW);
+	return(usb_control_msg(dev, pipe,
+			       FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
+			       FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
+			       ftdi_high_or_low, 0, 
+			       buf, 0, WDR_TIMEOUT));
+}
+
+
+
 static int ftdi_sio_startup (struct usb_serial *serial)
 {
+	struct ftdi_private *priv;
+	
 	init_waitqueue_head(&serial->port[0].write_wait);
 	
+	priv = serial->port->private = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL);
+	if (!priv){
+		err(__FUNCTION__"- kmalloc(%d) failed.", sizeof(struct ftdi_private));
+		return -ENOMEM;
+	}
+
+	priv->ftdi_type = sio;
+	
+	return (0);
+}
+
+
+static int ftdi_8U232AM_startup (struct usb_serial *serial)
+{
+	struct ftdi_private *priv;
+ 
+	init_waitqueue_head(&serial->port[0].write_wait);
+
+	priv = serial->port->private = kmalloc(sizeof(struct ftdi_private), GFP_KERNEL);
+	if (!priv){
+		err(__FUNCTION__"- kmalloc(%d) failed.", sizeof(struct ftdi_private));
+		return -ENOMEM;
+	}
+
+	priv->ftdi_type = F8U232AM;
+	
 	return (0);
 }
 
+static void ftdi_sio_shutdown (struct usb_serial *serial)
+{
+	
+	dbg (__FUNCTION__);
+
+	/* Close ports if they are open */
+	while (serial->port[0].open_count > 0) {
+		ftdi_sio_close (&serial->port[0], NULL);
+	}
+	if (serial->port->private){
+		kfree(serial->port->private);
+		serial->port->private = NULL;
+	}
+}
+
+
+
 static int  ftdi_sio_open (struct usb_serial_port *port, struct file *filp)
 { /* ftdi_sio_open */
 	struct termios tmp_termios;
 	struct usb_serial *serial = port->serial;
+	unsigned long flags;	/* Used for spinlock */
+	int result;
 	char buf[1]; /* Needed for the usb_control_msg I think */
 
-	dbg("ftdi_sio_open port %d", port->number);
-
-        /* FIXME - multiple concurrent opens cause trouble */
-	if (port->active) {
-		err ("port already open");
-		return -EINVAL;
-	}
-	port->active = 1; /* FIXME - For multiple open this should increment */
-
-	/* See ftdi_sio.h for description of what is reset */
-	usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-			FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, 
-			FTDI_SIO_RESET_SIO, 
-			0, buf, 0, WDR_TIMEOUT);
-
-	/* Setup termios */
-	port->tty->termios->c_cflag =
-		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	dbg(__FUNCTION__);
 
+	spin_lock_irqsave (&port->port_lock, flags);
 	
-	ftdi_sio_set_termios(port, &tmp_termios);	
+	MOD_INC_USE_COUNT;
+	++port->open_count;
 
-	/* Disable flow control */
-	if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-			    FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
-			    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
-			    0, 0, 
-			    buf, 0, WDR_TIMEOUT) < 0) {
-		err("error from flowcontrol urb");
-		return(-EINVAL);
-	}	    
-
-	/* Turn on RTS and DTR since we are not flow controlling*/
-	if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-			    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
-			    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-			    (unsigned)FTDI_SIO_SET_DTR_HIGH, 0, 
-			    buf, 0, WDR_TIMEOUT) < 0) {
-		err("Error from DTR HIGH urb");
+	if (!port->active){
+		port->active = 1;
+
+		spin_unlock_irqrestore (&port->port_lock, flags);
+
+		/* do not allow a task to be queued to deliver received data */
+		port->tty->low_latency = 1;
+
+		/* No error checking for this (will get errors later anyway) */
+		/* See ftdi_sio.h for description of what is reset */
+		usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+				FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, 
+				FTDI_SIO_RESET_SIO, 
+				0, buf, 0, WDR_TIMEOUT);
+
+		/* Setup termios defaults. According to tty_io.c the 
+		   settings are driver specific */
+		port->tty->termios->c_cflag =
+			B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+
+		/* ftdi_sio_set_termios  will send usb control messages */
+		ftdi_sio_set_termios(port, &tmp_termios);	
+
+		/* Turn on RTS and DTR since we are not flow controlling by default */
+		if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),HIGH) < 0) {
+			err(__FUNCTION__ " Error from DTR HIGH urb");
+		}
+		if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),HIGH) < 0){
+			err(__FUNCTION__ " Error from RTS HIGH urb");
+		}
+	
+		/* Start reading from the device */
+		FILL_BULK_URB(port->read_urb, serial->dev, 
+			      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+			      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
+			      ftdi_sio_read_bulk_callback, port);
+		result = usb_submit_urb(port->read_urb);
+		if (result)
+			err(__FUNCTION__ " - failed submitting read urb, error %d", result);
+	} else { /* the port was already active - so no initialisation is done */
+		spin_unlock_irqrestore (&port->port_lock, flags);
 	}
-	if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-			    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
-			    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-			    (unsigned)FTDI_SIO_SET_RTS_HIGH, 0, 
-			    buf, 0, WDR_TIMEOUT) < 0) {
-		err("Error from RTS HIGH urb");
-	}
-	
-	/*Start reading from the device*/
-	if (usb_submit_urb(port->read_urb))
-		err("usb_submit_urb(read bulk) failed");
 
 	return (0);
 } /* ftdi_sio_open */
@@ -229,41 +316,52 @@
 	struct usb_serial *serial = port->serial;
 	unsigned int c_cflag = port->tty->termios->c_cflag;
 	char buf[1];
+	unsigned long flags;
 
-	dbg("ftdi_sio_close port %d", port->number);
-	
-	if (c_cflag & HUPCL){
-		/* Disable flow control */
-		if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-				    FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
-				    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
-				    0, 0, 
-				    buf, 0, WDR_TIMEOUT) < 0) {
-			err("error from flowcontrol urb");
-		}	    
+	dbg( __FUNCTION__);
 
-		/* drop DTR */
- 		if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-				    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
-				    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-				    (unsigned)FTDI_SIO_SET_DTR_LOW, 0, 
-				    buf, 0, WDR_TIMEOUT) < 0) {
-			err("Error from DTR LOW urb");
+	spin_lock_irqsave (&port->port_lock, flags);
+	--port->open_count;
+
+	if (port->open_count <= 0) {
+		spin_unlock_irqrestore (&port->port_lock, flags);
+		if (c_cflag & HUPCL){
+			/* Disable flow control */
+			if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+					    FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
+					    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
+					    0, 0, 
+					    buf, 0, WDR_TIMEOUT) < 0) {
+				err("error from flowcontrol urb");
+			}	    
+
+			/* drop DTR */
+			if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0), LOW) < 0){
+				err("Error from DTR LOW urb");
+			}
+			/* drop RTS */
+			if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0) {
+				err("Error from RTS LOW urb");
+			}	
+		} /* Note change no line is hupcl is off */
+
+		/* shutdown our bulk reads and writes */
+		usb_unlink_urb (port->write_urb);
+		usb_unlink_urb (port->read_urb);
+		port->active = 0;
+		port->open_count = 0;
+	} else {  
+		spin_unlock_irqrestore (&port->port_lock, flags);
+
+		/* Send a HUP if necessary */
+		if (!(port->tty->termios->c_cflag & CLOCAL)){
+			tty_hangup(port->tty);
 		}
-		/* drop RTS */
-		if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-				    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
-				    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-				    (unsigned)FTDI_SIO_SET_RTS_LOW, 0, 
-				    buf, 0, WDR_TIMEOUT) < 0) {
-			err("Error from RTS LOW urb");
-		}	
+		
 	}
 
-	/* shutdown our bulk reads and writes */
-	usb_unlink_urb (port->write_urb);
-	usb_unlink_urb (port->read_urb);
-	port->active = 0;
+	MOD_DEC_USE_COUNT;
+
 } /* ftdi_sio_close */
 
 
@@ -277,32 +375,37 @@
 			   const unsigned char *buf, int count)
 { /* ftdi_sio_write */
 	struct usb_serial *serial = port->serial;
-	const int data_offset = 1;
+	struct ftdi_private *priv = (struct ftdi_private *)port->private;
+	int data_offset ;
 	int rc; 
+	int result;
 	DECLARE_WAITQUEUE(wait, current);
 	
-	dbg("ftdi_sio_serial_write port %d, %d bytes", port->number, count);
+	dbg(__FUNCTION__ " port %d, %d bytes", port->number, count);
 
 	if (count == 0) {
 		err("write request of 0 bytes");
 		return 0;
 	}
+	
+	if (priv->ftdi_type == sio){
+		data_offset = 1;
+	} else {
+		data_offset = 0;
+	}
+        dbg("data_offset set to %d",data_offset);
 
 	/* only do something if we have a bulk out endpoint */
 	if (serial->num_bulk_out) {
 		unsigned char *first_byte = port->write_urb->transfer_buffer;
 
 		/* Was seeing a race here, got a read callback, then write callback before
-		   hitting interuptible_sleep_on  - so wrapping in add_wait_queue stuff */
+		   hitting interuptible_sleep_on  - so wrapping in a wait_queue */
 
 		add_wait_queue(&port->write_wait, &wait);
 		set_current_state (TASK_INTERRUPTIBLE);
 		while (port->write_urb->status == -EINPROGRESS) {
-			dbg("ftdi_sio - write in progress - retrying");
-			if (0 /* file->f_flags & O_NONBLOCK */) {
-				rc = -EAGAIN;
-				goto err;
-			}
+			dbg(__FUNCTION__ " write in progress - retrying");
 			if (signal_pending(current)) {
 				current->state = TASK_RUNNING;
 				remove_wait_queue(&port->write_wait, &wait);
@@ -330,20 +433,28 @@
 			       buf, count - data_offset );
 		}  
 
-		/* Write the control byte at the front of the packet*/
 		first_byte = port->write_urb->transfer_buffer;
-		*first_byte = 1 | ((count-data_offset) << 2) ; 
+		if (data_offset > 0){
+			/* Write the control byte at the front of the packet*/
+			*first_byte = 1 | ((count-data_offset) << 2) ; 
+		}
 
-		dbg("Bytes: %d, Control Byte: 0o%03o",count, first_byte[0]);
+		dbg(__FUNCTION__ " Bytes: %d, First Byte: 0o%03o",count, first_byte[0]);
 		usb_serial_debug_data (__FILE__, __FUNCTION__, count, first_byte);
 		
 		/* send the data out the bulk port */
-		port->write_urb->transfer_buffer_length = count;
-
-		if (usb_submit_urb(port->write_urb))
-			err("usb_submit_urb(write bulk) failed");
+		FILL_BULK_URB(port->write_urb, serial->dev, 
+			      usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
+			      port->write_urb->transfer_buffer, count,
+			      ftdi_sio_write_bulk_callback, port);
+		
+		result = usb_submit_urb(port->write_urb);
+		if (result) {
+			err(__FUNCTION__ " - failed submitting write urb, error %d", result);
+			return 0;
+		}
 
-		dbg("write returning: %d", count - data_offset);
+		dbg(__FUNCTION__ " write returning: %d", count - data_offset);
 		return (count - data_offset);
 	}
 	
@@ -387,14 +498,16 @@
 static void ftdi_sio_read_bulk_callback (struct urb *urb)
 { /* ftdi_sio_serial_buld_callback */
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+	struct ftdi_private *priv = (struct ftdi_private *)port->private;
 	struct usb_serial *serial;
        	struct tty_struct *tty = port->tty ;
        	unsigned char *data = urb->transfer_buffer;
 
 	const int data_offset = 2;
 	int i;
+	int result;
 
-	dbg("ftdi_sio read callback");
+	dbg(__FUNCTION__);
 
 	if (port_paranoia_check (port, "ftdi_sio_read_bulk_callback")) {
 		return;
@@ -404,10 +517,6 @@
 	if (serial_paranoia_check (serial, "ftdi_sio_read_bulk_callback")) {
 		return;
 	}
-	
-	/* TO DO -- check for hung up line and handle appropriately: */
-	/*   send hangup (need to find out how to do this) */
- 
 
 	if (urb->status) {
 		/* This will happen at close every time so it is a dbg not an err */
@@ -421,6 +530,14 @@
                 dbg("Just status");
         }
 
+	priv->last_status_byte = data[0]; /* this has modem control lines */
+
+	/* TO DO -- check for hung up line and handle appropriately: */
+	/*   send hangup  */
+	/* See acm.c - you do a tty_hangup  - eg tty_hangup(tty) */
+	/* if CD is dropped and the line is not CLOCAL then we should hangup */
+
+
 	if (urb->actual_length > data_offset) {
 		for (i = data_offset ; i < urb->actual_length ; ++i) {
 			tty_insert_flip_char(tty, data[i], 0);
@@ -429,12 +546,65 @@
 	}
 
 	/* Continue trying to always read  */
-	if (usb_submit_urb(urb))
-		err("failed resubmitting read urb");
+	FILL_BULK_URB(urb, serial->dev, 
+		      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+		      urb->transfer_buffer, urb->transfer_buffer_length,
+		      ftdi_sio_read_bulk_callback, port);
+
+	result = usb_submit_urb(urb);
+	if (result)
+		err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
 
 	return;
 } /* ftdi_sio_serial_read_bulk_callback */
 
+
+__u16 translate_baudrate_to_ftdi(unsigned int cflag, ftdi_type_t ftdi_type) 
+{ /* translate_baudrate_to_ftdi */
+	
+	__u16 urb_value = ftdi_sio_b9600;
+
+	if (ftdi_type == sio){
+		switch(cflag & CBAUD){
+		case B0: break; /* ignored by this */
+		case B300: urb_value = ftdi_sio_b300; dbg("Set to 300"); break;
+		case B600: urb_value = ftdi_sio_b600; dbg("Set to 600") ; break;
+		case B1200: urb_value = ftdi_sio_b1200; dbg("Set to 1200") ; break;
+		case B2400: urb_value = ftdi_sio_b2400; dbg("Set to 2400") ; break;
+		case B4800: urb_value = ftdi_sio_b4800; dbg("Set to 4800") ; break;
+		case B9600: urb_value = ftdi_sio_b9600; dbg("Set to 9600") ; break;
+		case B19200: urb_value = ftdi_sio_b19200; dbg("Set to 19200") ; break;
+		case B38400: urb_value = ftdi_sio_b38400; dbg("Set to 38400") ; break;
+		case B57600: urb_value = ftdi_sio_b57600; dbg("Set to 57600") ; break;
+		case B115200: urb_value = ftdi_sio_b115200; dbg("Set to 115200") ; break;
+		default: dbg(__FUNCTION__ " FTDI_SIO does not support the baudrate (%d) requested",
+			     (cflag & CBAUD)); 
+		   break;
+		}
+	} else { /* it is 8U232AM */
+		switch(cflag & CBAUD){
+		case B0: break; /* ignored by this */
+		case B300: urb_value = ftdi_8U232AM_48MHz_b300; dbg("Set to 300"); break;
+		case B600: urb_value = ftdi_8U232AM_48MHz_b600; dbg("Set to 600") ; break;
+		case B1200: urb_value = ftdi_8U232AM_48MHz_b1200; dbg("Set to 1200") ; break;
+		case B2400: urb_value = ftdi_8U232AM_48MHz_b2400; dbg("Set to 2400") ; break;
+		case B4800: urb_value = ftdi_8U232AM_48MHz_b4800; dbg("Set to 4800") ; break;
+		case B9600: urb_value = ftdi_8U232AM_48MHz_b9600; dbg("Set to 9600") ; break;
+		case B19200: urb_value = ftdi_8U232AM_48MHz_b19200; dbg("Set to 19200") ; break;
+		case B38400: urb_value = ftdi_8U232AM_48MHz_b38400; dbg("Set to 38400") ; break;
+		case B57600: urb_value = ftdi_8U232AM_48MHz_b57600; dbg("Set to 57600") ; break;
+		case B115200: urb_value = ftdi_8U232AM_48MHz_b115200; dbg("Set to 115200") ; break;
+		case B230400: urb_value = ftdi_8U232AM_48MHz_b230400; dbg("Set to 230400") ; break;
+		case B460800: urb_value = ftdi_8U232AM_48MHz_b460800; dbg("Set to 460800") ; break;
+		case B921600: urb_value = ftdi_8U232AM_48MHz_b921600; dbg("Set to 921600") ; break;
+		default: dbg(__FUNCTION__ " The baudrate (%d) requested is not implemented",
+			     (cflag & CBAUD)); 
+		   break;
+		}
+	}
+	return(urb_value);
+}
+
 /* As I understand this - old_termios contains the original termios settings */
 /*  and tty->termios contains the new setting to be used */
 /* */
@@ -444,10 +614,12 @@
 { /* ftdi_sio_set_termios */
 	struct usb_serial *serial = port->serial;
 	unsigned int cflag = port->tty->termios->c_cflag;
-	__u16 urb_value; /* Will hold the new flags */
+	struct ftdi_private *priv = (struct ftdi_private *)port->private;	
+	__u16 urb_value; /* will hold the new flags */
 	char buf[1]; /* Perhaps I should dynamically alloc this? */
 	
-	dbg("ftdi_sio_set_termios port %d", port->number);
+	
+	dbg(__FUNCTION__);
 
 
 	/* FIXME -For this cut I don't care if the line is really changing or 
@@ -481,26 +653,12 @@
 			    FTDI_SIO_SET_DATA_REQUEST_TYPE,
 			    urb_value , 0,
 			    buf, 0, 100) < 0) {
-		err("FAILED to set databits/stopbits/parity");
+		err(__FUNCTION__ " FAILED to set databits/stopbits/parity");
 	}	   
 
 	/* Now do the baudrate */
-
-	switch(cflag & CBAUD){
-	case B0: break; /* Handled below */
-	case B300: urb_value = ftdi_sio_b300; dbg("Set to 300"); break;
-	case B600: urb_value = ftdi_sio_b600; dbg("Set to 600") ; break;
-	case B1200: urb_value = ftdi_sio_b1200; dbg("Set to 1200") ; break;
-	case B2400: urb_value = ftdi_sio_b2400; dbg("Set to 2400") ; break;
-	case B4800: urb_value = ftdi_sio_b4800; dbg("Set to 4800") ; break;
-	case B9600: urb_value = ftdi_sio_b9600; dbg("Set to 9600") ; break;
-	case B19200: urb_value = ftdi_sio_b19200; dbg("Set to 19200") ; break;
-	case B38400: urb_value = ftdi_sio_b38400; dbg("Set to 38400") ; break;
-	case B57600: urb_value = ftdi_sio_b57600; dbg("Set to 57600") ; break;
-	case B115200: urb_value = ftdi_sio_b115200; dbg("Set to 115200") ; break;
-	default: dbg("FTDI_SIO does not support the baudrate requested"); 
-		/* FIXME - how to return an error for this? */ break;
-	}
+	urb_value = translate_baudrate_to_ftdi((cflag & CBAUD), priv->ftdi_type);
+	
 	if ((cflag & CBAUD) == B0 ) {
 		/* Disable flow control */
 		if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
@@ -508,38 +666,31 @@
 				    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
 				    0, 0, 
 				    buf, 0, WDR_TIMEOUT) < 0) {
-			err("error from disable flowcontrol urb");
+			err(__FUNCTION__ " error from disable flowcontrol urb");
 		}	    
 		/* Drop RTS and DTR */
-		if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-				    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
-				    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-				    (unsigned)FTDI_SIO_SET_DTR_LOW, 0, 
-				    buf, 0, WDR_TIMEOUT) < 0) {
-			err("Error from DTR LOW urb");
+		if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0){
+			err(__FUNCTION__ " Error from DTR LOW urb");
 		}
-		if (usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-				    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
-				    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-				    (unsigned)FTDI_SIO_SET_RTS_LOW, 0, 
-				    buf, 0, WDR_TIMEOUT) < 0) {
-			err("Error from RTS LOW urb");
+		if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),LOW) < 0){
+			err(__FUNCTION__ " Error from RTS LOW urb");
 		}	
 		
 	} else {
+		/* set the baudrate determined before */
 		if (usb_control_msg(serial->dev, 
 				    usb_sndctrlpipe(serial->dev, 0),
 				    FTDI_SIO_SET_BAUDRATE_REQUEST, 
 				    FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE,
 				    urb_value, 0, 
 				    buf, 0, 100) < 0) {
-			err("urb failed to set baurdrate");
+			err(__FUNCTION__ " urb failed to set baurdrate");
 		}
 	}
 	/* Set flow control */
 	/* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */
 	if (cflag & CRTSCTS) {
-		dbg("Setting to CRTSCTS flow control");
+		dbg(__FUNCTION__ " Setting to CRTSCTS flow control");
 		if (usb_control_msg(serial->dev, 
 				    usb_sndctrlpipe(serial->dev, 0),
 				    FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
@@ -550,9 +701,8 @@
 		}		
 		
 	} else { 
-		/* CHECK Assuming XON/XOFF handled by stack - not by device */
-		/* Disable flow control */
-		dbg("Turning off hardware flow control");
+		/* CHECKME Assuming XON/XOFF handled by tty stack - not by device */
+		dbg(__FUNCTION__ " Turning off hardware flow control");
 		if (usb_control_msg(serial->dev, 
 				    usb_sndctrlpipe(serial->dev, 0),
 				    FTDI_SIO_SET_FLOW_CTRL_REQUEST, 
@@ -569,26 +719,38 @@
 static int ftdi_sio_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
 {
 	struct usb_serial *serial = port->serial;
+	struct ftdi_private *priv = (struct ftdi_private *)port->private;
 	__u16 urb_value=0; /* Will hold the new flags */
 	char buf[1];
 	int  ret, mask;
 	
-	dbg("ftdi_sio_ioctl - cmd 0x%04x", cmd);
+	dbg(__FUNCTION__ " cmd 0x%04x", cmd);
 
 	/* Based on code from acm.c and others */
 	switch (cmd) {
 
 	case TIOCMGET:
-		dbg("TIOCMGET");
-		/* Request the status from the device */
-		if ((ret = usb_control_msg(serial->dev, 
-					   usb_rcvctrlpipe(serial->dev, 0),
-					   FTDI_SIO_GET_MODEM_STATUS_REQUEST, 
-					   FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
-					   0, 0, 
-					   buf, 1, HZ * 5)) < 0 ) {
-			dbg("Get not get modem status of device");
-			return(ret);
+		dbg(__FUNCTION__ " TIOCMGET");
+		/* The MODEM_STATUS_REQUEST works for the sio but not the 232 */
+		if (priv->ftdi_type == sio){
+			/* TO DECIDE - use the 40ms status packets or not? */
+			/*   PRO: No need to send urb */
+			/*   CON: Could be 40ms out of date */
+
+			/* Request the status from the device */
+			if ((ret = usb_control_msg(serial->dev, 
+						   usb_rcvctrlpipe(serial->dev, 0),
+						   FTDI_SIO_GET_MODEM_STATUS_REQUEST, 
+						   FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
+						   0, 0, 
+						   buf, 1, WDR_TIMEOUT)) < 0 ) {
+				err(__FUNCTION__ " Could not get modem status of device - err: %d",
+				    ret);
+				return(ret);
+			}
+		} else {
+			/* This gets updated every 40ms - so just copy it in */
+			buf[0] = priv->last_status_byte;
 		}
 
 		return put_user((buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) |
@@ -599,51 +761,33 @@
 		break;
 
 	case TIOCMSET: /* Turns on and off the lines as specified by the mask */
-		dbg("TIOCMSET");
+		dbg(__FUNCTION__ " TIOCMSET");
 		if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
-		urb_value = ((mask & TIOCM_DTR) ? FTDI_SIO_SET_DTR_HIGH : FTDI_SIO_SET_DTR_LOW);
-		if ((ret = usb_control_msg(serial->dev, 
-				    usb_sndctrlpipe(serial->dev, 0),
-				    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
-				    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-				    urb_value , 0,
-				    buf, 0, WDR_TIMEOUT)) < 0){
-			err("Urb to set DTR failed");
-			return(ret);
-		}
-		urb_value = ((mask & TIOCM_RTS) ? FTDI_SIO_SET_RTS_HIGH : FTDI_SIO_SET_RTS_LOW);
-		if ((ret = usb_control_msg(serial->dev, 
-				    usb_sndctrlpipe(serial->dev, 0),
-				    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
-				    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-				    urb_value , 0,
-				    buf, 0, WDR_TIMEOUT)) < 0){
-			err("Urb to set RTS failed");
-			return(ret);
-		}
+		urb_value = ((mask & TIOCM_DTR) ? HIGH : LOW);
+		if (set_dtr(serial->dev, usb_sndctrlpipe(serial->dev, 0),urb_value) < 0){
+			err("Error from DTR set urb (TIOCMSET)");
+		}
+		urb_value = ((mask & TIOCM_RTS) ? HIGH : LOW);
+		if (set_rts(serial->dev, usb_sndctrlpipe(serial->dev, 0),urb_value) < 0){
+			err("Error from RTS set urb (TIOCMSET)");
+		}	
 		break;
 					
 	case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */
-		dbg("TIOCMBIS");
+		dbg(__FUNCTION__ " TIOCMBIS");
  	        if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
   	        if (mask & TIOCM_DTR){
-			if ((ret = usb_control_msg(serial->dev, 
-					    usb_sndctrlpipe(serial->dev, 0),
-					    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
-					    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-					    FTDI_SIO_SET_DTR_HIGH , 0,
-					    buf, 0, WDR_TIMEOUT)) < 0){
+			if ((ret = set_dtr(serial->dev, 
+					   usb_sndctrlpipe(serial->dev, 0),
+					   HIGH)) < 0) {
 				err("Urb to set DTR failed");
 				return(ret);
-				}
 			}
-			if (mask & TIOCM_RTS) {
-			if ((ret = usb_control_msg(serial->dev, 
-					    usb_sndctrlpipe(serial->dev, 0),
-					    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
-					    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-					    FTDI_SIO_SET_RTS_HIGH , 0,
-					    buf, 0, WDR_TIMEOUT)) < 0){
+		}
+		if (mask & TIOCM_RTS) {
+			if ((ret = set_rts(serial->dev, 
+					   usb_sndctrlpipe(serial->dev, 0),
+					   HIGH)) < 0){
 				err("Urb to set RTS failed");
 				return(ret);
 			}
@@ -651,26 +795,20 @@
 					break;
 
 	case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */
-		dbg("TIOCMBIC");
+		dbg(__FUNCTION__ " TIOCMBIC");
  	        if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
   	        if (mask & TIOCM_DTR){
-			if ((ret = usb_control_msg(serial->dev, 
-					    usb_sndctrlpipe(serial->dev, 0),
-					    FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
-					    FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-					    FTDI_SIO_SET_DTR_LOW , 0,
-					    buf, 0, WDR_TIMEOUT)) < 0){
+			if ((ret = set_dtr(serial->dev, 
+					   usb_sndctrlpipe(serial->dev, 0),
+					   LOW)) < 0){
 				err("Urb to unset DTR failed");
 				return(ret);
 			}
 		}	
 		if (mask & TIOCM_RTS) {
-			if ((ret = usb_control_msg(serial->dev, 
-					       usb_sndctrlpipe(serial->dev, 0),
-					       FTDI_SIO_SET_MODEM_CTRL_REQUEST, 
-					       FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
-					    FTDI_SIO_SET_RTS_LOW , 0,
-					    buf, 0, WDR_TIMEOUT)) < 0){
+			if ((ret = set_rts(serial->dev, 
+					   usb_sndctrlpipe(serial->dev, 0),
+					   LOW)) < 0){
 				err("Urb to unset RTS failed");
 				return(ret);
 			}
@@ -690,25 +828,28 @@
 	  /* This is not an error - turns out the higher layers will do 
 	   *  some ioctls itself (see comment above)
  	   */
-		dbg("ftdi_sio ioctl arg not supported - it was 0x%04x",cmd);
+		dbg(__FUNCTION__ " arg not supported - it was 0x%04x",cmd);
 		return(-ENOIOCTLCMD);
 		break;
 	}
-	dbg("ftdi_sio_ioctl returning 0");
 	return 0;
 } /* ftdi_sio_ioctl */
 
 
 static int __init ftdi_sio_init (void)
 {
+	dbg(__FUNCTION__);
 	usb_serial_register (&ftdi_sio_device);
+	usb_serial_register (&ftdi_8U232AM_device);
 	return 0;
 }
 
 
 static void __exit ftdi_sio_exit (void)
 {
+	dbg(__FUNCTION__);
 	usb_serial_deregister (&ftdi_sio_device);
+	usb_serial_deregister (&ftdi_8U232AM_device);
 }
 
 
@@ -716,4 +857,4 @@
 module_exit(ftdi_sio_exit);
 
 MODULE_AUTHOR("Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>");
-MODULE_DESCRIPTION("USB FTDI SIO driver");
+MODULE_DESCRIPTION("USB FTDI RS232 converters driver");
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/ftdi_sio.h linux.19p18/drivers/usb/serial/ftdi_sio.h
--- linux.vanilla/drivers/usb/serial/ftdi_sio.h	Mon Dec 11 22:13:01 2000
+++ linux.19p18/drivers/usb/serial/ftdi_sio.h	Tue Jan  9 11:55:48 2001
@@ -20,9 +20,9 @@
  */
 
 #define FTDI_VID	0x0403	/* Vendor Id */
-#define FTDI_SIO_PID	0x8372	/* Product Id */
+#define FTDI_SIO_PID	0x8372	/* Product Id SIO application of 8U100AX  */
+#define FTDI_8U232AM_PID 0x6001 /* Similar device to SIO above */
 
-/* Vendor Request Interface */
 #define FTDI_SIO_RESET 		0 /* Reset the port */
 #define FTDI_SIO_MODEM_CTRL 	1 /* Set the modem control register */
 #define FTDI_SIO_SET_FLOW_CTRL	2 /* Set flow control register */
@@ -86,6 +86,12 @@
  */
 
 typedef enum {
+	sio = 1,
+	F8U232AM = 2,
+} ftdi_type_t;
+
+
+typedef enum {
  ftdi_sio_b300 = 0, 
  ftdi_sio_b600 = 1, 
  ftdi_sio_b1200 = 2,
@@ -97,6 +103,38 @@
  ftdi_sio_b57600 = 8,
  ftdi_sio_b115200 = 9
 } FTDI_SIO_baudrate_t ;
+
+
+typedef enum {
+  ftdi_8U232AM_12MHz_b300 = 0x09c4,
+  ftdi_8U232AM_12MHz_b600 = 0x04E2,
+  ftdi_8U232AM_12MHz_b1200 = 0x0271,
+  ftdi_8U232AM_12MHz_b2400 = 0x4138,
+  ftdi_8U232AM_12MHz_b4800 = 0x809c,
+  ftdi_8U232AM_12MHz_b9600 = 0xc04e,
+  ftdi_8U232AM_12MHz_b19200 = 0x0027,
+  ftdi_8U232AM_12MHz_b38400 = 0x4013,
+  ftdi_8U232AM_12MHz_b57600 = 0x000d,
+  ftdi_8U232AM_12MHz_b115200 = 0x4006,
+  ftdi_8U232AM_12MHz_b230400 = 0x8003,
+} FTDI_8U232AM_12MHz_baudrate_t;
+/* Apparently all devices are 48MHz */
+typedef enum {
+  ftdi_8U232AM_48MHz_b300 = 0x2710,
+  ftdi_8U232AM_48MHz_b600 = 0x1388,
+  ftdi_8U232AM_48MHz_b1200 = 0x09c4,
+  ftdi_8U232AM_48MHz_b2400 = 0x04e2,
+  ftdi_8U232AM_48MHz_b4800 = 0x0271,
+  ftdi_8U232AM_48MHz_b9600 = 0x4138,
+  ftdi_8U232AM_48MHz_b19200 = 0x809c,
+  ftdi_8U232AM_48MHz_b38400 = 0xc04e,
+  ftdi_8U232AM_48MHz_b57600 = 0x0034,
+  ftdi_8U232AM_48MHz_b115200 = 0x001a,
+  ftdi_8U232AM_48MHz_b230400 = 0x000d,
+  ftdi_8U232AM_48MHz_b460800 = 0x4006,
+  ftdi_8U232AM_48MHz_b921600 = 0x8003,
+
+} FTDI_8U232AM_48MHz_baudrate_t;
 
 #define FTDI_SIO_SET_DATA_REQUEST FTDI_SIO_SET_DATA
 #define FTDI_SIO_SET_DATA_REQUEST_TYPE 0x40
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/keyspan.c linux.19p18/drivers/usb/serial/keyspan.c
--- linux.vanilla/drivers/usb/serial/keyspan.c	Mon Dec 11 22:13:01 2000
+++ linux.19p18/drivers/usb/serial/keyspan.c	Sat Mar 10 23:08:19 2001
@@ -19,21 +19,33 @@
   and Keyspan, Inc the manufacturers of the Keyspan USB-serial products.
   Thanks Guys :)
   
+  Thanks to Paulus for miscellaneous tidy ups, some largish chunks
+  of much nicer and/or completely new code and (perhaps most uniquely)
+  having the patience to sit down and explain why and where he'd changed
+  stuff. 
+  
   Tip 'o the hat to Linuxcare for supporting staff in their work on
   open source projects.
 
-  Wed Jul 19 14:00:42 EST 2000 gkh
-	Added module_init and module_exit functions to handle the fact that this
-	driver is a loadable module now.
-
-  Tue Jul 18 16:14:52 EST 2000 Hugh
-    Basic character input/output for USA-19 now mostly works,
-    fixed at 9600 baud for the moment.
-
+  Change History
+    Tue Oct 10 23:15:33 EST 2000 Hugh
+      Merged Paul's changes with my USA-49W mods.  Work in progress
+      still...
+  
+    Wed Jul 19 14:00:42 EST 2000 gkh
+      Added module_init and module_exit functions to handle the fact that
+      this driver is a loadable module now.
+ 
+    Tue Jul 18 16:14:52 EST 2000 Hugh
+      Basic character input/output for USA-19 now mostly works,
+      fixed at 9600 baud for the moment.
+
+    Sat Jul  8 11:11:48 EST 2000 Hugh
+      First public release - nothing works except the firmware upload.
+      Tested on PPC and x86 architectures, seems to behave...
 */
 
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
@@ -42,59 +54,136 @@
 #include <linux/init.h>
 #include <linux/malloc.h>
 #include <linux/fcntl.h>
+#include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
-#include <linux/tty.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
 
-#ifdef CONFIG_USB_SERIAL_DEBUG
+#define DEBUG
+/*  #ifdef CONFIG_USB_SERIAL_DEBUG */
 	#define DEBUG
-#else
-	#undef DEBUG
-#endif
+/*  #endif */
 #include <linux/usb.h>
 
 #include "usb-serial.h"
 #include "keyspan.h"
 
+#define INSTAT_BUFLEN	32
+#define GLOCONT_BUFLEN	64
+
 	/* Per device and per port private data */
 struct keyspan_serial_private {
-	struct urb	*in_urbs[8];
-	struct urb	*out_urbs[8];
-	char		out_buffer[64];
-	char		in_buffer[64];
+	/* number of active ports */
+	atomic_t	active_count;
+
+	const keyspan_device_details	*device_details;
+
+	urb_t		*instat_urb;
+	char		instat_buf[INSTAT_BUFLEN];
+
+	/* XXX this one probably will need a lock */
+	urb_t		*glocont_urb;
+	char		glocont_buf[GLOCONT_BUFLEN];
 };
 
 struct keyspan_port_private {
- 		/* Keep track of which output endpoint to use */
+	/* Keep track of which input & output endpoints to use */
+	int		in_flip;
 	int		out_flip;
 
-		/* Settings for the port */
+	/* Keep duplicate of device details in each port
+	   structure as well - simplifies some of the
+	   callback functions etc. */
+	const keyspan_device_details	*device_details;
+
+	/* Input endpoints and buffer for this port */
+	urb_t		*in_urbs[2];
+	char		in_buffer[2][64];
+	/* Output endpoints and buffer for this port */
+	urb_t		*out_urbs[2];
+	char		out_buffer[2][64];
+
+	/* Input ack endpoint */
+	urb_t		*inack_urb;
+	char		inack_buffer[1];
+
+	/* Output control endpoint */
+	urb_t		*outcont_urb;
+	char		outcont_buffer[64];
+
+	/* Settings for the port */
 	int		baud;
 	int		old_baud;
-	enum		{parity_none, parity_odd, parity_even} parity;
+	unsigned int	cflag;
 	enum		{flow_none, flow_cts, flow_xon} flow_control;
-	int		rts_state;
+	int		rts_state;	/* Handshaking pins (outputs) */
 	int		dtr_state;
+	int		cts_state;	/* Handshaking pins (inputs) */
+	int		dsr_state;
+	int		dcd_state;
+	int		ri_state;
 
+	unsigned long	tx_start_time[2];
+	int		resend_cont;	/* need to resend control packet */
 };
 
-
-	/* FIXME this will break if multiple physical interfaces used */
-static wait_queue_head_t	out_wait;
 	
-	/* Include Keyspan message headers (not both yet, need some tweaks
-	   to get clean build) */
-/*#include "keyspan_usa26msg.h"*/
+/* Include Keyspan message headers.  All current Keyspan Adapters
+   make use of one of three message formats which are referred
+   to as USA-26, USA-28 and USA-49 by Keyspan and within this driver. */
+#include "keyspan_usa26msg.h"
 #include "keyspan_usa28msg.h"
+#include "keyspan_usa49msg.h"
 	
-	/* If you don't get debugging output, uncomment the following
-	   two lines to enable cheat. */
-#undef 	dbg
-#define	dbg	printk
+/* If you don't get debugging output, uncomment the following
+   two lines to enable cheat. */
+#if 0
+  #undef 	dbg 
+  #define	dbg	printk 
+#endif
+
+static void keyspan_send_setup(struct usb_serial_port *port);
+
+/* Functions used by new usb-serial code. */
+int keyspan_init (void)
+{
+	usb_serial_register (&keyspan_usa18x_pre_device);
+	usb_serial_register (&keyspan_usa19_pre_device);
+	usb_serial_register (&keyspan_usa19w_pre_device);
+	usb_serial_register (&keyspan_usa28_pre_device);
+	usb_serial_register (&keyspan_usa28x_pre_device);
+	usb_serial_register (&keyspan_usa49w_pre_device);
+
+	usb_serial_register (&keyspan_usa18x_device);
+	usb_serial_register (&keyspan_usa19_device);
+	usb_serial_register (&keyspan_usa19w_device);
+	usb_serial_register (&keyspan_usa28_device);
+	usb_serial_register (&keyspan_usa28x_device);
+	usb_serial_register (&keyspan_usa49w_device);
+	return 0;
+}
+
+void keyspan_exit (void)
+{
+	usb_serial_deregister (&keyspan_usa18x_pre_device);
+	usb_serial_deregister (&keyspan_usa19_pre_device);
+	usb_serial_deregister (&keyspan_usa19w_pre_device);
+	usb_serial_deregister (&keyspan_usa28_pre_device);
+	usb_serial_deregister (&keyspan_usa28x_pre_device);
+	usb_serial_deregister (&keyspan_usa49w_pre_device);
+
+	usb_serial_deregister (&keyspan_usa18x_device);
+	usb_serial_deregister (&keyspan_usa19_device);
+	usb_serial_deregister (&keyspan_usa19w_device);
+	usb_serial_deregister (&keyspan_usa28_device);
+	usb_serial_deregister (&keyspan_usa28x_device);
+	usb_serial_deregister (&keyspan_usa49w_device);
+}
+
+module_init(keyspan_init);
+module_exit(keyspan_exit);
 
-	/* Functions - mostly stubs for now */
 static void keyspan_rx_throttle (struct usb_serial_port *port)
 {
 	dbg("keyspan_rx_throttle port %d", port->number);
@@ -116,180 +205,597 @@
 static void keyspan_set_termios (struct usb_serial_port *port, 
 				     struct termios *old_termios)
 {
-	dbg("keyspan_set_termios");
+	int				baud_rate;
+	struct keyspan_port_private 	*p_priv;
+	const keyspan_device_details	*d_details;
+	unsigned int 			cflag;
+
+	/*  dbg(__FUNCTION__ "."); */
+
+	p_priv = (struct keyspan_port_private *)(port->private);
+	d_details = p_priv->device_details;
+	cflag = port->tty->termios->c_cflag;
+
+	/* Baud rate calculation takes baud rate as an integer
+	   so other rates can be generated if desired. */
+	baud_rate = tty_get_baud_rate(port->tty);
+	/* If no match or invalid, don't change */		
+	if (baud_rate >= 0
+	    && d_details->calculate_baud_rate(baud_rate, d_details->baudclk,
+				NULL, NULL, NULL) == KEYSPAN_BAUD_RATE_OK) {
+		/* FIXME - more to do here to ensure rate changes cleanly */
+		p_priv->baud = baud_rate;
+	}
+
+	/* set CTS/RTS handshake etc. */
+	p_priv->cflag = cflag;
+	p_priv->flow_control = (cflag & CRTSCTS)? flow_cts: flow_none;
+
+	keyspan_send_setup(port);
 }
 
 static int keyspan_ioctl(struct usb_serial_port *port, struct file *file,
 			     unsigned int cmd, unsigned long arg)
 {
-	unsigned int		value;
+	unsigned int			value, set;
+	struct keyspan_port_private 	*p_priv;
 
-	dbg("keyspan_ioctl_info");
+	p_priv = (struct keyspan_port_private *)(port->private);
 	
 	switch (cmd) {
 	case TIOCMGET:
-		value = TIOCM_DTR | TIOCM_RNG;
-		if (copy_to_user((unsigned int *)arg, &value, sizeof(int))) {
+		value = ((p_priv->rts_state) ? TIOCM_RTS : 0) |
+			((p_priv->dtr_state) ? TIOCM_DTR : 0) |
+			((p_priv->cts_state) ? TIOCM_CTS : 0) |
+			((p_priv->dsr_state) ? TIOCM_DSR : 0) |
+			((p_priv->dcd_state) ? TIOCM_CAR : 0) |
+			((p_priv->ri_state) ? TIOCM_RNG : 0); 
+
+		if (put_user(value, (unsigned int *) arg))
 			return -EFAULT;
-		}
-		else {
-			return 0;
-		}
-		
-	default:
-		return -ENOIOCTLCMD;
+		return 0;
+	
+	case TIOCMSET:
+		if (get_user(value, (unsigned int *) arg))
+			return -EFAULT;
+		p_priv->rts_state = ((value & TIOCM_RTS) ? 1 : 0);
+		p_priv->dtr_state = ((value & TIOCM_DTR) ? 1 : 0);
+		keyspan_send_setup(port);
+		return 0;
+
+	case TIOCMBIS:
+	case TIOCMBIC:
+		if (get_user(value, (unsigned int *) arg))
+			return -EFAULT;
+		set = (cmd == TIOCMBIS);
+		if (value & TIOCM_RTS)
+			p_priv->rts_state = set;
+		if (value & TIOCM_DTR)
+			p_priv->dtr_state = set;
+		keyspan_send_setup(port);
+		return 0;
 	}
 
 	return -ENOIOCTLCMD;
 }
 
+	/* Write function is generic for the three protocols used
+	   with only a minor change for usa49 required */
 static int keyspan_write(struct usb_serial_port *port, int from_user, 
-			     const unsigned char *buf, int count)
+			 const unsigned char *buf, int count)
 {
-	struct usb_serial 		*serial = port->serial;
-	struct keyspan_serial_private 	*s_priv;
 	struct keyspan_port_private 	*p_priv;
-	int				current_urb;
-	int				i;
+	const keyspan_device_details	*d_details;
+	int				flip;
+	int left, todo;
+	urb_t *this_urb;
+	int err;
 
-	s_priv = (struct keyspan_serial_private *)(serial->private);
 	p_priv = (struct keyspan_port_private *)(port->private);
-	
-	if (p_priv->out_flip == 0) {
-		current_urb = 0;
-		p_priv->out_flip = 1;
+	d_details = p_priv->device_details;
+
+#if 0
+	dbg(__FUNCTION__ " for port %d (%d chars [%x]), flip=%d",
+	    port->number, count, buf[0], p_priv->out_flip);
+#endif
+
+	for (left = count; left > 0; left -= todo) {
+		todo = left;
+		if (todo > 63)
+			todo = 63;
+
+		flip = p_priv->out_flip;
+	
+		/* Check we have a valid urb/endpoint before we use it... */
+		if ((this_urb = p_priv->out_urbs[flip]) == 0) {
+			/* no bulk out, so return 0 bytes written */
+			dbg(__FUNCTION__ " no output urb :(");
+			return count;
+		}
+
+		if (this_urb->status == -EINPROGRESS) {
+			if (this_urb->transfer_flags & USB_ASYNC_UNLINK)
+				break;
+			if (jiffies - p_priv->tx_start_time[flip] < 10 * HZ)
+				break;
+			this_urb->transfer_flags |= USB_ASYNC_UNLINK;
+			usb_unlink_urb(this_urb);
+			break;
+		}
+
+		/* First byte in buffer is "last flag" - unused so
+		   for now so set to zero */
+		((char *)this_urb->transfer_buffer)[0] = 0;
+
+		if (from_user) {
+			copy_from_user(this_urb->transfer_buffer + 1, buf, todo);
+		} else {
+			memcpy (this_urb->transfer_buffer + 1, buf, todo);
+		}
+		buf += todo;
+
+		/* send the data out the bulk port */
+		this_urb->transfer_buffer_length = todo + 1;
+
+		this_urb->transfer_flags &= ~USB_ASYNC_UNLINK;
+		this_urb->dev = port->serial->dev;
+		if ((err = usb_submit_urb(this_urb)) != 0) {
+			dbg("usb_submit_urb(write bulk) failed (%d)", err);
+		}
+		p_priv->tx_start_time[flip] = jiffies;
+
+		/* Flip for next time if usa26 or usa28 interface
+		   (not used on usa49) */
+		p_priv->out_flip = (flip + 1) & d_details->outdat_endp_flip;
 	}
-	else {
-		current_urb = 1;
-		p_priv->out_flip = 0;
+
+	return count - left;
+}
+
+static void	usa26_indat_callback(struct urb *urb)
+{
+	int			i, err;
+	int			endpoint;
+	struct usb_serial_port	*port;
+	struct tty_struct	*tty;
+	unsigned char 		*data = urb->transfer_buffer;
+
+	/*  dbg (__FUNCTION__); */
+
+	endpoint = usb_pipeendpoint(urb->pipe);
+
+	if (urb->status) {
+		dbg(__FUNCTION__ "nonzero status: %x on endpoint %d.",
+			      		urb->status, endpoint);
+		return;
+	}
+
+	port = (struct usb_serial_port *) urb->context;
+	tty = port->tty;
+	if (urb->actual_length) {
+		if (data[0] == 0) {
+			/* no error on any byte */
+			for (i = 1; i < urb->actual_length ; ++i) {
+				tty_insert_flip_char(tty, data[i], 0);
+			}
+		} else {
+			/* some bytes had errors, every byte has status */
+			for (i = 0; i + 1 < urb->actual_length; i += 2) {
+				int stat = data[i], flag = 0;
+				if (stat & RXERROR_OVERRUN)
+					flag |= TTY_OVERRUN;
+				if (stat & RXERROR_FRAMING)
+					flag |= TTY_FRAME;
+				if (stat & RXERROR_PARITY)
+					flag |= TTY_PARITY;
+				/* XXX should handle break (0x10) */
+				tty_insert_flip_char(tty, data[i+1], flag);
+			}
+		}
+		tty_flip_buffer_push(tty);
+	}
+				
+		/* Resubmit urb so we continue receiving */
+	urb->dev = port->serial->dev;
+	if ((err = usb_submit_urb(urb)) != 0) {
+		dbg(__FUNCTION__ "resubmit read urb failed. (%d)", err);
+	}
+	return;
+}
+
+	/* Outdat handling is common for usa26, usa28 and usa49 messages */
+static void	usa2x_outdat_callback(struct urb *urb)
+{
+	struct usb_serial_port *port;
+	struct keyspan_port_private *p_priv;
+
+	port = (struct usb_serial_port *) urb->context;
+	p_priv = (struct keyspan_port_private *)(port->private);
+	/*  dbg (__FUNCTION__ " urb %d", urb == p_priv->out_urbs[1]); */
+
+	if (port->active) {
+		queue_task(&port->tqueue, &tq_immediate);
+		mark_bh(IMMEDIATE_BH);
+	}
+}
+
+static void	usa26_inack_callback(struct urb *urb)
+{
+	dbg (__FUNCTION__);
+	
+}
+
+static void	usa26_outcont_callback(struct urb *urb)
+{
+	struct usb_serial_port *port;
+	struct keyspan_port_private *p_priv;
+
+	port = (struct usb_serial_port *) urb->context;
+	p_priv = (struct keyspan_port_private *)(port->private);
+
+	if (p_priv->resend_cont) {
+		/*  dbg (__FUNCTION__ " sending setup"); */
+		keyspan_usa26_send_setup(port->serial, port);
 	}
+}
 
-	dbg("keyspan_write called for port %d (%d) chars {", port->number, count);
-	for (i = 0; i < count ; i++) {
-		dbg("%02x ", buf[i]);
+static void	usa26_instat_callback(struct urb *urb)
+{
+	unsigned char 				*data = urb->transfer_buffer;
+	keyspan_usa26_portStatusMessage		*msg;
+	struct usb_serial			*serial;
+	struct usb_serial_port			*port;
+	struct keyspan_port_private	 	*p_priv;
+	int old_dcd_state, err;
+
+	serial = (struct usb_serial *) urb->context;
+
+	if (urb->status) {
+		dbg(__FUNCTION__ " nonzero status: %x", urb->status);
+		return;
+	}
+	if (urb->actual_length != 9) {
+		dbg(__FUNCTION__ " %d byte report??", urb->actual_length);
+		goto exit;
 	}
-	dbg("}\n");
 
-	if (count == 0) {
-		dbg("write request of 0 bytes");
-		return (0);
+	msg = (keyspan_usa26_portStatusMessage *)data;
+
+#if 0
+	dbg(__FUNCTION__ " port status: port %d cts %d dcd %d dsr %d ri %d toff %d txoff %d rxen %d cr %d",
+	    msg->port, msg->hskia_cts, msg->gpia_dcd, msg->dsr, msg->ri, msg->_txOff,
+	    msg->_txXoff, msg->rxEnabled, msg->controlResponse);
+#endif
+
+	/* Now do something useful with the data */
+
+
+	/* Check port number from message and retrieve private data */	
+	if (msg->port >= serial->num_ports) {
+		dbg ("Unexpected port number %d", msg->port);
+		goto exit;
 	}
+	port = &serial->port[msg->port];
+	p_priv = (struct keyspan_port_private *)(port->private);
+	
+	/* Update handshaking pin state information */
+	old_dcd_state = p_priv->dcd_state;
+	p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
+	p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
+	p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
+	p_priv->ri_state = ((msg->ri) ? 1 : 0);
+
+	if (port->tty && !C_CLOCAL(port->tty)
+	    && old_dcd_state != p_priv->dcd_state) {
+		if (old_dcd_state)
+			tty_hangup(port->tty);
+		/*  else */
+		/*	wake_up_interruptible(&p_priv->open_wait); */
+	}
+	
+exit:
+	/* Resubmit urb so we continue receiving */
+	urb->dev = serial->dev;
+	if ((err = usb_submit_urb(urb)) != 0) {
+		dbg(__FUNCTION__ "resubmit read urb failed. (%d)", err);
+	}
+}
+
+static void	usa26_glocont_callback(struct urb *urb)
+{
+	dbg (__FUNCTION__);
+	
+}
+
+
+static void     usa28_indat_callback(struct urb *urb)
+{
+	int                     i, err;
+	struct usb_serial_port  *port;
+	struct tty_struct       *tty;
+	unsigned char           *data;
+	struct keyspan_port_private             *p_priv;
+
+	/*  dbg (__FUNCTION__); */
+
+	port = (struct usb_serial_port *) urb->context;
+	p_priv = (struct keyspan_port_private *)(port->private);
+	data = urb->transfer_buffer;
+
+	if (urb != p_priv->in_urbs[p_priv->in_flip])
+		return;
 
-		/* only send data if we have a bulk out endpoint */
-	if (s_priv->out_urbs[current_urb]) {
-		while (s_priv->out_urbs[current_urb]->status == -EINPROGRESS) {
-			dbg (__FUNCTION__ " INPROGRES\n");
-			interruptible_sleep_on(&out_wait);
-			if (signal_pending(current)) {
-				dbg (__FUNCTION__ " signal\n");
-				return (-ERESTARTSYS);
+	do {
+		if (urb->status) {
+			dbg(__FUNCTION__ "nonzero status: %x on endpoint
+%d.",
+			    urb->status, usb_pipeendpoint(urb->pipe));
+			return;
+		}
+
+		port = (struct usb_serial_port *) urb->context;
+		p_priv = (struct keyspan_port_private *)(port->private);
+		data = urb->transfer_buffer;
+
+		tty = port->tty;
+		if (urb->actual_length) {
+			for (i = 0; i < urb->actual_length ; ++i) {
+				tty_insert_flip_char(tty, data[i], 0);
 			}
+			tty_flip_buffer_push(tty);
 		}
-		/*if (s_priv->out_urbs[current_urb]->status == -EINPROGRESS) {
-			dbg ("already writing");
-			return (-EAGAIN);
-		}*/
-			/* First byte in buffer is "last flag" - unused so
-			   for now so set to zero */
-		memset(s_priv->out_urbs[current_urb]->transfer_buffer, 0, 1);
 
-		if (from_user) {
-			copy_from_user(s_priv->out_urbs[current_urb]->transfer_buffer + 1, buf, count);
+		/* Resubmit urb so we continue receiving */
+		urb->dev = port->serial->dev;
+		if ((err = usb_submit_urb(urb)) != 0) {
+			dbg(__FUNCTION__ "resubmit read urb failed. (%d)",
+err);
 		}
-		else {
-			memcpy (s_priv->out_urbs[current_urb]->transfer_buffer + 1, buf, count);
-		}  
+		p_priv->in_flip ^= 1;
 
-		/* send the data out the bulk port */
-		s_priv->out_urbs[current_urb]->transfer_buffer_length = count + 1;
+		urb = p_priv->in_urbs[p_priv->in_flip];
+	} while (urb->status != -EINPROGRESS);
+}
 
-		if (usb_submit_urb(s_priv->out_urbs[current_urb])) {
-			dbg("usb_submit_urb(write bulk) failed");
-		}
+static void	usa28_inack_callback(struct urb *urb)
+{
+	dbg (__FUNCTION__);
+}
+
+static void	usa28_outcont_callback(struct urb *urb)
+{
+	struct usb_serial_port *port;
+	struct keyspan_port_private *p_priv;
 
-		return (count);
+	port = (struct usb_serial_port *) urb->context;
+	p_priv = (struct keyspan_port_private *)(port->private);
+
+	if (p_priv->resend_cont) {
+		dbg (__FUNCTION__ " sending setup");
+		keyspan_usa28_send_setup(port->serial, port);
 	}
+}
+
+static void	usa28_instat_callback(struct urb *urb)
+{
+	int					err;
+	unsigned char 				*data = urb->transfer_buffer;
+	keyspan_usa28_portStatusMessage		*msg;
+	struct usb_serial			*serial;
+	struct usb_serial_port			*port;
+	struct keyspan_port_private	 	*p_priv;
+	int old_dcd_state;
+
+	serial = (struct usb_serial *) urb->context;
+
+	if (urb->status) {
+		dbg(__FUNCTION__ " nonzero status: %x", urb->status);
+		return;
+	}
+
+	if (urb->actual_length != sizeof(struct keyspan_usa28_portStatusMessage)) {
+		dbg(__FUNCTION__ " bad length %d", urb->actual_length);
+		goto exit;
+	}
+
+	/*dbg(__FUNCTION__ " %x %x %x %x %x %x %x %x %x %x %x %x",
+	    data[0], data[1], data[2], data[3], data[4], data[5],
+	    data[6], data[7], data[8], data[9], data[10], data[11]);*/
 	
-	/* no bulk out, so return 0 bytes written */
-	return (0);
+		/* Now do something useful with the data */
+	msg = (keyspan_usa28_portStatusMessage *)data;
+
+
+		/* Check port number from message and retrieve private data */	
+	if (msg->port >= serial->num_ports) {
+		dbg ("Unexpected port number %d", msg->port);
+		goto exit;
+	}
+	port = &serial->port[msg->port];
+	p_priv = (struct keyspan_port_private *)(port->private);
+	
+	/* Update handshaking pin state information */
+	old_dcd_state = p_priv->dcd_state;
+	p_priv->cts_state = ((msg->cts) ? 1 : 0);
+	p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
+	p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
+	p_priv->ri_state = ((msg->ri) ? 1 : 0);
+
+	if (port->tty && !C_CLOCAL(port->tty)
+	    && old_dcd_state != p_priv->dcd_state) {
+		if (old_dcd_state)
+			tty_hangup(port->tty);
+		/*  else */
+		/*	wake_up_interruptible(&p_priv->open_wait); */
+	}
+
+exit:	
+		/* Resubmit urb so we continue receiving */
+	urb->dev = serial->dev;
+	if ((err = usb_submit_urb(urb)) != 0) {
+		dbg(__FUNCTION__ "resubmit read urb failed. (%d)", err);
+	}
 }
 
+static void	usa28_glocont_callback(struct urb *urb)
+{
+	dbg (__FUNCTION__);
+}
 
-static void keyspan_write_bulk_callback (struct urb *urb)
+
+static void	usa49_glocont_callback(struct urb *urb)
 {
-	int		endpoint;
-	
-	endpoint = usb_pipeendpoint(urb->pipe);
+	struct usb_serial *serial;
+	struct usb_serial_port *port;
+	struct keyspan_port_private *p_priv;
+	int i;
+
+	/*  dbg (__FUNCTION__); */
+
+	serial = (struct usb_serial *) urb->context;
+	for (i = 0; i < serial->num_ports; ++i) {
+		port = &serial->port[i];
+		p_priv = (struct keyspan_port_private *)(port->private);
 
-	dbg("keyspan_write_bulk_callback for endpoint %d\n", endpoint);
+		if (p_priv->resend_cont) {
+			/*  dbg (__FUNCTION__ " sending setup"); */
+			keyspan_usa49_send_setup(serial, port);
+			break;
+		}
+	}
+}
 
-		/* Only do wakeup if this callback is from one of the data
-		   endpoints.  */
-	if (endpoint == 2 || endpoint == 3) {
-		wake_up_interruptible(&out_wait);
+	/* This is actually called glostat in the Keyspan
+	   doco */
+static void	usa49_instat_callback(struct urb *urb)
+{
+	int					err;
+	unsigned char 				*data = urb->transfer_buffer;
+	keyspan_usa49_portStatusMessage		*msg;
+	struct usb_serial			*serial;
+	struct usb_serial_port			*port;
+	struct keyspan_port_private	 	*p_priv;
+	int old_dcd_state;
+
+	/*  dbg (__FUNCTION__); */
+
+	serial = (struct usb_serial *) urb->context;
+
+	if (urb->status) {
+		dbg(__FUNCTION__ " nonzero status: %x", urb->status);
+		return;
+	}
+
+	if (urb->actual_length != sizeof(struct keyspan_usa49_portStatusMessage)) {
+		dbg(__FUNCTION__ " bad length %d", urb->actual_length);
+		goto exit;
+	}
+
+	/*dbg(__FUNCTION__ " %x %x %x %x %x %x %x %x %x %x %x",
+	    data[0], data[1], data[2], data[3], data[4], data[5],
+	    data[6], data[7], data[8], data[9], data[10]);*/
+	
+		/* Now do something useful with the data */
+	msg = (keyspan_usa49_portStatusMessage *)data;
+
+		/* Check port number from message and retrieve private data */	
+	if (msg->portNumber >= serial->num_ports) {
+		dbg ("Unexpected port number %d", msg->portNumber);
+		goto exit;
+	}
+	port = &serial->port[msg->portNumber];
+	p_priv = (struct keyspan_port_private *)(port->private);
+	
+	/* Update handshaking pin state information */
+	old_dcd_state = p_priv->dcd_state;
+	p_priv->cts_state = ((msg->cts) ? 1 : 0);
+	p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
+	p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
+	p_priv->ri_state = ((msg->ri) ? 1 : 0);
+
+	if (port->tty && !C_CLOCAL(port->tty)
+	    && old_dcd_state != p_priv->dcd_state) {
+		if (old_dcd_state)
+			tty_hangup(port->tty);
+		/*  else */
+		/*	wake_up_interruptible(&p_priv->open_wait); */
 	}
 
+exit:	
+		/* Resubmit urb so we continue receiving */
+	urb->dev = serial->dev;
+
+	if ((err = usb_submit_urb(urb)) != 0) {
+		dbg(__FUNCTION__ "resubmit read urb failed. (%d)", err);
+	}
 }
 
+static void	usa49_inack_callback(struct urb *urb)
+{
+	dbg (__FUNCTION__);
+}
 
-static void keyspan_read_bulk_callback (struct urb *urb)
+static void	usa49_indat_callback(struct urb *urb)
 {
-	int			i;
+	int			i, err;
 	int			endpoint;
-	struct usb_serial	*serial;
 	struct usb_serial_port	*port;
 	struct tty_struct	*tty;
 	unsigned char 		*data = urb->transfer_buffer;
 
-	endpoint = usb_pipeendpoint(urb->pipe);
+	/*  dbg (__FUNCTION__); */
 
+	endpoint = usb_pipeendpoint(urb->pipe);
 
 	if (urb->status) {
-		dbg(__FUNCTION__ "nonzero status: %x on endpoint %d.\n",
+		dbg(__FUNCTION__ "nonzero status: %x on endpoint %d.",
 			      		urb->status, endpoint);
 		return;
 	}
 
-	switch (endpoint) {
-
-			/* If this is one of the data endpoints, stuff it's
-		   	   contents into the tty flip_buffer. */
-		case 1:
-		case 2: serial = (struct usb_serial *) urb->context;
-			port = &serial->port[0];
-			tty = port->tty;
-			if (urb->actual_length) {
-				for (i = 0; i < urb->actual_length ; ++i) {
-					 tty_insert_flip_char(tty, data[i], 0);
-				}
-				tty_flip_buffer_push(tty);
+	port = (struct usb_serial_port *) urb->context;
+	tty = port->tty;
+	if (urb->actual_length) {
+		if (data[0] == 0) {
+			/* no error on any byte */
+			for (i = 1; i < urb->actual_length ; ++i) {
+				tty_insert_flip_char(tty, data[i], 0);
 			}
-			break;
-
-			/* INACK endpoint */	
-		case 3: dbg(__FUNCTION__ " callback for INACK endpoint\n");
-			break;
-
-			/* INSTAT endpoint */
-		case 4: dbg(__FUNCTION__ " callback for INSTAT endpoint\n");
-			break;
-		
-		default:
-		       	dbg(__FUNCTION__ " callback for unknown endpoint!\n");
-			break;
+		} else {
+			/* some bytes had errors, every byte has status */
+			for (i = 0; i + 1 < urb->actual_length; i += 2) {
+				int stat = data[i], flag = 0;
+				if (stat & RXERROR_OVERRUN)
+					flag |= TTY_OVERRUN;
+				if (stat & RXERROR_FRAMING)
+					flag |= TTY_FRAME;
+				if (stat & RXERROR_PARITY)
+					flag |= TTY_PARITY;
+				/* XXX should handle break (0x10) */
+				tty_insert_flip_char(tty, data[i+1], flag);
+			}
+		}
+		tty_flip_buffer_push(tty);
 	}
 				
 		/* Resubmit urb so we continue receiving */
-	if (usb_submit_urb(urb)) {
-		dbg(__FUNCTION__ "resubmit read urb failed.\n");
+	urb->dev = port->serial->dev;
+	if ((err = usb_submit_urb(urb)) != 0) {
+		dbg(__FUNCTION__ "resubmit read urb failed. (%d)", err);
 	}
-	return;
-	
 }
 
+/* not used, usa-49 doesn't have per-port control endpoints */
+static void	usa49_outcont_callback(struct urb *urb)
+{
+	dbg (__FUNCTION__);
+}
+
+
+
 static int keyspan_write_room (struct usb_serial_port *port)
 {
-//	dbg("keyspan_write_room called\n");
+//	dbg("keyspan_write_room called");
 	return (32);
 
 }
@@ -306,62 +812,92 @@
 	struct keyspan_port_private 	*p_priv;
 	struct keyspan_serial_private 	*s_priv;
 	struct usb_serial 		*serial = port->serial;
-	int				i;
+	const keyspan_device_details	*d_details;
+	int				i, already_active, err;
+	unsigned long flags;
+	urb_t *urb;
 
 	s_priv = (struct keyspan_serial_private *)(serial->private);
 	p_priv = (struct keyspan_port_private *)(port->private);
+	d_details = s_priv->device_details;
 	
-	dbg("keyspan_open called.\n");
-	
-	if (port->active) {
-		dbg(__FUNCTION__ "port->active already true!\n");
-		return (-EINVAL);
-	}
+	/*  dbg("keyspan_open called."); */
+	MOD_INC_USE_COUNT;
 
-	p_priv = (struct keyspan_port_private *)(port->private);
-	
-	p_priv->out_flip = 0;
+	spin_lock_irqsave (&port->port_lock, flags);
+	++port->open_count;
+	already_active = port->active;
 	port->active = 1;
+	spin_unlock_irqrestore (&port->port_lock, flags);
 
-		/* Start reading from port */
-	for (i = 0; i < 4; i++) {
-		if (s_priv->in_urbs[i]) {
-			if (usb_submit_urb(s_priv->in_urbs[i])) {
-				dbg(__FUNCTION__ " submit in urb %d failed", i);
-			}
-		}
+	if (already_active)
+		return 0;
+
+	p_priv = (struct keyspan_port_private *)(port->private);
 
+	/* Set some sane defaults */
+	p_priv->rts_state = 1;
+	p_priv->dtr_state = 1;
+
+	/* Start reading from endpoints */
+	for (i = 0; i < 2; i++) {
+		if ((urb = p_priv->in_urbs[i]) == NULL)
+			continue;
+		urb->dev = serial->dev;
+		if ((err = usb_submit_urb(urb)) != 0) {
+			dbg(__FUNCTION__ " submit urb %d failed (%d)", i, err);
+		}
 	}
-	
-	keyspan_usa19_send_setup(serial, port);
+
+	keyspan_set_termios(port, NULL);
 
 	return (0);
 }
 
+static inline void stop_urb(urb_t *urb)
+{
+	if (urb && urb->status == -EINPROGRESS) {
+		urb->transfer_flags &= ~USB_ASYNC_UNLINK;
+		usb_unlink_urb(urb);
+	}
+}
 
 static void keyspan_close(struct usb_serial_port *port, struct file *filp)
 {
 	int			i;
 	struct usb_serial	*serial = port->serial; /* FIXME should so sanity check */
 	struct keyspan_serial_private 	*s_priv;
+	struct keyspan_port_private 	*p_priv;
+	unsigned long flags;
 
+	/*  dbg("keyspan_close called"); */
 	s_priv = (struct keyspan_serial_private *)(serial->private);
-	
-		/* Stop reading/writing urbs */
-	for (i = 0; i < 4; i++) {
-		if (s_priv->in_urbs[i]) {
-			usb_unlink_urb(s_priv->in_urbs[i]);
-		}
+	p_priv = (struct keyspan_port_private *)(port->private);
 
-	}
-	for (i = 0; i < 3; i++) {
-		if (s_priv->out_urbs[i]) {
-			usb_unlink_urb(s_priv->out_urbs[i]);
-		}
+	spin_lock_irqsave (&port->port_lock, flags);
 
+	if (--port->open_count <= 0) {
+		if (port->active) {
+			/* Stop reading/writing urbs */
+			stop_urb(p_priv->inack_urb);
+			stop_urb(p_priv->outcont_urb);
+			for (i = 0; i < 2; i++) {
+				stop_urb(p_priv->in_urbs[i]);
+				stop_urb(p_priv->out_urbs[i]);
+			}
+			/* Now done in shutdown 
+			if (atomic_dec_return(&s_priv->active_count) <= 0) {
+				stop_urb(s_priv->instat_urb);
+				stop_urb(s_priv->glocont_urb);
+			} */
+		}
+		port->active = 0;
+		port->open_count = 0;
+		port->tty = 0;
 	}
-	port->active = 0;
-	dbg("keyspan_close called\n");
+	spin_unlock_irqrestore (&port->port_lock, flags);
+
+	MOD_DEC_USE_COUNT;
 }
 
 
@@ -372,47 +908,59 @@
 	const struct ezusb_hex_record 	*record;
 	char				*fw_name;
 
-	dbg("Keyspan startup version %04x product %04x\n", serial->dev->descriptor.bcdDevice,
-		       					serial->dev->descriptor.idProduct); 
+	dbg("Keyspan startup version %04x product %04x",
+	    serial->dev->descriptor.bcdDevice,
+	    serial->dev->descriptor.idProduct); 
 	
 	if ((serial->dev->descriptor.bcdDevice & 0x8000) != 0x8000) {
-		dbg("Firmware already loaded.  Quitting.\n");
+		dbg("Firmware already loaded.  Quitting.");
 		return(1);
 	}
 
 		/* Select firmware image on the basis of idProduct */
 	switch (serial->dev->descriptor.idProduct) {
-		case 0x0101: record = &keyspan_usa28_firmware[0];
-			     fw_name = "USA28";
-			     break;
-			     
-		case 0x0102: record = &keyspan_usa28x_firmware[0];
-			     fw_name = "USA28X";
-			     break;
-
-		case 0x0103: record = &keyspan_usa19_firmware[0];
-			     fw_name = "USA19";
-			     break;
+	case 0x0101:
+		record = &keyspan_usa28_firmware[0];
+		fw_name = "USA28";
+		break;
+
+	case 0x0102:
+		record = &keyspan_usa28x_firmware[0];
+		fw_name = "USA28X";
+		break;
+
+	case 0x0103:
+		record = &keyspan_usa19_firmware[0];
+		fw_name = "USA19";
+		break;
 			     
-		case 0x0105: record = &keyspan_usa18x_firmware[0];
-			     fw_name = "USA18X";
-			     break;
+	case 0x0105:
+		record = &keyspan_usa18x_firmware[0];
+		fw_name = "USA18X";
+		break;
 			     
-		case 0x0106: record = &keyspan_usa19w_firmware[0];
-			     fw_name = "USA19W";
-			     break;
+	case 0x0106:
+		record = &keyspan_usa19w_firmware[0];
+		fw_name = "USA19W";
+		break;
 		
-		default:     record = NULL;
-			     fw_name = "Unknown";
-			     break;
+	case 0x0109:
+		record = &keyspan_usa49w_firmware[0];
+		fw_name = "USA49W";
+		break;
+
+	default:
+		record = NULL;
+		fw_name = "Unknown";
+		break;
 	}
 
 	if (record == NULL) {
-		err("Required keyspan firmware image (%s) unavailable.\n", fw_name);
+		err("Required keyspan firmware image (%s) unavailable.", fw_name);
 		return(1);
 	}
 
-	dbg("Uploading Keyspan %s firmware.\n", fw_name);
+	dbg("Uploading Keyspan %s firmware.", fw_name);
 
 		/* download the firmware image */
 	response = ezusb_set_reset(serial, 1);
@@ -434,72 +982,165 @@
 		   moment and the new device will bind to the real driver */
 	response = ezusb_set_reset(serial, 0);
 
-		/* we don't want this device to have a driver assigned to it. */
+	/* we don't want this device to have a driver assigned to it. */
 	return (1);
 }
 
-	/* USA-19 uses three output endpoints and four input
-	   endpoints.  First two output endpoints are for
-	   data (used in an alternating fashion), the third is
-	   output control.  First two input endpoints are for
-	   data (again alternating), the third is the ACK
-	   endpoint, the fourth is input status. */
-static void keyspan_usa19_setup_urbs(struct usb_serial *serial)
+/* Helper functions used by keyspan_setup_urbs */
+static urb_t *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
+				int dir, void *ctx, char *buf, int len,
+				void (*callback)(urb_t *))
+{
+	urb_t *urb;
+
+	if (endpoint == -1)
+		return NULL;		/* endpoint not needed */
+
+	/*  dbg (__FUNCTION__ " alloc for endpoint %d.", endpoint); */
+	urb = usb_alloc_urb(0);		/* No ISO */
+	if (urb == NULL) {
+		dbg (__FUNCTION__ " alloc for endpoint %d failed.", endpoint);
+		return NULL;
+	}
+
+		/* Fill URB using supplied data. */
+	FILL_BULK_URB(urb, serial->dev,
+		      usb_sndbulkpipe(serial->dev, endpoint) | dir,
+		      buf, len, callback, ctx);
+
+	return urb;
+}
+
+struct callbacks {
+	void	(*instat_callback)(urb_t *);
+	void	(*glocont_callback)(urb_t *);
+	void	(*indat_callback)(urb_t *);
+	void	(*outdat_callback)(urb_t *);
+	void	(*inack_callback)(urb_t *);
+	void	(*outcont_callback)(urb_t *);
+} keyspan_callbacks[] = {
+	{
+		/* msg_usa26 callbacks */
+		instat_callback: usa26_instat_callback,
+		glocont_callback: usa26_glocont_callback,
+		indat_callback: usa26_indat_callback,
+		outdat_callback: usa2x_outdat_callback,
+		inack_callback: usa26_inack_callback,
+		outcont_callback: usa26_outcont_callback,
+	}, {
+		/* msg_usa28 callbacks */
+		instat_callback: usa28_instat_callback,
+		glocont_callback: usa28_glocont_callback,
+		indat_callback: usa28_indat_callback,
+		outdat_callback: usa2x_outdat_callback,
+		inack_callback: usa28_inack_callback,
+		outcont_callback: usa28_outcont_callback,
+	}, {
+		/* msg_usa49 callbacks */
+		instat_callback: usa49_instat_callback,
+		glocont_callback: usa49_glocont_callback,
+		indat_callback: usa49_indat_callback,
+		outdat_callback: usa2x_outdat_callback,
+		inack_callback: usa49_inack_callback,
+		outcont_callback: usa49_outcont_callback,
+	}
+};
+
+	/* Generic setup urbs function that uses
+	   data in device_details */
+static void keyspan_setup_urbs(struct usb_serial *serial)
 {
+	int				i, j;
 	struct keyspan_serial_private 	*s_priv;
-	int			i;
+	const keyspan_device_details	*d_details;
+	struct usb_serial_port		*port;
+	struct keyspan_port_private	*p_priv;
+	struct callbacks		*cback;
+	int				endp;
+
+	/*  dbg (__FUNCTION__); */
 
 	s_priv = (struct keyspan_serial_private *)(serial->private);
+	d_details = s_priv->device_details;
 
-		/* Output urbs first */
-	dbg(__FUNCTION__ "Allocating output urbs.\n");
-	for (i = 0; i < 3; i++) {
-
-		s_priv->out_urbs[i] = usb_alloc_urb (0);	/* No ISO */
-		if (!s_priv->out_urbs[i]) {
-			dbg (__FUNCTION__ "Alloc for %d out urb failed.\n", i);
-			return;
-		}
+		/* Setup values for the various callback routines */
+	cback = &keyspan_callbacks[d_details->msg_format];
 
-		FILL_BULK_URB(s_priv->out_urbs[i], serial->dev, 
-			      usb_sndbulkpipe(serial->dev, i + 1),
-			      &s_priv->out_buffer[i], sizeof(s_priv->out_buffer[i]),
-			      keyspan_write_bulk_callback, 
-			      serial);
-	}
+		/* Allocate and set up urbs for each one that is in use, 
+		   starting with instat endpoints */
+	s_priv->instat_urb = keyspan_setup_urb
+		(serial, d_details->instat_endpoint, USB_DIR_IN,
+		 serial, s_priv->instat_buf, INSTAT_BUFLEN,
+		 cback->instat_callback);
+
+	s_priv->glocont_urb = keyspan_setup_urb
+		(serial, d_details->glocont_endpoint, USB_DIR_OUT,
+		 serial, s_priv->glocont_buf, GLOCONT_BUFLEN,
+		 cback->glocont_callback);
 
-		/* Now input urbs */
-	dbg(__FUNCTION__ "Allocating input urbs.\n");
-	for (i = 0; i < 4; i++) {
-
-		s_priv->in_urbs[i] = usb_alloc_urb (0);	/* No ISO */
-		if (!s_priv->in_urbs[i]) {
-			dbg (__FUNCTION__ "Alloc for %d in urb failed.\n", i);
-			return;
+		/* Setup endpoints for each port specific thing */
+	for (i = 0; i < d_details->num_ports; i ++) {
+		port = &serial->port[i];
+		p_priv = (struct keyspan_port_private *)(port->private);
+
+		/* Do indat endpoints first, once for each flip */
+		endp = d_details->indat_endpoints[i];
+		for (j = 0; j <= d_details->indat_endp_flip; ++j, ++endp) {
+			p_priv->in_urbs[j] = keyspan_setup_urb
+				(serial, endp, USB_DIR_IN, port,
+				 p_priv->in_buffer[j], 64,
+				 cback->indat_callback);
 		}
+		for (; j < 2; ++j)
+			p_priv->in_urbs[j] = NULL;
+
+		/* outdat endpoints also have flip */
+		endp = d_details->outdat_endpoints[i];
+		for (j = 0; j <= d_details->outdat_endp_flip; ++j, ++endp) {
+			p_priv->out_urbs[j] = keyspan_setup_urb
+				(serial, endp, USB_DIR_OUT, port,
+				 p_priv->out_buffer[j], 64,
+				 cback->outdat_callback);
+		}
+		for (; j < 2; ++j)
+			p_priv->out_urbs[j] = NULL;
+
+		/* inack endpoint */
+		p_priv->inack_urb = keyspan_setup_urb
+			(serial, d_details->inack_endpoints[i], USB_DIR_IN,
+			 port, p_priv->inack_buffer, 1, cback->inack_callback);
+
+		/* outcont endpoint */
+		p_priv->outcont_urb = keyspan_setup_urb
+			(serial, d_details->outcont_endpoints[i], USB_DIR_OUT,
+			 port, p_priv->outcont_buffer, 64,
+			 cback->outcont_callback);
+	}	
 
-		FILL_BULK_URB(s_priv->in_urbs[i], serial->dev, 
-			      usb_rcvbulkpipe(serial->dev, i + 0x81),
-			      &s_priv->in_buffer[i], sizeof(s_priv->in_buffer[i]),
-			      keyspan_read_bulk_callback, 
-			      serial);
-	}
-	
 }
 
-static int keyspan_usa19_calc_baud(u32 baud_rate, u8 *rate_hi, u8 *rate_low)
+/* usa19 function doesn't require prescaler */
+static int keyspan_usa19_calc_baud(u32 baud_rate, u32 baudclk,
+				   u8 *rate_hi, u8 *rate_low, u8 *prescaler)
 {
-	u32 b16,	/* baud rate times 16 (actual rate used internally) */
+	u32 	b16,	/* baud rate times 16 (actual rate used internally) */
 		div,	/* divisor */	
 		cnt;	/* inverse of divisor (programmed into 8051) */
+		
 
 		/* prevent divide by zero...  */
 	if( (b16 = (baud_rate * 16L)) == 0) {
 		return (KEYSPAN_INVALID_BAUD_RATE);
 	}
 
+		/* Any "standard" rate over 57k6 is marginal on the USA-19
+		   as we run out of divisor resolution. */
+	if (baud_rate > 57600) {
+		return (KEYSPAN_INVALID_BAUD_RATE);
+	}
+
 		/* calculate the divisor and the counter (its inverse) */
-	if( (div = (USA19_BAUDCLK / b16)) == 0) {
+	if( (div = (baudclk / b16)) == 0) {
 		return (KEYSPAN_INVALID_BAUD_RATE);
 	}
 	else {
@@ -510,216 +1151,520 @@
 		return (KEYSPAN_INVALID_BAUD_RATE);
 	}
 
-		/* return the counter values */
-	*rate_low = (u8) (cnt & 0xff);
-	*rate_hi = (u8) ((cnt >> 8) & 0xff);
+		/* return the counter values if non-null */
+	if (rate_low) {
+		*rate_low = (u8) (cnt & 0xff);
+	}
+	if (rate_hi) {
+		*rate_hi = (u8) ((cnt >> 8) & 0xff);
+	}
+	if (rate_low && rate_hi) {
+		dbg (__FUNCTION__ " %d %02x %02x.", baud_rate, *rate_hi, *rate_low);
+	}
 	
-	dbg(__FUNCTION__ " Baud rate of %d is %02x %02x.\n", baud_rate, *rate_hi, *rate_low);
+	return (KEYSPAN_BAUD_RATE_OK);
+}
+
+static int keyspan_usa19w_calc_baud(u32 baud_rate, u32 baudclk,
+				    u8 *rate_hi, u8 *rate_low, u8 *prescaler)
+{
+	u32 	b16,	/* baud rate times 16 (actual rate used internally) */
+		clk,	/* clock with 13/8 prescaler */
+		div,	/* divisor using 13/8 prescaler */	
+		res,	/* resulting baud rate using 13/8 prescaler */
+		diff,	/* error using 13/8 prescaler */
+		smallest_diff;
+	u8	best_prescaler;
+	int	i;
+
+	/*  dbg (__FUNCTION__ " %d.", baud_rate); */
+
+		/* prevent divide by zero */
+	if( (b16 = baud_rate * 16L) == 0) {
+		return (KEYSPAN_INVALID_BAUD_RATE);
+	}
 
+		/* Calculate prescaler by trying them all and looking
+		   for best fit */
+		
+		/* start with largest possible difference */
+	smallest_diff = 0xffffffff;
+
+		/* 0 is an invalid prescaler, used as a flag */
+	best_prescaler = 0;
+
+	for(i = 8; i <= 0xff; ++i)
+	{
+		clk = (baudclk * 8) / (u32) i;
+		
+		if( (div = clk / b16) == 0) {
+			continue;
+		}
+
+		res = clk / div;
+		diff= (res > b16) ? (res-b16) : (b16-res);
+
+		if(diff < smallest_diff)
+		{
+			best_prescaler = i;
+			smallest_diff = diff;
+		}
+	}
+
+	if(best_prescaler == 0) {
+		return (KEYSPAN_INVALID_BAUD_RATE);
+	}
+
+	clk = (baudclk * 8) / (u32) best_prescaler;
+	div = clk / b16;
+
+		/* return the divisor and prescaler if non-null */
+	if (rate_low) {
+		*rate_low = (u8) (div & 0xff);
+	}
+	if (rate_hi) {
+		*rate_hi = (u8) ((div >> 8) & 0xff);
+	}
+	if (prescaler) {
+		*prescaler = best_prescaler;
+		/*  dbg(__FUNCTION__ " %d %d", *prescaler, div); */
+	}
 	return (KEYSPAN_BAUD_RATE_OK);
 }
 
-static int keyspan_usa19_send_setup(struct usb_serial *serial, struct usb_serial_port *port)
+static int keyspan_usa26_send_setup(struct usb_serial *serial,
+				    struct usb_serial_port *port)
 {
-	struct portControlMessage	msg;		
-	struct keyspan_serial_private 	*s_priv;
-	struct keyspan_port_private 	*p_priv;
+	struct keyspan_usa26_portControlMessage	msg;		
+	struct keyspan_serial_private 		*s_priv;
+	struct keyspan_port_private 		*p_priv;
+	const  keyspan_device_details		*d_details;
+	int 					outcont_urb;
+	urb_t *this_urb;
+	int err;
+
+	/*  dbg (__FUNCTION__); */
 
 	s_priv = (struct keyspan_serial_private *)(serial->private);
 	p_priv = (struct keyspan_port_private *)(port->private);
+	d_details = s_priv->device_details;
+
+	outcont_urb = d_details->outcont_endpoints[port->number];
+	this_urb = p_priv->outcont_urb;
+
+		/* Make sure we have an urb then send the message */
+	if (this_urb == NULL) {
+		dbg(__FUNCTION__ " oops no urb.");
+		return -1;
+	}
+
+	p_priv->resend_cont = 1;
+	if (this_urb->status == -EINPROGRESS) {
+		/*  dbg (__FUNCTION__ " already writing"); */
+		return(-1);
+	}
+
+	memset(&msg, 0, sizeof (struct keyspan_usa26_portControlMessage));
+	
+		/* Only set baud rate if it's changed */	
+	if (p_priv->old_baud != p_priv->baud) {
+		p_priv->old_baud = p_priv->baud;
+		msg.setClocking = 0xff;
+		if (d_details->calculate_baud_rate
+		    (p_priv->baud, d_details->baudclk, &msg.baudHi,
+		     &msg.baudLo, &msg.prescaler) == KEYSPAN_INVALID_BAUD_RATE ) {
+			dbg(__FUNCTION__ "Invalid baud rate %d requested, using 9600.",
+			    p_priv->baud);
+			msg.baudLo = 0;
+			msg.baudHi = 125;	/* Values for 9600 baud */
+			msg.prescaler = 10;
+		}
+		msg.setPrescaler = 0xff;
+	}
+
+	msg.lcr = USA_DATABITS_8 | STOPBITS_5678_1;
+	if (p_priv->cflag & PARENB) {
+		/* note USA_PARITY_NONE == 0 */
+		msg.lcr |= (p_priv->cflag & PARODD)?
+			USA_PARITY_ODD: USA_PARITY_EVEN;
+	}
+	msg.setLcr = 0xff;
 
-	//memset(msg, 0, sizeof (struct portControlMessage));
+	msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
+	msg.xonFlowControl = 0;
+	msg.setFlowControl = 0xff;
+	
+	msg.forwardingLength = 1;
+	msg.xonChar = 17;
+	msg.xoffChar = 19;
+	
+	msg._txOn = 1;
+	msg._txOff = 0;
+	msg.txFlush = 0;
+	msg.txBreak = 0;
+	msg.rxOn = 1;
+	msg.rxOff = 0;
+	msg.rxFlush = 0;
+	msg.rxForward = 0;
+	/*msg.returnStatus = 1;
+	msg.resetDataToggle = 0xff;*/
+
+		/* Do handshaking outputs */	
+	msg.setTxTriState_setRts = 0xff;
+	msg.txTriState_rts = p_priv->rts_state;
+
+	msg.setHskoa_setDtr = 0xff;
+	msg.hskoa_dtr = p_priv->dtr_state;
 		
+	p_priv->resend_cont = 0;
+	memcpy (this_urb->transfer_buffer, &msg, sizeof(msg));
+	
+	/* send the data out the device on control endpoint */
+	this_urb->transfer_buffer_length = sizeof(msg);
+
+	this_urb->dev = serial->dev;
+	if ((err = usb_submit_urb(this_urb)) != 0) {
+		dbg(__FUNCTION__ " usb_submit_urb(setup) failed (%d)", err);
+	}
+#if 0
+	else {
+		dbg(__FUNCTION__ " usb_submit_urb(%d) OK %d bytes (end %d)",
+		    outcont_urb, this_urb->transfer_buffer_length,
+		    usb_pipeendpoint(this_urb->pipe));
+	}
+#endif
+
+	return (0);
+}
+
+static int keyspan_usa28_send_setup(struct usb_serial *serial,
+				    struct usb_serial_port *port)
+{
+	struct keyspan_usa28_portControlMessage	msg;		
+	struct keyspan_serial_private	 	*s_priv;
+	struct keyspan_port_private 		*p_priv;
+	const  keyspan_device_details		*d_details;
+	urb_t *this_urb;
+	int err;
+
+	s_priv = (struct keyspan_serial_private *)(serial->private);
+	p_priv = (struct keyspan_port_private *)(port->private);
+	d_details = s_priv->device_details;
+
+	/* only do something if we have a bulk out endpoint */
+	if ((this_urb = p_priv->outcont_urb) == NULL) {
+		dbg(__FUNCTION__ " oops no urb.");
+		return -1;
+	}
+
+	p_priv->resend_cont = 1;
+	if (this_urb->status == -EINPROGRESS) {
+		dbg (__FUNCTION__ " already writing");
+		return(-1);
+	}
+
+	memset(&msg, 0, sizeof (struct keyspan_usa28_portControlMessage));
+
 	msg.setBaudRate = 1;
-	if (keyspan_usa19_calc_baud(9600, &msg.baudHi, &msg.baudLo) ==
-		KEYSPAN_INVALID_BAUD_RATE ) {
-		dbg(__FUNCTION__ "Invalid baud rate requested %d.\n", 9600);
+	if (keyspan_usa19_calc_baud(p_priv->baud, d_details->baudclk,
+		&msg.baudHi, &msg.baudLo, NULL) == KEYSPAN_INVALID_BAUD_RATE ) {
+		dbg(__FUNCTION__ "Invalid baud rate requested %d.", 9600);
 		msg.baudLo = 0xff;
 		msg.baudHi = 0xb2;	/* Values for 9600 baud */
 	}
 
-		/* If parity is enabled, we must calculate it ourselves. */
-	if (p_priv->parity) {
-		msg.parity = 1;
+	/* If parity is enabled, we must calculate it ourselves. */
+	msg.parity = 0;		/* XXX for now */
+
+	msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
+	msg.xonFlowControl = 0;
+
+	/* Do handshaking outputs, DTR is inverted relative to RTS */	
+	msg.rts = p_priv->rts_state;
+	msg.dtr = p_priv->dtr_state;
+
+	msg.forwardingLength = 1;
+	msg.forwardMs = 10;
+	msg.breakThreshold = 45;
+	msg.xonChar = 17;
+	msg.xoffChar = 19;
+
+	msg._txOn = 1;
+	msg._txOff = 0;
+	msg.txFlush = 0;
+	msg.txForceXoff = 0;
+	msg.txBreak = 0;
+	msg.rxOn = 1;
+	msg.rxOff = 0;
+	msg.rxFlush = 0;
+	msg.rxForward = 0;
+	/*msg.returnStatus = 1;
+	msg.resetDataToggle = 0xff;*/
+
+	p_priv->resend_cont = 0;
+	memcpy (this_urb->transfer_buffer, &msg, sizeof(msg));
+
+	/* send the data out the device on control endpoint */
+	this_urb->transfer_buffer_length = sizeof(msg);
+
+	this_urb->dev = serial->dev;
+	if ((err = usb_submit_urb(this_urb)) != 0) {
+		dbg(__FUNCTION__ " usb_submit_urb(setup) failed");
 	}
+#if 0
 	else {
-		msg.parity = 0;
+		dbg(__FUNCTION__ " usb_submit_urb(setup) OK %d bytes",
+		    this_urb->transfer_buffer_length);
+	}
+#endif
+
+	return (0);
+}
+
+static int keyspan_usa49_send_setup(struct usb_serial *serial,
+				    struct usb_serial_port *port)
+{
+	struct keyspan_usa49_portControlMessage	msg;		
+	struct keyspan_serial_private 		*s_priv;
+	struct keyspan_port_private 		*p_priv;
+	const  keyspan_device_details		*d_details;
+	int 					glocont_urb;
+	urb_t *this_urb;
+	int err;
+
+	/*  dbg (__FUNCTION__); */
+
+	s_priv = (struct keyspan_serial_private *)(serial->private);
+	p_priv = (struct keyspan_port_private *)(port->private);
+	d_details = s_priv->device_details;
+
+	glocont_urb = d_details->glocont_endpoint;
+	this_urb = s_priv->glocont_urb;
+
+	/*  dbg(__FUNCTION__ " port %d\n", port->number); */
+
+		/* Make sure we have an urb then send the message */
+	if (this_urb == NULL) {
+		dbg(__FUNCTION__ " oops no urb for port %d.", port->number);
+		return -1;
+	}
+
+	p_priv->resend_cont = 1;
+	if (this_urb->status == -EINPROGRESS) {
+		/*  dbg (__FUNCTION__ " already writing"); */
+		return(-1);
+	}
+
+	memset(&msg, 0, sizeof (struct keyspan_usa49_portControlMessage));
+
+	msg.portNumber = port->number;
+	
+		/* Only set baud rate if it's changed */	
+	if (p_priv->old_baud != p_priv->baud) {
+		p_priv->old_baud = p_priv->baud;
+		msg.setClocking = 0xff;
+		if (d_details->calculate_baud_rate
+		    (p_priv->baud, d_details->baudclk, &msg.baudHi,
+		     &msg.baudLo, &msg.prescaler) == KEYSPAN_INVALID_BAUD_RATE ) {
+			dbg(__FUNCTION__ "Invalid baud rate %d requested, using 9600.",
+			    p_priv->baud);
+			msg.baudLo = 0;
+			msg.baudHi = 125;	/* Values for 9600 baud */
+			msg.prescaler = 10;
+		}
+		//msg.setPrescaler = 0xff;
 	}
 
-	msg.ctsFlowControl = 0;
+	msg.lcr = USA_DATABITS_8 | STOPBITS_5678_1;
+	if (p_priv->cflag & PARENB) {
+		/* note USA_PARITY_NONE == 0 */
+		msg.lcr |= (p_priv->cflag & PARODD)?
+			USA_PARITY_ODD: USA_PARITY_EVEN;
+	}
+	msg.setLcr = 0xff;
+
+	msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
 	msg.xonFlowControl = 0;
-	msg.rts = 1;
-	msg.dtr = 0;
+	msg.setFlowControl = 0xff;
 	
 	msg.forwardingLength = 1;
-	msg.forwardMs = 10;
-	msg.breakThreshold = 45;
 	msg.xonChar = 17;
 	msg.xoffChar = 19;
 	
 	msg._txOn = 1;
 	msg._txOff = 0;
 	msg.txFlush = 0;
-	msg.txForceXoff = 0;
 	msg.txBreak = 0;
 	msg.rxOn = 1;
 	msg.rxOff = 0;
 	msg.rxFlush = 0;
 	msg.rxForward = 0;
-	msg.returnStatus = 1;
-	msg.resetDataToggle = 1;
+	msg.enablePort = 0xff;
+	msg.disablePort = 0;
+
+		/* Do handshaking outputs */	
+	msg.setRts = 0xff;
+	msg.rts = p_priv->rts_state;
 
+	msg.setDtr = 0xff;
+	msg.dtr = p_priv->dtr_state;
 		
-	/* only do something if we have a bulk out endpoint */
-	if (s_priv->out_urbs[2]) {
-		if (s_priv->out_urbs[2]->status == -EINPROGRESS) {
-			dbg (__FUNCTION__ " already writing");
-			return(-1);
-		}
-		memcpy (s_priv->out_urbs[2]->transfer_buffer, &msg, sizeof(msg));
+	p_priv->resend_cont = 0;
+	memcpy (this_urb->transfer_buffer, &msg, sizeof(msg));
 	
-			/* send the data out the device on control endpoint */
-		s_priv->out_urbs[2]->transfer_buffer_length = sizeof(msg);
+	/* send the data out the device on control endpoint */
+	this_urb->transfer_buffer_length = sizeof(msg);
 
-		if (usb_submit_urb(s_priv->out_urbs[2])) {
-			dbg(__FUNCTION__ " usb_submit_urb(setup) failed\n");
-		}
-		else {
-			dbg(__FUNCTION__ " usb_submit_urb(setup) OK %d bytes\n", s_priv->out_urbs[2]->transfer_buffer_length);
-		}
-	
+	this_urb->dev = serial->dev;
+	if ((err = usb_submit_urb(this_urb)) != 0) {
+		dbg(__FUNCTION__ " usb_submit_urb(setup) failed (%d)", err);
 	}
+#if 0
+	else {
+		dbg(__FUNCTION__ " usb_submit_urb(%d) OK %d bytes (end %d)",
+		    outcont_urb, this_urb->transfer_buffer_length,
+		    usb_pipeendpoint(this_urb->pipe));
+	}
+#endif
+
 	return (0);
 }
 
+static void keyspan_send_setup(struct usb_serial_port *port)
+{
+	struct usb_serial *serial = port->serial;
+	struct keyspan_serial_private 	*s_priv;
+	const keyspan_device_details	*d_details;
+
+	s_priv = (struct keyspan_serial_private *)(serial->private);
+	d_details = s_priv->device_details;
 
-	/* Gets called by the "real" driver (ie once firmware is loaded
-	   and renumeration has taken place. */
+	switch (d_details->msg_format) {
+	case msg_usa26:
+		keyspan_usa26_send_setup(serial, port);
+		break;
+	case msg_usa28:
+		keyspan_usa28_send_setup(serial, port);
+		break;
+	case msg_usa49:
+		keyspan_usa49_send_setup(serial, port);
+		break;
+	}
+}
+
+/* Gets called by the "real" driver (ie once firmware is loaded
+   and renumeration has taken place. */
 static int keyspan_startup (struct usb_serial *serial)
 {
-	int			i;
-	struct usb_serial_port	*port;
+	int				i, err;
+	struct usb_serial_port		*port;
+	struct keyspan_serial_private 	*s_priv;
+	struct keyspan_port_private	*p_priv;
+	const keyspan_device_details	*d_details;
+
+	/*  dbg("keyspan_startup called."); */
 
-	dbg("keyspan_startup called.\n");
+	for (i = 0; (d_details = keyspan_devices[i]) != NULL; ++i)
+		if (d_details->product_id == serial->dev->descriptor.idProduct)
+			break;
+	if (d_details == NULL) {
+		printk(KERN_ERR __FUNCTION__ ": unknown product id %x\n",
+		       serial->dev->descriptor.idProduct);
+		return 1;
+	}
 
-		/* Setup private data for serial driver */
-	serial->private = kmalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL);
+	/* Setup private data for serial driver */
+	serial->private = kmalloc(sizeof(struct keyspan_serial_private),
+				  GFP_KERNEL);
 	if (!serial->private) {
-		dbg(__FUNCTION__ "kmalloc for keyspan_serial_private failed!.\n");
+		dbg(__FUNCTION__ "kmalloc for keyspan_serial_private failed.");
 		return (1);
 	}
 	memset(serial->private, 0, sizeof(struct keyspan_serial_private));
+
+	s_priv = (struct keyspan_serial_private *)(serial->private);
+	s_priv->device_details = d_details;
 		
-	init_waitqueue_head(&out_wait);
-	
-		/* Now setup per port private data */
+	/* Now setup per port private data */
 	for (i = 0; i < serial->num_ports; i++) {
 		port = &serial->port[i];
-		port->private = kmalloc(sizeof(struct keyspan_port_private), GFP_KERNEL);
+		port->private = kmalloc(sizeof(struct keyspan_port_private),
+					GFP_KERNEL);
 		if (!port->private) {
-			dbg(__FUNCTION__ "kmalloc for keyspan_port_private (%d) failed!.\n", i);
+			dbg(__FUNCTION__ "kmalloc for keyspan_port_private (%d) failed!.", i);
 			return (1);
 		}
 		memset(port->private, 0, sizeof(struct keyspan_port_private));
+		p_priv = (struct keyspan_port_private *)(port->private);
+		p_priv->device_details = d_details;
 	}
 
-	
+	keyspan_setup_urbs(serial);
 
-	switch (serial->dev->descriptor.idProduct) {
-		case 0x0107:	keyspan_usa19_setup_urbs(serial);
-				//keyspan_send_usa19_setup(serial);
-				break;
-
-		default:	break;
+	s_priv->instat_urb->dev = serial->dev;
+	if ((err = usb_submit_urb(s_priv->instat_urb)) != 0) {
+		dbg(__FUNCTION__ " submit instat urb failed %d", err);
 	}
-
 			
 	return (0);
 }
 
 static void keyspan_shutdown (struct usb_serial *serial)
 {
-	int				i;
+	int				i, j;
 	struct usb_serial_port		*port;
 	struct keyspan_serial_private 	*s_priv;
+	struct keyspan_port_private	*p_priv;
 
-	dbg("keyspan_shutdown called freeing ");
+	/*  dbg("keyspan_shutdown called"); */
 
 	s_priv = (struct keyspan_serial_private *)(serial->private);
 
-		/* Stop reading/writing urbs */
-	for (i = 0; i < 4; i++) {
-		if (s_priv->in_urbs[i]) {
-			usb_unlink_urb(s_priv->in_urbs[i]);
+	/* Stop reading/writing urbs */
+	stop_urb(s_priv->instat_urb);
+	stop_urb(s_priv->glocont_urb);
+	for (i = 0; i < serial->num_ports; ++i) {
+		port = &serial->port[i];
+		p_priv = (struct keyspan_port_private *)(port->private);
+		stop_urb(p_priv->inack_urb);
+		stop_urb(p_priv->outcont_urb);
+		for (j = 0; j < 2; j++) {
+			stop_urb(p_priv->in_urbs[j]);
+			stop_urb(p_priv->out_urbs[j]);
 		}
-
 	}
-	for (i = 0; i < 3; i++) {
-		if (s_priv->out_urbs[i]) {
-			usb_unlink_urb(s_priv->out_urbs[i]);
-		}
 
-	}
-		/* Now free them */
-	for (i = 0; i < 7; i ++) {
-		if (s_priv->in_urbs[i] != NULL) {
-			dbg("in%d ", i);
-			usb_free_urb(s_priv->in_urbs[i]);
-		}
-		
-		if (s_priv->out_urbs[i] != NULL) {
-			dbg("out%d ", i);
-			usb_free_urb(s_priv->out_urbs[i]);
+	/* Now free them */
+	if (s_priv->instat_urb)
+		usb_free_urb(s_priv->instat_urb);
+	if (s_priv->glocont_urb)
+		usb_free_urb(s_priv->glocont_urb);
+	for (i = 0; i < serial->num_ports; ++i) {
+		port = &serial->port[i];
+		p_priv = (struct keyspan_port_private *)(port->private);
+		if (p_priv->inack_urb)
+			usb_free_urb(p_priv->inack_urb);
+		if (p_priv->outcont_urb)
+			usb_free_urb(p_priv->outcont_urb);
+		for (j = 0; j < 2; j++) {
+			if (p_priv->in_urbs[j])
+				usb_free_urb(p_priv->in_urbs[j]);
+			if (p_priv->out_urbs[j])
+				usb_free_urb(p_priv->out_urbs[j]);
 		}
 	}
-	dbg("urbs.\n");
 
-	dbg("Freeing serial->private.\n");	
+	/*  dbg("Freeing serial->private."); */
 	kfree(serial->private);
 
-	dbg("Freeing port->private.\n");	
-		/* Now free per port private data */
+	/*  dbg("Freeing port->private."); */
+	/* Now free per port private data */
 	for (i = 0; i < serial->num_ports; i++) {
 		port = &serial->port[i];
+		while (port->open_count > 0) {
+			--port->open_count;
+			MOD_DEC_USE_COUNT;
+		}
 		kfree(port->private);
 	}
-	
 }
-
-
-static int __init keyspan_init (void)
-{
-	usb_serial_register (&keyspan_usa18x_pre_device);
-	usb_serial_register (&keyspan_usa19_pre_device);
-	usb_serial_register (&keyspan_usa19w_pre_device);
-	usb_serial_register (&keyspan_usa28_pre_device);
-	usb_serial_register (&keyspan_usa28x_pre_device);
-	usb_serial_register (&keyspan_usa18x_device);
-	usb_serial_register (&keyspan_usa19_device);
-	usb_serial_register (&keyspan_usa19w_device);
-	usb_serial_register (&keyspan_usa28_device);
-	usb_serial_register (&keyspan_usa28x_device);
-	return 0;
-}
-
-
-static void __exit keyspan_exit (void)
-{
-	usb_serial_deregister (&keyspan_usa18x_pre_device);
-	usb_serial_deregister (&keyspan_usa19_pre_device);
-	usb_serial_deregister (&keyspan_usa19w_pre_device);
-	usb_serial_deregister (&keyspan_usa28_pre_device);
-	usb_serial_deregister (&keyspan_usa28x_pre_device);
-	usb_serial_deregister (&keyspan_usa18x_device);
-	usb_serial_deregister (&keyspan_usa19_device);
-	usb_serial_deregister (&keyspan_usa19w_device);
-	usb_serial_deregister (&keyspan_usa28_device);
-	usb_serial_deregister (&keyspan_usa28x_device);
-}
-
-
-module_init(keyspan_init);
-module_exit(keyspan_exit);
-
-MODULE_AUTHOR("Hugh Blemings <hugh@linuxcare.com>");
-MODULE_DESCRIPTION("Keyspan USB to Serial Converter driver");
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/keyspan.h linux.19p18/drivers/usb/serial/keyspan.h
--- linux.vanilla/drivers/usb/serial/keyspan.h	Mon Dec 11 22:13:01 2000
+++ linux.19p18/drivers/usb/serial/keyspan.h	Tue Feb 20 13:41:53 2001
@@ -19,6 +19,11 @@
   and Keyspan, Inc the manufacturers of the Keyspan USB-serial products.
   Thanks Guys :)
   
+  Thanks to Paulus for miscellaneous tidy ups, some largish chunks
+  of much nicer and/or completely new code and (perhaps most uniquely)
+  having the patience to sit down and explain why and where he'd changed
+  stuff.
+
   Tip 'o the hat to Linuxcare for supporting staff in their work on
   open source projects.
   
@@ -41,12 +46,18 @@
 static void keyspan_rx_throttle		(struct usb_serial_port *port);
 static void keyspan_rx_unthrottle	(struct usb_serial_port *port);
 static int  keyspan_write_room		(struct usb_serial_port *port);
+
 static int  keyspan_write		(struct usb_serial_port *port,
 					 int from_user,
 					 const unsigned char *buf,
 					 int count);
+
+#if 0
 static void keyspan_write_bulk_callback (struct urb *urb);
-static void keyspan_read_bulk_callback  (struct urb *urb);
+#endif
+
+//static void keyspan_usa26_read_int_callback  (struct urb *urb);
+//static void keyspan_usa28_read_int_callback  (struct urb *urb);
 static int  keyspan_chars_in_buffer 	(struct usb_serial_port *port);
 static int  keyspan_ioctl		(struct usb_serial_port *port,
 					 struct file *file,
@@ -58,12 +69,20 @@
 					 int break_state);
 static int  keyspan_fake_startup	(struct usb_serial *serial);
 
-static int  keyspan_usa19_calc_baud	(u32 baud_rate, u8 *rate_hi, 
-					 u8 *rate_low);
-static void keyspan_usa19_setup_urbs	(struct usb_serial *serial);
-static int  keyspan_usa19_send_setup	(struct usb_serial *serial,
-					 struct usb_serial_port *port);
+static int  keyspan_usa19_calc_baud	(u32 baud_rate, u32 baudclk, 
+					 u8 *rate_hi, u8 *rate_low, u8 *prescaler);
+
+static int  keyspan_usa19w_calc_baud	(u32 baud_rate, u32 baudclk,
+					 u8 *rate_hi, u8 *rate_low, u8 *prescaler);
+
+//static void keyspan_usa19_setup_urbs	(struct usb_serial *serial);
 
+static int  keyspan_usa28_send_setup	(struct usb_serial *serial,
+					 struct usb_serial_port *port);
+static int  keyspan_usa26_send_setup	(struct usb_serial *serial,
+	       				 struct usb_serial_port *port);
+static int  keyspan_usa49_send_setup	(struct usb_serial *serial,
+					 struct usb_serial_port *port);
 
 	/* Functions from usbserial.c for ezusb firmware handling */
 extern int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit);
@@ -109,34 +128,186 @@
 	static const struct ezusb_hex_record *keyspan_usa19w_firmware = NULL;
 #endif
 
-
+#ifdef CONFIG_USB_SERIAL_KEYSPAN_USA49W
+        #include "keyspan_usa49w_fw.h"
+#else
+	static const struct ezusb_hex_record *keyspan_usa49w_firmware = NULL;
+#endif
+	
 	/* Values used for baud rate calculation - device specific */
 #define	KEYSPAN_INVALID_BAUD_RATE		(-1)
 #define	KEYSPAN_BAUD_RATE_OK			(0)
-#define	USA19_BAUDCLK				(12000000L)
+#define	KEYSPAN_USA18X_BAUDCLK			(12000000L)	/* a guess */
+#define	KEYSPAN_USA19_BAUDCLK			(12000000L)
+#define	KEYSPAN_USA19W_BAUDCLK			(24000000L)
+#define	KEYSPAN_USA28X_BAUDCLK			(12000000L)
+#define	KEYSPAN_USA49W_BAUDCLK			(48000000L)
+
+	/* Some constants used to characterise each device. 
+	   There is a four port device due later in the year,
+	   we allow for it now in the following */
+#define		KEYSPAN_MAX_NUM_PORTS		(4)
+#define		KEYSPAN_MAX_FLIPS		(2)
+	
+typedef struct {
+	/* product ID value */
+	int	product_id;
+	
+	enum	{msg_usa26, msg_usa28, msg_usa49} msg_format;
+
+		/* Number of physical ports */
+	int	num_ports;
+
+		/* 1 if endpoint flipping used on input, 0 if not */
+	int	indat_endp_flip;
+
+		/* 1 if endpoint flipping used on output, 0 if not */
+	int 	outdat_endp_flip;
+
+		/* Table mapping input data endpoint IDs to physical
+		   port number and flip if used */
+	int	indat_endpoints[KEYSPAN_MAX_NUM_PORTS];
+
+		/* Same for output endpoints */
+	int	outdat_endpoints[KEYSPAN_MAX_NUM_PORTS];
+
+		/* Input acknowledge endpoints */
+	int	inack_endpoints[KEYSPAN_MAX_NUM_PORTS];
+
+		/* Output control endpoints */	
+	int	outcont_endpoints[KEYSPAN_MAX_NUM_PORTS];
+
+		/* Endpoint used for input status */
+	int	instat_endpoint;
+
+		/* Endpoint used for global control functions */
+	int	glocont_endpoint;	
+	
+	int	(*calculate_baud_rate) (u32 baud_rate, u32 baudclk,
+			u8 *rate_hi, u8 *rate_low, u8 *prescaler);
+	u32	baudclk;
+
+} keyspan_device_details; 
+
+	/* Now for each device type we setup the device detail
+	   structure with the appropriate information (provided
+	   in Keyspan's documentation) */
+
+static const keyspan_device_details usa18x_device_details = {
+	0x112,				/* product ID */
+       	msg_usa26, 			/* msg type*/
+	1,				/* num ports */
+	0,				/* indat endpoint flip */
+	1,				/* outdat endpoint flip */
+  	{0x81},				/* per port indat */
+  	{0x01},				/* per port outdat */
+	{0x85},				/* per port inack */
+	{0x05},				/* per port outcont */
+	0x87,				/* instat endpoint */
+	0x07,				/* glocont endpoint */
+	keyspan_usa19w_calc_baud,	/* calc baud rate */
+	KEYSPAN_USA18X_BAUDCLK		/* base baud clock */
+};
+
+static const keyspan_device_details usa19_device_details = {
+	0x107,				/* product ID */
+       	msg_usa28, 			/* msg type*/
+	1,				/* num ports */
+	1,				/* indat endpoint flip */
+	1,				/* outdat endpoint flip */
+  	{0x81},				/* per port indat */
+  	{0x01},				/* per port outdat */
+	{0x83},				/* per port inack */
+	{0x03},				/* per port outcont */
+	0x84,				/* instat endpoint */
+	-1,				/* glocont endpoint */
+	keyspan_usa19_calc_baud,	/* calc baud rate */
+	KEYSPAN_USA19_BAUDCLK		/* base baud clock */
+};
+
+static const keyspan_device_details usa19w_device_details = {
+	0x108,				/* product ID */
+       	msg_usa26, 			/* msg type*/
+	1,				/* num ports */
+	0,				/* indat endpoint flip */
+	1,				/* outdat endpoint flip */
+  	{0x81},				/* per port indat */
+  	{0x01},				/* per port outdat */
+	{0x85},				/* per port inack */
+	{0x05},				/* per port outcont */
+	0x87,				/* instat endpoint */
+	0x07,				/* glocont endpoint */
+	keyspan_usa19w_calc_baud,	/* calc baud rate */
+	KEYSPAN_USA19W_BAUDCLK		/* base baud clock */
+};
+
+static const keyspan_device_details usa28x_device_details = {
+	0x110,				/* product ID */
+       	msg_usa26, 			/* msg type*/
+	2,				/* num ports */
+	0,				/* indat endpoint flip */
+	1,				/* outdat endpoint flip */
+  	{0x81, 0x83},			/* per port indat */
+  	{0x01, 0x03},			/* per port outdat */
+	{0x85, 0x86},			/* per port inack */
+	{0x05, 0x06},			/* per port outcont */
+	0x87,				/* instat endpoint */
+	0x07,				/* glocont endpoint */
+	keyspan_usa19w_calc_baud,	/* calc baud rate */
+	KEYSPAN_USA28X_BAUDCLK
+};
+
+static const keyspan_device_details usa49w_device_details = {
+	0x010a,				/* product ID */
+       	msg_usa49, 			/* msg type*/
+	4,				/* num ports */
+	0,				/* indat endpoint flip */
+	0,				/* outdat endpoint flip */
+  	{ 0x81, 0x82, 0x83, 0x84},	/* per port indat */
+  	{ 0x01, 0x02, 0x03, 0x04},	/* per port outdat */
+	{-1, -1, -1, -1},		/* per port inack */
+	{-1, -1, -1, -1},		/* per port outcont */
+	0x87,				/* instat endpoint */
+	0x07,				/* glocont endpoint */
+	keyspan_usa19w_calc_baud,	/* calc baud rate */
+	KEYSPAN_USA49W_BAUDCLK
+};
+
+static const keyspan_device_details *keyspan_devices[] = {
+	&usa18x_device_details,
+	&usa19_device_details,
+	&usa19w_device_details,
+	&usa28x_device_details,
+	&usa49w_device_details,
+	NULL
+};
 
-	/* Device info for the Keyspan serial converter */
+	/* Device info for the Keyspan serial converter, used
+	   by the overall usb-serial probe function */
 #define KEYSPAN_VENDOR_ID			(0x06cd)
 static __u16	keyspan_vendor_id		= KEYSPAN_VENDOR_ID;
 
     /* Product IDs for the five products supported, pre-renumeration */
-static __u16	keyspan_usa18x_pre_product_id	= 0x0105;	
-static __u16	keyspan_usa19_pre_product_id	= 0x0103;	
-static __u16	keyspan_usa19w_pre_product_id	= 0x0106;	
-static __u16	keyspan_usa28_pre_product_id	= 0x0101;	
-static __u16	keyspan_usa28x_pre_product_id	= 0x0102;	
+static __u16	keyspan_usa18x_pre_product_id	= 0x0105;
+static __u16	keyspan_usa19_pre_product_id	= 0x0103;
+static __u16	keyspan_usa19w_pre_product_id	= 0x0106;
+static __u16	keyspan_usa28_pre_product_id	= 0x0101;
+static __u16	keyspan_usa28x_pre_product_id	= 0x0102;
+static __u16	keyspan_usa49w_pre_product_id	= 0x0109;
 
     /* Product IDs post-renumeration */
-static __u16	keyspan_usa18x_product_id	= 0x0112;	
-static __u16	keyspan_usa19_product_id	= 0x0107;	
-static __u16	keyspan_usa19w_product_id	= 0x0108;	
-static __u16	keyspan_usa28_product_id	= 0x010f;	
-static __u16	keyspan_usa28x_product_id	= 0x0110;	
+static __u16	keyspan_usa18x_product_id	= 0x0112;
+static __u16	keyspan_usa19_product_id	= 0x0107;
+static __u16	keyspan_usa19w_product_id	= 0x0108;
+static __u16	keyspan_usa28_product_id	= 0x010f;
+static __u16	keyspan_usa28x_product_id	= 0x0110;
+static __u16	keyspan_usa49w_product_id	= 0x010a;
+
 
     /* Structs for the devices, pre and post renumeration.
        These are incomplete at present - HAB 20000708  */
 struct usb_serial_device_type keyspan_usa18x_pre_device = {
-	name:			"Keyspan USA18X - (prerenumeration)",
+	name:			"Keyspan USA18X - (without firmware)",
 	idVendor:		&keyspan_vendor_id,
 	idProduct:		&keyspan_usa18x_pre_product_id,
 	needs_interrupt_in:	DONT_CARE,
@@ -150,7 +321,7 @@
 };
 
 struct usb_serial_device_type keyspan_usa19_pre_device = {
-	name:			"Keyspan USA19 - (prerenumeration)",
+	name:			"Keyspan USA19 - (without firmware)",
 	idVendor:		&keyspan_vendor_id,
 	idProduct:		&keyspan_usa19_pre_product_id,
 	needs_interrupt_in:	DONT_CARE,
@@ -165,7 +336,7 @@
 
 
 struct usb_serial_device_type keyspan_usa19w_pre_device = {
-	name:			"Keyspan USA19W - (prerenumeration)",
+	name:			"Keyspan USA19W - (without firmware)",
 	idVendor:		&keyspan_vendor_id,
 	idProduct:		&keyspan_usa19w_pre_product_id,
 	needs_interrupt_in:	DONT_CARE,
@@ -180,7 +351,7 @@
 
 
 struct usb_serial_device_type keyspan_usa28_pre_device = {
-	name:			"Keyspan USA28 - (prerenumeration)",
+	name:			"Keyspan USA28 - (without firmware)",
 	idVendor:		&keyspan_vendor_id,
 	idProduct:		&keyspan_usa28_pre_product_id,
 	needs_interrupt_in:	DONT_CARE,
@@ -194,7 +365,7 @@
 };
 
 struct usb_serial_device_type keyspan_usa28x_pre_device = {
-	name:			"Keyspan USA28X - (prerenumeration)",
+	name:			"Keyspan USA28X - (without firmware)",
 	idVendor:		&keyspan_vendor_id,
 	idProduct:		&keyspan_usa28x_pre_product_id,
 	needs_interrupt_in:	DONT_CARE,
@@ -207,23 +378,45 @@
 	startup:		keyspan_fake_startup	
 };
 
+struct usb_serial_device_type keyspan_usa49w_pre_device = {
+	name:			"Keyspan USA49W - (without firmware)",
+	idVendor:		&keyspan_vendor_id,
+	idProduct:		&keyspan_usa49w_pre_product_id,
+	needs_interrupt_in:	DONT_CARE,
+	needs_bulk_in:		DONT_CARE,
+	needs_bulk_out:		DONT_CARE,
+	num_interrupt_in:	NUM_DONT_CARE,
+	num_bulk_in:		NUM_DONT_CARE,
+	num_bulk_out:		NUM_DONT_CARE,
+	num_ports:		4,
+	startup:		keyspan_fake_startup	
+};
 
 struct usb_serial_device_type keyspan_usa18x_device = {
 	name:			"Keyspan USA18X",
 	idVendor:		&keyspan_vendor_id,
 	idProduct:		&keyspan_usa18x_product_id,
 	needs_interrupt_in:	DONT_CARE,	
-	needs_bulk_in:		DONT_CARE,
-	needs_bulk_out:		DONT_CARE,
+	needs_bulk_in:		MUST_HAVE,
+	needs_bulk_out:		MUST_HAVE,
 	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
+	num_bulk_in:		3,
+	num_bulk_out:		4,
 	num_ports:		1,
 	open:			keyspan_open,
 	close:			keyspan_close,
+	write:			keyspan_write,
+	write_room:		keyspan_write_room,
+	//write_bulk_callback: 	Not used - we define our own herbs
+	//read_int_callback:	keyspan_usa26_read_int_callback,
+	chars_in_buffer:	keyspan_chars_in_buffer,
 	throttle:		keyspan_rx_throttle,
 	unthrottle:		keyspan_rx_unthrottle,
+	ioctl:			keyspan_ioctl,
 	set_termios:		keyspan_set_termios,
+	break_ctl:		keyspan_break_ctl,
+	startup:		keyspan_startup,
+	shutdown:		keyspan_shutdown,
 };
 
 struct usb_serial_device_type keyspan_usa19_device = {
@@ -241,8 +434,8 @@
 	close:			keyspan_close,
 	write:			keyspan_write,
 	write_room:		keyspan_write_room,
-	write_bulk_callback: 	keyspan_write_bulk_callback,
-	read_int_callback:	keyspan_read_bulk_callback,
+//	write_bulk_callback: 	keyspan_write_bulk_callback,
+//	read_int_callback:	keyspan_usa28_read_int_callback,
 	chars_in_buffer:	keyspan_chars_in_buffer,
 	throttle:		keyspan_rx_throttle,
 	unthrottle:		keyspan_rx_unthrottle,
@@ -259,17 +452,26 @@
 	idVendor:		&keyspan_vendor_id,
 	idProduct:		&keyspan_usa19w_product_id,
 	needs_interrupt_in:	DONT_CARE,	
-	needs_bulk_in:		DONT_CARE,
-	needs_bulk_out:		DONT_CARE,
+	needs_bulk_in:		MUST_HAVE,
+	needs_bulk_out:		MUST_HAVE,
 	num_interrupt_in:	NUM_DONT_CARE,
-	num_bulk_in:		NUM_DONT_CARE,
-	num_bulk_out:		NUM_DONT_CARE,
+	num_bulk_in:		3,
+	num_bulk_out:		4,
 	num_ports:		1,
 	open:			keyspan_open,
 	close:			keyspan_close,
+	write:			keyspan_write,
+	write_room:		keyspan_write_room,
+	//write_bulk_callback: 	Not used - we define our own herbs
+	//read_int_callback:	keyspan_usa26_read_int_callback,
+	chars_in_buffer:	keyspan_chars_in_buffer,
 	throttle:		keyspan_rx_throttle,
 	unthrottle:		keyspan_rx_unthrottle,
+	ioctl:			keyspan_ioctl,
 	set_termios:		keyspan_set_termios,
+	break_ctl:		keyspan_break_ctl,
+	startup:		keyspan_startup,
+	shutdown:		keyspan_shutdown,
 };
 
 
@@ -307,8 +509,8 @@
 	close:			keyspan_close,
 	write:			keyspan_write,
 	write_room:		keyspan_write_room,
-	write_bulk_callback: 	keyspan_write_bulk_callback,
-	read_int_callback:	keyspan_read_bulk_callback,
+//	write_bulk_callback: 	keyspan_write_bulk_callback,
+//	read_int_callback:	keyspan_usa26_read_int_callback,
 	chars_in_buffer:	keyspan_chars_in_buffer,
 	throttle:		keyspan_rx_throttle,
 	unthrottle:		keyspan_rx_unthrottle,
@@ -318,10 +520,35 @@
 	startup:		keyspan_startup,
 	shutdown:		keyspan_shutdown,
 
+};
 				
 
+struct usb_serial_device_type keyspan_usa49w_device = {
+	name:			"Keyspan USA49W",
+	idVendor:		&keyspan_vendor_id,
+	idProduct:		&keyspan_usa49w_product_id,
+	needs_interrupt_in:	DONT_CARE,	
+	needs_bulk_in:		MUST_HAVE,
+	needs_bulk_out:		MUST_HAVE,
+	num_interrupt_in:	NUM_DONT_CARE,
+	num_bulk_in:		5,
+	num_bulk_out:		5,
+	num_ports:		4,
+	open:			keyspan_open,
+	close:			keyspan_close,
+	write:			keyspan_write,
+	write_room:		keyspan_write_room,
+	//write_bulk_callback: 	Not used - we define our own herbs
+	//read_int_callback:	keyspan_usa26_read_int_callback,
+	chars_in_buffer:	keyspan_chars_in_buffer,
+	throttle:		keyspan_rx_throttle,
+	unthrottle:		keyspan_rx_unthrottle,
+	ioctl:			keyspan_ioctl,
+	set_termios:		keyspan_set_termios,
+	break_ctl:		keyspan_break_ctl,
+	startup:		keyspan_startup,
+	shutdown:		keyspan_shutdown,
 };
-
 
 
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/keyspan_usa26msg.h linux.19p18/drivers/usb/serial/keyspan_usa26msg.h
--- linux.vanilla/drivers/usb/serial/keyspan_usa26msg.h	Mon Dec 11 22:13:01 2000
+++ linux.19p18/drivers/usb/serial/keyspan_usa26msg.h	Tue Jan  9 11:56:23 2001
@@ -92,16 +92,8 @@
 #ifndef	__USA26MSG__
 #define	__USA26MSG__
 
-#ifndef __stubs__
-#include "datadefs.h"
-#endif
 
-typedef struct txAckMessage
-{
-	u8	dummy;
-} txAckMessage;
-
-typedef struct portControlMessage
+typedef struct keyspan_usa26_portControlMessage
 {
 	/*
 		there are three types of "commands" sent in the control message:
@@ -172,7 +164,7 @@
 		returnStatus,	// BOTH: return current status (even if it hasn't changed)
 		resetDataToggle;// BOTH: reset data toggle state to DATA0
 	
-} portControlMessage;
+} keyspan_usa26_portControlMessage;
 
 // defines for bits in lcr
 #define	USA_DATABITS_5		0x00
@@ -190,7 +182,7 @@
 
 // all things called "StatusMessage" are sent on the status endpoint
 
-typedef struct portStatusMessage	// one for each port
+typedef struct keyspan_usa26_portStatusMessage	// one for each port
 {
 	u8	port,			// BOTH: 0=first, 1=second, other=see below
 		hskia_cts,		// USA26: reports HSKIA pin
@@ -203,7 +195,7 @@
 		_txXoff,		// port is in XOFF state (either host or RX XOFF)
 		rxEnabled,		// as configured by rxOn/rxOff 1=on, 0=off
 		controlResponse;// 1=a control message has been processed
-} portStatusMessage;
+} keyspan_usa26_portStatusMessage;
 
 // bits in RX data message when STAT byte is included
 #define	RXERROR_OVERRUN	0x02
@@ -211,28 +203,28 @@
 #define	RXERROR_FRAMING	0x08
 #define	RXERROR_BREAK	0x10
 
-typedef struct globalControlMessage
+typedef struct keyspan_usa26_globalControlMessage
 {
 	u8	sendGlobalStatus,	// 2=request for two status responses
 		resetStatusToggle,	// 1=reset global status toggle
 		resetStatusCount;	// a cycling value
-} globalControlMessage;
+} keyspan_usa26_globalControlMessage;
 
-typedef struct globalStatusMessage
+typedef struct keyspan_usa26_globalStatusMessage
 {
 	u8	port,				// 3
 		sendGlobalStatus,	// from request, decremented
 		resetStatusCount;	// as in request
-} globalStatusMessage;
+} keyspan_usa26_globalStatusMessage;
 
-typedef struct globalDebugMessage
+typedef struct keyspan_usa26_globalDebugMessage
 {
 	u8	port,				// 2
 		a,
 		b,
 		c,
 		d;
-} globalDebugMessage;
+} keyspan_usa26_globalDebugMessage;
 
 // ie: the maximum length of an EZUSB endpoint buffer
 #define	MAX_DATA_LEN			64
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/keyspan_usa28msg.h linux.19p18/drivers/usb/serial/keyspan_usa28msg.h
--- linux.vanilla/drivers/usb/serial/keyspan_usa28msg.h	Mon Dec 11 22:13:01 2000
+++ linux.19p18/drivers/usb/serial/keyspan_usa28msg.h	Tue Jan  9 11:56:23 2001
@@ -94,16 +94,8 @@
 #ifndef	__USA28MSG__
 #define	__USA28MSG__
 
-/*#ifndef STUBS
-#include "datadefs.h"
-#endif*/
 
-typedef struct txAckMessage
-{
-	u8	dummy;
-} txAckMessage;
-
-typedef struct portControlMessage
+typedef struct keyspan_usa28_portControlMessage
 {
 	/*
 		there are four types of "commands" sent in the control message:
@@ -153,9 +145,9 @@
 		returnStatus,	// return current status n times (1 or 2)
 		resetDataToggle;// reset data toggle state to DATA0
 	
-} portControlMessage;
+} keyspan_usa28_portControlMessage;
 
-typedef struct portStatusMessage
+typedef struct keyspan_usa28_portStatusMessage
 {
 	u8	port,			// 0=first, 1=second, 2=global (see below)
 		cts,
@@ -171,32 +163,32 @@
 		rxBreak,		// 1=we're in break state
 		rs232invalid,	// 1=no valid signals on rs-232 inputs
 		controlResponse;// 1=a control messages has been processed
-} portStatusMessage;
+} keyspan_usa28_portStatusMessage;
 
 // bit defines in txState
 #define	TX_OFF			0x01	// requested by host txOff command
 #define	TX_XOFF			0x02	// either real, or simulated by host
 
-typedef struct globalControlMessage
+typedef struct keyspan_usa28_globalControlMessage
 {
 	u8	sendGlobalStatus,	// 2=request for two status responses
 		resetStatusToggle,	// 1=reset global status toggle
 		resetStatusCount;	// a cycling value
-} globalControlMessage;
+} keyspan_usa28_globalControlMessage;
 
-typedef struct globalStatusMessage
+typedef struct keyspan_usa28_globalStatusMessage
 {
 	u8	port,				// 3
 		sendGlobalStatus,	// from request, decremented
 		resetStatusCount;	// as in request
-} globalStatusMessage;
+} keyspan_usa28_globalStatusMessage;
 
-typedef struct globalDebugMessage
+typedef struct keyspan_usa28_globalDebugMessage
 {
 	u8	port,				// 2
 		n,					// typically a count/status byte
 		b;					// typically a data byte
-} globalDebugMessage;
+} keyspan_usa28_globalDebugMessage;
 
 // ie: the maximum length of an EZUSB endpoint buffer
 #define	MAX_DATA_LEN			64
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/keyspan_usa49msg.h linux.19p18/drivers/usb/serial/keyspan_usa49msg.h
--- linux.vanilla/drivers/usb/serial/keyspan_usa49msg.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/usb/serial/keyspan_usa49msg.h	Tue Jan  9 11:56:23 2001
@@ -0,0 +1,255 @@
+/*
+	usa49msg.h
+
+	Copyright (c) 1998-2000 InnoSys Incorporated.  All Rights Reserved
+	This file is available under a BSD-style copyright
+
+	Keyspan USB Async Firmware to run on Anchor EZ-USB
+
+	Redistribution and use in source and binary forms, with or without
+	modification, are permitted provided that the following conditions are
+	met:
+
+	1. Redistributions of source code must retain this licence text
+   	without modification, this list of conditions, and the following
+   	disclaimer.  The following copyright notice must appear immediately at
+   	the beginning of all source files:
+
+        	Copyright (c) 1998-2000 InnoSys Incorporated.  All Rights Reserved
+
+        	This file is available under a BSD-style copyright
+
+	2. Redistributions in binary form must reproduce the above copyright
+   	notice, this list of conditions and the following disclaimer in the
+   	documentation and/or other materials provided with the distribution.
+
+	3. The name of InnoSys Incorprated may not be used to endorse or promote
+   	products derived from this software without specific prior written
+   	permission.
+
+	THIS SOFTWARE IS PROVIDED BY INNOSYS CORP. ``AS IS'' AND ANY EXPRESS OR
+	IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+	OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+	NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+	INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+	(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+	SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+	CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+	LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+	OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+	SUCH DAMAGE.    
+
+	4th revision: USA49W version
+
+	See usa26msg.h for description of message formats
+
+	Third revision: USA28X version (aka USA26)
+
+	Buffer formats for RX/TX data messages are not defined by
+	a structure, but are described here:
+
+	USB OUT (host -> USA26, transmit) messages contain a 
+	REQUEST_ACK indicator (set to 0xff to request an ACK at the 
+	completion of transmit; 0x00 otherwise), followed by data:
+
+		RQSTACK DAT DAT DAT ...
+
+	with a total data length of 63.
+
+	USB IN (USA26 -> host, receive) messages contain either a zero
+	flag (indicating no error in any data bytes):
+
+		00 DAT DAT DAT ...
+
+	for a total of 63 data bytes, or a non-zero status flag (indicating 
+	that all data bytes will be preceded by status flag):
+
+		STAT DAT STAT DAT STAT DAT ...
+
+	for a total of 32 data bytes.  The valid bits in the STAT bytes are:
+
+		OVERRUN	0x02
+		PARITY	0x04
+		FRAMING	0x08
+		BREAK	0x10
+
+	Notes:
+	
+	1.	a "no status" RX data message (first byte zero) can serve as
+		a "break off" indicator.
+	2.	a control message specifying disablePort will be answered
+		with a status message, but no further status will be sent
+		until a control messages with enablePort is sent
+
+	revision history:
+
+	1999feb10	add reportHskiaChanges to allow us to ignore them
+	1999feb10	add txAckThreshold for fast+loose throughput enhancement
+	1999mar30	beef up support for RX error reporting
+	1999apr14	add resetDataToggle to control message
+	2000jan04	merge with usa17msg.h
+	2000mar08	clone from usa26msg.h -> usa49msg.h
+	2000mar09	change to support 4 ports
+	2000may03	change external clocking to match USA-49W hardware
+	2000jun01	add extended BSD-style copyright text
+*/
+
+#ifndef	__USA49MSG__
+#define	__USA49MSG__
+
+
+/*
+	Host->device messages sent on the global control endpoint:
+
+	portNumber	message
+	----------	--------------------
+	0,1,2,3		portControlMessage
+	0x80		globalControlMessage
+*/
+
+typedef struct keyspan_usa49_portControlMessage
+{
+	/*
+		0.	0/1/2/3 	port control message follows
+			0x80 set	non-port control message follows
+	*/
+	u8	portNumber,
+
+	/*
+		there are three types of "commands" sent in the control message:
+
+		1.	configuration changes which must be requested by setting
+			the corresponding "set" flag (and should only be requested
+			when necessary, to reduce overhead on the USA26):
+	*/
+		setClocking,	// host requests baud rate be set
+		baudLo,			// host does baud divisor calculation
+		baudHi,			// baudHi is only used for first port (gives lower rates)
+		prescaler,		// specified as N/8; values 8-ff are valid
+						// must be set any time internal baud rate is set;
+		txClocking,		// 0=internal, 1=external/DSR
+		rxClocking,		// 0=internal, 1=external/DSR
+
+		setLcr,			// host requests lcr be set
+		lcr,			// use PARITY, STOPBITS, DATABITS below
+
+		setFlowControl,	// host requests flow control be set
+		ctsFlowControl,	// 1=use CTS flow control, 0=don't
+		xonFlowControl,	// 1=use XON/XOFF flow control, 0=don't
+		xonChar,		// specified in current character format
+		xoffChar,		// specified in current character format
+
+		setRts,			// host requests RTS output be set
+		rts,			// 1=active, 0=inactive
+
+		setDtr,			// host requests DTR output be set
+		dtr;			// 1=on, 0=off
+
+
+	/*
+		3.	configuration data which is simply used as is (no overhead,
+			but must be specified correctly in every host message).
+	*/
+	u8	forwardingLength,  // forward when this number of chars available
+		dsrFlowControl,	// 1=use DSR flow control, 0=don't
+		txAckThreshold,	// 0=not allowed, 1=normal, 2-255 deliver ACK faster
+		loopbackMode;	// 0=no loopback, 1=loopback enabled
+
+	/*
+		4.	commands which are flags only; these are processed in order
+			(so that, e.g., if both _txOn and _txOff flags are set, the
+			port ends in a TX_OFF state); any non-zero value is respected
+	*/
+	u8	_txOn,			// enable transmitting (and continue if there's data)
+		_txOff,			// stop transmitting
+		txFlush,		// toss outbound data
+		txBreak,		// turn on break (cleared by _txOn)
+		rxOn,			// turn on receiver
+		rxOff,			// turn off receiver
+		rxFlush,		// toss inbound data
+		rxForward,		// forward all inbound data, NOW (as if fwdLen==1)
+		returnStatus,	// return current status (even if it hasn't changed)
+		resetDataToggle,// reset data toggle state to DATA0
+		enablePort,		// start servicing port (move data, check status)
+		disablePort;	// stop servicing port (does implicit tx/rx flush/off)
+	
+} keyspan_usa49_portControlMessage;
+
+// defines for bits in lcr
+#define	USA_DATABITS_5		0x00
+#define	USA_DATABITS_6		0x01
+#define	USA_DATABITS_7		0x02
+#define	USA_DATABITS_8		0x03
+#define	STOPBITS_5678_1		0x00	// 1 stop bit for all byte sizes
+#define	STOPBITS_5_1p5		0x04	// 1.5 stop bits for 5-bit byte
+#define	STOPBITS_678_2		0x04	// 2 stop bits for 6/7/8-bit byte
+#define	USA_PARITY_NONE		0x00
+#define	USA_PARITY_ODD		0x08
+#define	USA_PARITY_EVEN		0x18
+#define	PARITY_1			0x28
+#define	PARITY_0			0x38
+
+typedef struct keyspan_usa49_globalControlMessage
+{
+	u8	portNumber,			// 0x80
+		sendGlobalStatus,	// 1/2=number of status responses requested
+		resetStatusToggle,	// 1=reset global status toggle
+		resetStatusCount,	// a cycling value
+		remoteWakeupEnable;	// 0x10=P1, 0x20=P2, 0x40=P3, 0x80=P3
+} keyspan_usa49_globalControlMessage;
+
+/*
+	Device->host messages send on the global status endpoint
+
+	portNumber			message
+	----------			--------------------
+	0x00,0x01,0x02,0x03	portStatusMessage
+	0x80				globalStatusMessage
+	0x81				globalDebugMessage
+*/
+
+typedef struct keyspan_usa49_portStatusMessage	// one for each port
+{
+	u8	portNumber,		// 0,1,2,3
+		cts,			// reports CTS pin
+		dcd,			// reports DCD pin
+		dsr,			// reports DSR pin
+		ri,				// reports RI pin
+		_txOff,			// transmit has been disabled (by host)
+		_txXoff,		// transmit is in XOFF state (either host or RX XOFF)
+		rxEnabled,		// as configured by rxOn/rxOff 1=on, 0=off
+		controlResponse,// 1=a control message has been processed
+		txAck,			// ACK (data TX complete)
+		rs232valid;		// RS-232 signal valid
+} keyspan_usa49_portStatusMessage;
+
+// bits in RX data message when STAT byte is included
+#define	RXERROR_OVERRUN	0x02
+#define	RXERROR_PARITY	0x04
+#define	RXERROR_FRAMING	0x08
+#define	RXERROR_BREAK	0x10
+
+typedef struct keyspan_usa49_globalStatusMessage
+{
+	u8	portNumber,			// 0x80=globalStatusMessage
+		sendGlobalStatus,	// from request, decremented
+		resetStatusCount;	// as in request
+} keyspan_usa49_globalStatusMessage;
+
+typedef struct keyspan_usa49_globalDebugMessage
+{
+	u8	portNumber,			// 0x81=globalDebugMessage
+		n,					// typically a count/status byte
+		b;					// typically a data byte
+} keyspan_usa49_globalDebugMessage;
+
+// ie: the maximum length of an EZUSB endpoint buffer
+#define	MAX_DATA_LEN			64
+
+// update status approx. 60 times a second (16.6666 ms)
+#define	STATUS_UPDATE_INTERVAL	16
+
+// status rationing tuning value (each port gets checked each n ms)
+#define	STATUS_RATION	10
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/keyspan_usa49w_fw.h linux.19p18/drivers/usb/serial/keyspan_usa49w_fw.h
--- linux.vanilla/drivers/usb/serial/keyspan_usa49w_fw.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/drivers/usb/serial/keyspan_usa49w_fw.h	Tue Jan  9 11:56:23 2001
@@ -0,0 +1,457 @@
+/* keyspan_usa49w_fw.h
+  
+   Generated from Keyspan firmware image Thu Sep 28 09:13:26 2000 EST
+   This firmware is for the Keyspan USA-49W Serial Adaptor
+
+   "The firmware contained herein as keyspan_usa49w_fw.h is
+   Copyright (C) 1999-2000 Keyspan, A division of InnoSys Incorporated
+   ("Keyspan"), as an unpublished work.  This notice does not imply
+   unrestricted or public access to this firmware which is a trade secret of
+   Keyspan, and which may not be reproduced, used, sold or transferred to any
+   third party without Keyspan's prior written consent.  All Rights Reserved.
+
+   This firmware may not be modified and may only be used with the Keyspan 
+   USA-49W Serial Adapter.  Distribution and/or Modification of the
+   keyspan.c driver which includes this firmware, in whole or in part,
+   requires the inclusion of this statement."
+
+*/
+
+static const struct ezusb_hex_record keyspan_usa49w_firmware[] = {
+{ 0x0000,	3,	{0x02, 0x10, 0x36} },
+{ 0x0003,	16,	{0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x78, 0x41, 0x74} },
+{ 0x0013,	16,	{0x01, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x27, 0x24} },
+{ 0x0023,	16,	{0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x0033,	3,	{0x02, 0x17, 0xf0} },
+{ 0x0036,	12,	{0x90, 0x78, 0x41, 0x74, 0x01, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x0043,	3,	{0x02, 0x18, 0x00} },
+{ 0x0046,	16,	{0xe4, 0xff, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xe0, 0xfe, 0xe5, 0x27} },
+{ 0x0056,	16,	{0x24, 0x04, 0xfd, 0xe4, 0x35, 0x26, 0xfa, 0xa9, 0x05, 0x7b, 0x01, 0xef, 0x7c, 0x00, 0x29, 0xf9} },
+{ 0x0066,	16,	{0xec, 0x3a, 0xfa, 0xee, 0x12, 0x11, 0x90, 0x0f, 0xbf, 0x22, 0xd7, 0xe5, 0x27, 0x24, 0x05, 0xf5} },
+{ 0x0076,	16,	{0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x70, 0x03, 0x02, 0x01, 0x4f, 0x7f, 0x01, 0xe5, 0x27} },
+{ 0x0086,	16,	{0x24, 0x08, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xfd, 0x12, 0x15, 0x3d, 0xe5, 0x27} },
+{ 0x0096,	16,	{0x24, 0x06, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xff, 0x12, 0x15, 0x6c, 0xe5, 0x27} },
+{ 0x00a6,	16,	{0x24, 0x07, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xff, 0x12, 0x00, 0x03, 0xe5, 0x27} },
+{ 0x00b6,	16,	{0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x30, 0xf0, 0x7d, 0x04, 0x44} },
+{ 0x00c6,	16,	{0x20, 0xf0, 0xe5, 0x27, 0x24, 0x09, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x12} },
+{ 0x00d6,	16,	{0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0xdf, 0xf0, 0x43} },
+{ 0x00e6,	16,	{0x05, 0xc0, 0xe5, 0x27, 0x24, 0x0a, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x14} },
+{ 0x00f6,	16,	{0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0xdf, 0xf0, 0x43} },
+{ 0x0106,	16,	{0x05, 0x0b, 0x80, 0x03, 0x43, 0x05, 0x02, 0x7f, 0x03, 0x12, 0x15, 0x3d, 0xe5, 0x27, 0x24, 0x39} },
+{ 0x0116,	16,	{0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x04} },
+{ 0x0126,	16,	{0xf0, 0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x90, 0xc0, 0x00} },
+{ 0x0136,	16,	{0xf0, 0x90, 0x78, 0x41, 0x74, 0x02, 0xf0, 0xe5, 0x27, 0x24, 0x36, 0xf5, 0x82, 0xe4, 0x35, 0x26} },
+{ 0x0146,	16,	{0xf5, 0x83, 0xe0, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x27, 0x24, 0x0b, 0xf5, 0x82, 0xe4} },
+{ 0x0156,	16,	{0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x32, 0xe5, 0x27, 0x24, 0x0c, 0xf5, 0x82, 0xe4, 0x35, 0x26} },
+{ 0x0166,	16,	{0xf5, 0x83, 0xe0, 0x54, 0x3f, 0xff, 0xe5, 0x27, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} },
+{ 0x0176,	16,	{0x83, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x27, 0x24, 0x37, 0xf5, 0x82, 0xe4} },
+{ 0x0186,	16,	{0x35, 0x26, 0xf5, 0x83, 0xe0, 0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x27, 0x24, 0x0d, 0xf5, 0x82, 0xe4} },
+{ 0x0196,	16,	{0x35, 0x26, 0xf5, 0x83, 0xe0, 0x70, 0x03, 0x02, 0x02, 0x6a, 0xe5, 0x27, 0x24, 0x17, 0xf5, 0x82} },
+{ 0x01a6,	16,	{0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x11, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x01b6,	16,	{0x26, 0xf5, 0x83, 0xe0, 0x44, 0x04, 0xf0, 0x80, 0x0f, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82, 0xe4} },
+{ 0x01c6,	16,	{0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0xfb, 0xf0, 0xe4, 0xff, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82} },
+{ 0x01d6,	16,	{0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xfd, 0x12, 0x15, 0x3d, 0xe5, 0x27, 0x24, 0x0e, 0xf5, 0x82} },
+{ 0x01e6,	16,	{0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x11, 0xe5, 0x27, 0x24, 0x33, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x01f6,	16,	{0x26, 0xf5, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x0f, 0xe5, 0x27, 0x24, 0x33, 0xf5, 0x82, 0xe4} },
+{ 0x0206,	16,	{0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0xf0, 0xe5, 0x27, 0x24, 0x33, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x0216,	16,	{0x26, 0xf5, 0x83, 0xe0, 0x54, 0xfc, 0xf0, 0xe5, 0x27, 0x24, 0x0f, 0xf5, 0x82, 0xe4, 0x35, 0x26} },
+{ 0x0226,	16,	{0xf5, 0x83, 0xe0, 0x60, 0x2f, 0xe5, 0x27, 0x24, 0x33, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83} },
+{ 0x0236,	16,	{0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x27, 0x24, 0x10, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} },
+{ 0x0246,	16,	{0xff, 0x12, 0x14, 0xdd, 0xe5, 0x27, 0x24, 0x11, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} },
+{ 0x0256,	16,	{0xff, 0x12, 0x15, 0x0d, 0xe5, 0x27, 0x24, 0x33, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} },
+{ 0x0266,	16,	{0xff, 0x12, 0x14, 0xad, 0xe5, 0x27, 0x24, 0x14, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} },
+{ 0x0276,	16,	{0x60, 0x44, 0xe5, 0x27, 0x24, 0x15, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x11} },
+{ 0x0286,	16,	{0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x01, 0xf0, 0x80} },
+{ 0x0296,	16,	{0x0f, 0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0xfe, 0xf0} },
+{ 0x02a6,	16,	{0x90, 0x78, 0x41, 0x74, 0x04, 0xf0, 0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} },
+{ 0x02b6,	16,	{0x83, 0xe0, 0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x27, 0x24, 0x12, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} },
+{ 0x02c6,	16,	{0x83, 0xe0, 0x60, 0x44, 0xe5, 0x27, 0x24, 0x13, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} },
+{ 0x02d6,	16,	{0x60, 0x11, 0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x02} },
+{ 0x02e6,	16,	{0xf0, 0x80, 0x0f, 0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54} },
+{ 0x02f6,	16,	{0xfd, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x04, 0xf0, 0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x0306,	16,	{0x26, 0xf5, 0x83, 0xe0, 0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x27, 0x24, 0x16, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x0316,	16,	{0x26, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x27, 0x24, 0x35, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83} },
+{ 0x0326,	16,	{0xef, 0xf0, 0xe5, 0x27, 0x24, 0x17, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x30, 0xe0} },
+{ 0x0336,	16,	{0x11, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x40, 0xf0} },
+{ 0x0346,	16,	{0x80, 0x0f, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0xbf} },
+{ 0x0356,	16,	{0xf0, 0xe5, 0x27, 0x24, 0x18, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x27} },
+{ 0x0366,	16,	{0x24, 0x3b, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xef, 0xf0, 0xe5, 0x27, 0x24, 0x19, 0xf5} },
+{ 0x0376,	16,	{0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x11, 0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4} },
+{ 0x0386,	16,	{0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x10, 0xf0, 0x80, 0x0f, 0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82} },
+{ 0x0396,	16,	{0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x04, 0xf0, 0xe5} },
+{ 0x03a6,	16,	{0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x90, 0xc0, 0x00, 0xf0, 0xe5} },
+{ 0x03b6,	16,	{0x27, 0x24, 0x1a, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x6b, 0xe5, 0x27, 0x24} },
+{ 0x03c6,	16,	{0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x78, 0x41, 0x74} },
+{ 0x03d6,	16,	{0x03, 0xf0, 0xe5, 0x27, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x7f} },
+{ 0x03e6,	16,	{0x90, 0xc0, 0x00, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x01, 0xf0, 0x12, 0x00, 0x36, 0xef, 0x54, 0xfe} },
+{ 0x03f6,	16,	{0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} },
+{ 0x0406,	16,	{0x54, 0xfd, 0xff, 0xf0, 0xfd, 0xe4, 0xff, 0x12, 0x15, 0x3d, 0xe5, 0x27, 0x24, 0x2c, 0xf5, 0x82} },
+{ 0x0416,	16,	{0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x27, 0x24, 0x2b, 0xf5, 0x82, 0xe4, 0x35, 0x26} },
+{ 0x0426,	16,	{0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x28, 0x42, 0x25, 0xe5, 0x27, 0x24, 0x1b, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x0436,	16,	{0x26, 0xf5, 0x83, 0xe0, 0x70, 0x0e, 0xe5, 0x27, 0x24, 0x25, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} },
+{ 0x0446,	16,	{0x83, 0xe0, 0x60, 0x28, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} },
+{ 0x0456,	16,	{0x44, 0x02, 0xff, 0xf0, 0xfd, 0xe4, 0xff, 0x12, 0x15, 0x3d, 0xe5, 0x27, 0x24, 0x2b, 0xf5, 0x82} },
+{ 0x0466,	16,	{0xe4, 0x35, 0x26, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0xe5, 0x28, 0x42, 0x25, 0xe5, 0x27, 0x24, 0x1c} },
+{ 0x0476,	16,	{0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x70, 0x0e, 0xe5, 0x27, 0x24, 0x25, 0xf5, 0x82} },
+{ 0x0486,	16,	{0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x2c, 0x90, 0x78, 0x41, 0x74, 0x02, 0xf0, 0xe5, 0x27} },
+{ 0x0496,	16,	{0x24, 0x36, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x04, 0x90, 0xc0, 0x00, 0xf0} },
+{ 0x04a6,	16,	{0xe4, 0xff, 0x12, 0x14, 0x0c, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83} },
+{ 0x04b6,	16,	{0xe0, 0x54, 0x7f, 0xf0, 0xe5, 0x27, 0x24, 0x1d, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} },
+{ 0x04c6,	16,	{0x60, 0x27, 0xe5, 0x27, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x40} },
+{ 0x04d6,	16,	{0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x27, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26} },
+{ 0x04e6,	16,	{0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x27, 0x24, 0x1e, 0xf5, 0x82, 0xe4} },
+{ 0x04f6,	16,	{0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x28, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x26} },
+{ 0x0506,	16,	{0xf5, 0x83, 0xe0, 0x54, 0xfe, 0xff, 0xf0, 0xfd, 0xe4, 0xff, 0x12, 0x15, 0x3d, 0xe5, 0x27, 0x24} },
+{ 0x0516,	16,	{0x2d, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0xe5, 0x28, 0x42, 0x25, 0xe5} },
+{ 0x0526,	16,	{0x27, 0x24, 0x1f, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x70, 0x0e, 0xe5, 0x27, 0x24} },
+{ 0x0536,	16,	{0x25, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x27, 0xe5, 0x27, 0x24, 0x32, 0xf5} },
+{ 0x0546,	16,	{0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x01, 0xff, 0xf0, 0xfd, 0xe4, 0xff, 0x12, 0x15} },
+{ 0x0556,	16,	{0x3d, 0xe5, 0x27, 0x24, 0x2d, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x28} },
+{ 0x0566,	16,	{0x42, 0x25, 0xe5, 0x27, 0x24, 0x20, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x70, 0x0e} },
+{ 0x0576,	16,	{0xe5, 0x27, 0x24, 0x25, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x18, 0x90, 0x78} },
+{ 0x0586,	16,	{0x41, 0x74, 0x02, 0xf0, 0xe5, 0x27, 0x24, 0x36, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} },
+{ 0x0596,	16,	{0x44, 0x02, 0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x27, 0x24, 0x21, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} },
+{ 0x05a6,	16,	{0x83, 0xe0, 0x60, 0x0f, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} },
+{ 0x05b6,	16,	{0x44, 0x02, 0xf0, 0xe5, 0x27, 0x24, 0x22, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60} },
+{ 0x05c6,	16,	{0x1f, 0xe5, 0x27, 0x24, 0x2e, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0xe5} },
+{ 0x05d6,	16,	{0x27, 0x24, 0x3a, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x28, 0x42, 0x25} },
+{ 0x05e6,	16,	{0xe5, 0x27, 0x24, 0x23, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x03, 0x12, 0x17} },
+{ 0x05f6,	16,	{0x4e, 0xe5, 0x27, 0x24, 0x24, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x1b, 0xe5} },
+{ 0x0606,	16,	{0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x08, 0xf0, 0x90, 0x7f} },
+{ 0x0616,	16,	{0x98, 0xe0, 0xff, 0xe5, 0x28, 0xf4, 0xfe, 0xef, 0x5e, 0xf0, 0xe5, 0x27, 0x24, 0x25, 0xf5, 0x82} },
+{ 0x0626,	16,	{0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x16, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x0636,	14,	{0x26, 0xf5, 0x83, 0xe0, 0x54, 0xf7, 0xf0, 0x90, 0x7f, 0x98, 0xe0, 0x45, 0x28, 0xf0} },
+{ 0x0644,	1,	{0x22} },
+{ 0x0645,	16,	{0x90, 0x7f, 0xe9, 0xe0, 0x12, 0x11, 0xa2, 0x07, 0x42, 0x00, 0x07, 0xb6, 0x01, 0x08, 0x22, 0x03} },
+{ 0x0655,	16,	{0x06, 0x68, 0x06, 0x07, 0x35, 0x08, 0x07, 0x2f, 0x09, 0x07, 0x17, 0x0a, 0x07, 0x26, 0x0b, 0x00} },
+{ 0x0665,	16,	{0x00, 0x08, 0x71, 0x90, 0x7f, 0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x19, 0x14, 0x60, 0x77, 0x24, 0x02} },
+{ 0x0675,	16,	{0x60, 0x03, 0x02, 0x07, 0x0d, 0x74, 0x19, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90, 0x7f, 0xd5} },
+{ 0x0685,	16,	{0xf0, 0x02, 0x08, 0x78, 0x90, 0x7f, 0xea, 0xe0, 0x04, 0x75, 0x82, 0x17, 0x75, 0x83, 0x19, 0xf0} },
+{ 0x0695,	16,	{0x90, 0x7f, 0xea, 0xe0, 0x30, 0xe0, 0x04, 0x7f, 0x03, 0x80, 0x02, 0x7f, 0x02, 0x75, 0x82, 0x82} },
+{ 0x06a5,	16,	{0x75, 0x83, 0x19, 0xef, 0xf0, 0x75, 0x82, 0x6d, 0x75, 0x83, 0x19, 0xf0, 0x75, 0x82, 0x66, 0x75} },
+{ 0x06b5,	16,	{0x83, 0x19, 0xf0, 0x75, 0x82, 0x5f, 0x75, 0x83, 0x19, 0xf0, 0x75, 0x82, 0x58, 0x75, 0x83, 0x19} },
+{ 0x06c5,	16,	{0xf0, 0x90, 0x7f, 0xea, 0xe0, 0x30, 0xe1, 0x04, 0x7f, 0x64, 0x80, 0x02, 0x7f, 0x32, 0x75, 0x82} },
+{ 0x06d5,	16,	{0x1a, 0x75, 0x83, 0x19, 0xef, 0xf0, 0x74, 0x19, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x12, 0x90, 0x7f} },
+{ 0x06e5,	16,	{0xd5, 0xf0, 0x02, 0x08, 0x78, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x13, 0x54, 0xea, 0x49, 0x60} },
+{ 0x06f5,	16,	{0x0d, 0xea, 0x90, 0x7f, 0xd4, 0xf0, 0xe9, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x08, 0x78, 0x90, 0x7f} },
+{ 0x0705,	16,	{0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x08, 0x78, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02} },
+{ 0x0715,	16,	{0x08, 0x78, 0x90, 0x7f, 0x00, 0xe5, 0x0a, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x02, 0x08} },
+{ 0x0725,	16,	{0x78, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x0a, 0x02, 0x08, 0x78, 0x12, 0x0a, 0x6a, 0x02, 0x08, 0x78} },
+{ 0x0735,	16,	{0x90, 0x7f, 0x00, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb5, 0xf0, 0x02, 0x08, 0x78, 0x90, 0x7f, 0xe8} },
+{ 0x0745,	16,	{0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31, 0x24, 0x02, 0x70, 0x5b, 0xa2, 0x00, 0xe4, 0x33} },
+{ 0x0755,	16,	{0xff, 0x25, 0xe0, 0xff, 0xa2, 0x06, 0xe4, 0x33, 0x4f, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0} },
+{ 0x0765,	16,	{0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x08, 0x78, 0xe4, 0x90, 0x7f, 0x00, 0xf0, 0xa3, 0xf0} },
+{ 0x0775,	16,	{0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x08, 0x78, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80} },
+{ 0x0785,	16,	{0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4} },
+{ 0x0795,	16,	{0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f} },
+{ 0x07a5,	16,	{0xb5, 0x74, 0x02, 0xf0, 0x02, 0x08, 0x78, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x08} },
+{ 0x07b5,	16,	{0x78, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x1d, 0x24, 0x02, 0x60, 0x03, 0x02, 0x08, 0x78} },
+{ 0x07c5,	16,	{0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x05, 0xc2, 0x00, 0x02, 0x08, 0x78, 0x90, 0x7f, 0xb4, 0xe0} },
+{ 0x07d5,	16,	{0x44, 0x01, 0xf0, 0x02, 0x08, 0x78, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x38, 0x90, 0x7f, 0xec, 0xe0} },
+{ 0x07e5,	16,	{0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4} },
+{ 0x07f5,	16,	{0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x7f, 0xec, 0xe0, 0x54, 0x80, 0xff} },
+{ 0x0805,	16,	{0x13, 0x13, 0x13, 0x54, 0x1f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x90, 0x7f, 0xd7, 0xf0, 0xe0, 0x44} },
+{ 0x0815,	16,	{0x20, 0xf0, 0x80, 0x5f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x56, 0x90, 0x7f, 0xe8} },
+{ 0x0825,	16,	{0xe0, 0x24, 0xfe, 0x60, 0x18, 0x24, 0x02, 0x70, 0x4a, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x04} },
+{ 0x0835,	16,	{0xd2, 0x00, 0x80, 0x3f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x36, 0x90, 0x7f, 0xea} },
+{ 0x0845,	16,	{0xe0, 0x70, 0x20, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0} },
+{ 0x0855,	16,	{0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01} },
+{ 0x0865,	16,	{0xf0, 0x80, 0x10, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x07, 0x90, 0x7f, 0xb4, 0xe0} },
+{ 0x0875,	10,	{0x44, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0} },
+{ 0x087f,	1,	{0x22} },
+{ 0x0880,	16,	{0xe5, 0x23, 0x54, 0x0f, 0x70, 0x03, 0x02, 0x09, 0x5f, 0x12, 0x15, 0x9b, 0xef, 0x20, 0xe1, 0x63} },
+{ 0x0890,	16,	{0x12, 0x15, 0xf9, 0xef, 0x14, 0xf5, 0x1a, 0x12, 0x17, 0xc1, 0xef, 0x25, 0x1a, 0xff, 0xe4, 0x33} },
+{ 0x08a0,	16,	{0xfe, 0xc3, 0xef, 0x94, 0x80, 0xee, 0x64, 0x80, 0x94, 0x80, 0x50, 0x47, 0x85, 0x27, 0x82, 0x85} },
+{ 0x08b0,	16,	{0x26, 0x83, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xf5, 0x82, 0x8e, 0x83, 0xe0, 0x30, 0xe0, 0x11, 0xe5} },
+{ 0x08c0,	16,	{0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x0f} },
+{ 0x08d0,	16,	{0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0xf0, 0x85} },
+{ 0x08e0,	16,	{0x1a, 0x08, 0xef, 0x24, 0x01, 0xf5, 0x10, 0xe4, 0x3e, 0xf5, 0x0f, 0x12, 0x13, 0xd6, 0xe4, 0xff} },
+{ 0x08f0,	16,	{0x12, 0x14, 0x0c, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x30} },
+{ 0x0900,	16,	{0xe7, 0x5d, 0x12, 0x17, 0xc1, 0xe5, 0x27, 0x24, 0x3b, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83} },
+{ 0x0910,	16,	{0xe0, 0xfe, 0xef, 0xc3, 0x9e, 0x50, 0x48, 0xe5, 0x27, 0x24, 0x2f, 0xf5, 0x82, 0xe4, 0x35, 0x26} },
+{ 0x0920,	16,	{0xf5, 0x83, 0x74, 0x01, 0xf0, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83} },
+{ 0x0930,	16,	{0xe0, 0x54, 0x7f, 0xf0, 0xe5, 0x27, 0x24, 0x3a, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe4} },
+{ 0x0940,	16,	{0xf0, 0xe5, 0x28, 0x42, 0x25, 0x90, 0x7f, 0xc2, 0xe0, 0x30, 0xe1, 0x10, 0xe5, 0x27, 0x24, 0x26} },
+{ 0x0950,	16,	{0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xf5, 0x09, 0x80, 0x03, 0x12, 0x12, 0x3d, 0x12} },
+{ 0x0960,	16,	{0x15, 0xca, 0xef, 0x30, 0xe1, 0x03, 0x02, 0x0a, 0x69, 0xe5, 0x27, 0x24, 0x38, 0xf5, 0x82, 0xe4} },
+{ 0x0970,	16,	{0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x80, 0xf0, 0xe5, 0x27, 0x24, 0x38, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x0980,	16,	{0x26, 0xf5, 0x83, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfe, 0x12, 0x17, 0xcd, 0xee, 0x4f, 0xd0, 0x82} },
+{ 0x0990,	16,	{0xd0, 0x83, 0xf0, 0x12, 0x16, 0xd1, 0x8f, 0x1a, 0xe5, 0x27, 0x24, 0x35, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x09a0,	16,	{0x26, 0xf5, 0x83, 0xe0, 0xfe, 0xef, 0xc3, 0x9e, 0x50, 0x28, 0x12, 0x17, 0xa9, 0xef, 0x30, 0xe0} },
+{ 0x09b0,	16,	{0x21, 0xe5, 0x27, 0x24, 0x38, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x20, 0xe7, 0x12} },
+{ 0x09c0,	16,	{0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x20, 0xe1, 0x03, 0x02} },
+{ 0x09d0,	16,	{0x0a, 0x69, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0xfd} },
+{ 0x09e0,	16,	{0xf0, 0xe5, 0x1a, 0x70, 0x0e, 0xe5, 0x27, 0x24, 0x38, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83} },
+{ 0x09f0,	16,	{0xe4, 0xf0, 0x22, 0xe5, 0x27, 0x24, 0x38, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xff} },
+{ 0x0a00,	16,	{0x30, 0xe7, 0x29, 0xe5, 0x1a, 0xd3, 0x94, 0x20, 0x40, 0x03, 0x75, 0x1a, 0x20, 0x85, 0x1a, 0x08} },
+{ 0x0a10,	16,	{0x85, 0x27, 0x82, 0x85, 0x26, 0x83, 0xa3, 0xa3, 0xe0, 0xfc, 0xa3, 0xe0, 0x8c, 0x0f, 0xf5, 0x10} },
+{ 0x0a20,	16,	{0x12, 0x13, 0x06, 0xe5, 0x1a, 0x25, 0xe0, 0xff, 0x12, 0x14, 0x42, 0x22, 0xe5, 0x1a, 0xd3, 0x94} },
+{ 0x0a30,	16,	{0x3f, 0x40, 0x03, 0x75, 0x1a, 0x3f, 0x85, 0x1a, 0x08, 0x85, 0x27, 0x82, 0x85, 0x26, 0x83, 0xa3} },
+{ 0x0a40,	16,	{0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xf5, 0x82, 0x8e, 0x83, 0xe4, 0xf0, 0x85, 0x27, 0x82, 0x85, 0x26} },
+{ 0x0a50,	16,	{0x83, 0xa3, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0x24, 0x01, 0xf5, 0x10, 0xe4, 0x3e, 0xf5, 0x0f, 0x12} },
+{ 0x0a60,	9,	{0x13, 0x95, 0xe5, 0x1a, 0x04, 0xff, 0x12, 0x14, 0x42} },
+{ 0x0a69,	1,	{0x22} },
+{ 0x0a6a,	16,	{0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0xf0, 0xf0, 0x90, 0x7f, 0x96, 0xf0, 0xe4} },
+{ 0x0a7a,	16,	{0x90, 0x7f, 0x94, 0xf0, 0x90, 0x78, 0x4a, 0x04, 0xf0, 0xf5, 0x8e, 0x90, 0x7f, 0x95, 0x74, 0xc0} },
+{ 0x0a8a,	16,	{0xf0, 0x90, 0x7f, 0x9e, 0x74, 0x3f, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x1f, 0xf0, 0x90, 0x78, 0x43} },
+{ 0x0a9a,	16,	{0x74, 0xff, 0xf0, 0xe4, 0x90, 0x78, 0x41, 0xf0, 0x90, 0x7f, 0xdf, 0x74, 0x9f, 0xf0, 0x90, 0x7f} },
+{ 0x0aaa,	16,	{0xde, 0xf0, 0x90, 0x7f, 0x92, 0xe0, 0x44, 0x02, 0xf0, 0x7e, 0x7b, 0x7f, 0xc0, 0x75, 0x26, 0x7b} },
+{ 0x0aba,	16,	{0x75, 0x27, 0xc0, 0x90, 0x7f, 0x96, 0x74, 0xef, 0xf0, 0x75, 0x28, 0x01, 0x12, 0x0e, 0xb3, 0x7e} },
+{ 0x0aca,	16,	{0x7b, 0x7f, 0xc0, 0x75, 0x26, 0x7b, 0x75, 0x27, 0xc0, 0x90, 0x7f, 0x96, 0x74, 0xef, 0xf0, 0x75} },
+{ 0x0ada,	16,	{0x28, 0x01, 0xe5, 0x27, 0x24, 0x26, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe4, 0xf0, 0x7e} },
+{ 0x0aea,	16,	{0x7e, 0x7f, 0x40, 0x85, 0x27, 0x82, 0x85, 0x26, 0x83, 0x74, 0x7e, 0xf0, 0xa3, 0x74, 0x40, 0xf0} },
+{ 0x0afa,	16,	{0x7e, 0x7e, 0x7f, 0x80, 0x85, 0x27, 0x82, 0x85, 0x26, 0x83, 0xa3, 0xa3, 0x74, 0x7e, 0xf0, 0xa3} },
+{ 0x0b0a,	16,	{0x74, 0x80, 0xf0, 0x7e, 0x7c, 0x7f, 0x00, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x00, 0x90, 0x7f, 0x96} },
+{ 0x0b1a,	16,	{0x74, 0xdf, 0xf0, 0x75, 0x28, 0x02, 0x12, 0x0e, 0xb3, 0x7e, 0x7c, 0x7f, 0x00, 0x75, 0x26, 0x7c} },
+{ 0x0b2a,	16,	{0x75, 0x27, 0x00, 0x90, 0x7f, 0x96, 0x74, 0xdf, 0xf0, 0x75, 0x28, 0x02, 0xe5, 0x27, 0x24, 0x26} },
+{ 0x0b3a,	16,	{0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x7e, 0x7d, 0x7f, 0xc0, 0x85, 0x27} },
+{ 0x0b4a,	16,	{0x82, 0x85, 0x26, 0x83, 0x74, 0x7d, 0xf0, 0xa3, 0x74, 0xc0, 0xf0, 0x7e, 0x7e, 0x7f, 0x00, 0x85} },
+{ 0x0b5a,	16,	{0x27, 0x82, 0x85, 0x26, 0x83, 0xa3, 0xa3, 0x74, 0x7e, 0xf0, 0xa3, 0x74, 0x00, 0xf0, 0x7e, 0x7c} },
+{ 0x0b6a,	16,	{0x7f, 0x40, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x40, 0x90, 0x7f, 0x96, 0x74, 0xbf, 0xf0, 0x75, 0x28} },
+{ 0x0b7a,	16,	{0x04, 0x12, 0x0e, 0xb3, 0x7e, 0x7c, 0x7f, 0x40, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x40, 0x90, 0x7f} },
+{ 0x0b8a,	16,	{0x96, 0x74, 0xbf, 0xf0, 0x75, 0x28, 0x04, 0xe5, 0x27, 0x24, 0x26, 0xf5, 0x82, 0xe4, 0x35, 0x26} },
+{ 0x0b9a,	16,	{0xf5, 0x83, 0x74, 0x02, 0xf0, 0x7e, 0x7d, 0x7f, 0x40, 0x85, 0x27, 0x82, 0x85, 0x26, 0x83, 0x74} },
+{ 0x0baa,	16,	{0x7d, 0xf0, 0xa3, 0x74, 0x40, 0xf0, 0x7e, 0x7d, 0x7f, 0x80, 0x85, 0x27, 0x82, 0x85, 0x26, 0x83} },
+{ 0x0bba,	16,	{0xa3, 0xa3, 0x74, 0x7d, 0xf0, 0xa3, 0x74, 0x80, 0xf0, 0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x26, 0x7c} },
+{ 0x0bca,	16,	{0x75, 0x27, 0x80, 0x90, 0x7f, 0x96, 0x74, 0x7f, 0xf0, 0x75, 0x28, 0x08, 0x12, 0x0e, 0xb3, 0x7e} },
+{ 0x0bda,	16,	{0x7c, 0x7f, 0x80, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x80, 0x90, 0x7f, 0x96, 0x74, 0x7f, 0xf0, 0x75} },
+{ 0x0bea,	16,	{0x28, 0x08, 0xe5, 0x27, 0x24, 0x26, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0x74, 0x03, 0xf0} },
+{ 0x0bfa,	16,	{0x7e, 0x7c, 0x7f, 0xc0, 0x85, 0x27, 0x82, 0x85, 0x26, 0x83, 0x74, 0x7c, 0xf0, 0xa3, 0x74, 0xc0} },
+{ 0x0c0a,	16,	{0xf0, 0x7e, 0x7d, 0x7f, 0x00, 0x85, 0x27, 0x82, 0x85, 0x26, 0x83, 0xa3, 0xa3, 0x74, 0x7d, 0xf0} },
+{ 0x0c1a,	7,	{0xa3, 0x74, 0x00, 0xf0, 0xd2, 0x02, 0x22} },
+{ 0x0c21,	16,	{0xe5, 0x22, 0x04, 0x54, 0x03, 0xf5, 0x22, 0x14, 0x60, 0x1f, 0x14, 0x60, 0x31, 0x14, 0x60, 0x43} },
+{ 0x0c31,	16,	{0x24, 0x03, 0x70, 0x52, 0x7e, 0x7b, 0x7f, 0xc0, 0x75, 0x26, 0x7b, 0x75, 0x27, 0xc0, 0x90, 0x7f} },
+{ 0x0c41,	16,	{0x96, 0x74, 0xef, 0xf0, 0x75, 0x28, 0x01, 0x80, 0x3d, 0x7e, 0x7c, 0x7f, 0x00, 0x75, 0x26, 0x7c} },
+{ 0x0c51,	16,	{0x75, 0x27, 0x00, 0x90, 0x7f, 0x96, 0x74, 0xdf, 0xf0, 0x75, 0x28, 0x02, 0x80, 0x28, 0x7e, 0x7c} },
+{ 0x0c61,	16,	{0x7f, 0x40, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x40, 0x90, 0x7f, 0x96, 0x74, 0xbf, 0xf0, 0x75, 0x28} },
+{ 0x0c71,	16,	{0x04, 0x80, 0x13, 0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x80, 0x90, 0x7f, 0x96} },
+{ 0x0c81,	16,	{0x74, 0x7f, 0xf0, 0x75, 0x28, 0x08, 0xe5, 0x15, 0x55, 0x28, 0x70, 0x03, 0x02, 0x0d, 0xbf, 0xe5} },
+{ 0x0c91,	16,	{0x28, 0xf4, 0xff, 0x52, 0x15, 0xe5, 0x0b, 0x54, 0x7f, 0xfe, 0x70, 0x0f, 0xe5, 0x0d, 0x55, 0x28} },
+{ 0x0ca1,	16,	{0x60, 0x24, 0x90, 0x7f, 0x98, 0xe0, 0x45, 0x28, 0xf0, 0x80, 0x1b, 0xbe, 0x20, 0x18, 0xe5, 0x27} },
+{ 0x0cb1,	16,	{0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x30, 0xe3, 0x09, 0xe4, 0xf5, 0x0d} },
+{ 0x0cc1,	16,	{0x90, 0x7f, 0x98, 0xe0, 0x5f, 0xf0, 0xe5, 0x27, 0x24, 0x3a, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} },
+{ 0x0cd1,	16,	{0x83, 0xe0, 0x60, 0x03, 0xe0, 0x14, 0xf0, 0xe5, 0x27, 0x24, 0x34, 0xf5, 0x82, 0xe4, 0x35, 0x26} },
+{ 0x0ce1,	16,	{0xf5, 0x83, 0xe0, 0x60, 0x03, 0xe0, 0x14, 0xf0, 0xe0, 0x60, 0x03, 0x02, 0x0d, 0xbf, 0x74, 0x0a} },
+{ 0x0cf1,	16,	{0xf0, 0x12, 0x00, 0x36, 0xef, 0x54, 0x01, 0xff, 0xf5, 0x1a, 0xe5, 0x27, 0x24, 0x2c, 0xf5, 0x82} },
+{ 0x0d01,	16,	{0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x6f, 0x60, 0x07, 0xe5, 0x1a, 0xf0, 0xe5, 0x28, 0x42, 0x25} },
+{ 0x0d11,	16,	{0x12, 0x17, 0xd9, 0x8f, 0x1a, 0xe5, 0x27, 0x24, 0x27, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83} },
+{ 0x0d21,	16,	{0xe0, 0xff, 0xe5, 0x1a, 0x54, 0x10, 0xfe, 0x6f, 0x60, 0x06, 0xee, 0xf0, 0xe5, 0x28, 0x42, 0x25} },
+{ 0x0d31,	16,	{0xe5, 0x27, 0x24, 0x28, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x1a, 0x54} },
+{ 0x0d41,	16,	{0x80, 0xfe, 0x6f, 0x60, 0x06, 0xee, 0xf0, 0xe5, 0x28, 0x42, 0x25, 0xe5, 0x27, 0x24, 0x29, 0xf5} },
+{ 0x0d51,	16,	{0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x1a, 0x54, 0x20, 0xfe, 0x6f, 0x60, 0x15} },
+{ 0x0d61,	16,	{0xee, 0xf0, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x30, 0xe4} },
+{ 0x0d71,	16,	{0x04, 0xe5, 0x28, 0x42, 0x25, 0xe5, 0x24, 0x55, 0x28, 0xff, 0xf5, 0x1a, 0xe5, 0x27, 0x24, 0x2a} },
+{ 0x0d81,	16,	{0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x6f, 0x60, 0x16, 0xe5, 0x1a, 0xf0, 0xe5, 0x27} },
+{ 0x0d91,	16,	{0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x30, 0xe5, 0x04, 0xe5, 0x28, 0x42} },
+{ 0x0da1,	16,	{0x25, 0xe5, 0x29, 0x55, 0x28, 0xff, 0xf5, 0x1a, 0xe5, 0x27, 0x24, 0x30, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x0db1,	14,	{0x26, 0xf5, 0x83, 0xe0, 0x6f, 0x60, 0x07, 0xe5, 0x1a, 0xf0, 0xe5, 0x28, 0x42, 0x25} },
+{ 0x0dbf,	1,	{0x22} },
+{ 0x0dc0,	16,	{0xe5, 0x09, 0x14, 0x60, 0x2a, 0x14, 0x60, 0x41, 0x14, 0x60, 0x58, 0x14, 0x60, 0x6f, 0x24, 0x04} },
+{ 0x0dd0,	16,	{0x60, 0x03, 0x02, 0x0e, 0x77, 0x7e, 0x7b, 0x7f, 0xc0, 0x75, 0x26, 0x7b, 0x75, 0x27, 0xc0, 0x90} },
+{ 0x0de0,	16,	{0x7f, 0x96, 0x74, 0xef, 0xf0, 0x75, 0x28, 0x01, 0x12, 0x12, 0x3d, 0x75, 0x09, 0x01, 0x22, 0x7e} },
+{ 0x0df0,	16,	{0x7c, 0x7f, 0x00, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x00, 0x90, 0x7f, 0x96, 0x74, 0xdf, 0xf0, 0x75} },
+{ 0x0e00,	16,	{0x28, 0x02, 0x12, 0x12, 0x3d, 0x75, 0x09, 0x02, 0x22, 0x7e, 0x7c, 0x7f, 0x40, 0x75, 0x26, 0x7c} },
+{ 0x0e10,	16,	{0x75, 0x27, 0x40, 0x90, 0x7f, 0x96, 0x74, 0xbf, 0xf0, 0x75, 0x28, 0x04, 0x12, 0x12, 0x3d, 0x75} },
+{ 0x0e20,	16,	{0x09, 0x03, 0x22, 0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x80, 0x90, 0x7f, 0x96} },
+{ 0x0e30,	16,	{0x74, 0x7f, 0xf0, 0x75, 0x28, 0x08, 0x12, 0x12, 0x3d, 0x75, 0x09, 0x04, 0x22, 0x30, 0x04, 0x33} },
+{ 0x0e40,	16,	{0xc2, 0x04, 0x53, 0x25, 0xdf, 0xe4, 0xf5, 0x1a, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x11, 0x25, 0x1a} },
+{ 0x0e50,	16,	{0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x11, 0x4a, 0xff, 0x74, 0x80, 0x25, 0x1a, 0xf5, 0x82, 0xe4} },
+{ 0x0e60,	16,	{0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x1a, 0xe5, 0x1a, 0xb4, 0x03, 0xdb, 0x90, 0x7f, 0xc3} },
+{ 0x0e70,	16,	{0x74, 0x03, 0xf0, 0x75, 0x09, 0x05, 0x22, 0xe5, 0x17, 0x60, 0x34, 0xd5, 0x17, 0x03, 0x53, 0x25} },
+{ 0x0e80,	16,	{0xef, 0xe4, 0xf5, 0x1a, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x16, 0x25, 0x1a, 0xf9, 0xee, 0x34, 0x00} },
+{ 0x0e90,	16,	{0xfa, 0x12, 0x11, 0x4a, 0xff, 0x74, 0x80, 0x25, 0x1a, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83} },
+{ 0x0ea0,	16,	{0xef, 0xf0, 0x05, 0x1a, 0xe5, 0x1a, 0xb4, 0x03, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x03, 0xf0, 0xe4} },
+{ 0x0eb0,	2,	{0xf5, 0x09} },
+{ 0x0eb2,	1,	{0x22} },
+{ 0x0eb3,	16,	{0xe4, 0xf5, 0x19, 0x7e, 0x00, 0x7b, 0x01, 0xe5, 0x27, 0x25, 0x19, 0xf9, 0xee, 0x35, 0x26, 0xfa} },
+{ 0x0ec3,	16,	{0xe4, 0x12, 0x11, 0x90, 0x05, 0x19, 0xe5, 0x19, 0xb4, 0x3c, 0xe8, 0xe5, 0x27, 0x24, 0x35, 0xf5} },
+{ 0x0ed3,	16,	{0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5} },
+{ 0x0ee3,	16,	{0x27, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00} },
+{ 0x0ef3,	16,	{0xf0, 0x7f, 0x0c, 0xe4, 0xfd, 0x12, 0x15, 0x3d, 0x7f, 0x10, 0xe5, 0x27, 0x24, 0x33, 0xf5, 0x82} },
+{ 0x0f03,	16,	{0xe4, 0x35, 0x26, 0xf5, 0x83, 0xef, 0xf0, 0x12, 0x14, 0xad, 0x90, 0x78, 0x41, 0x74, 0x02, 0xf0} },
+{ 0x0f13,	16,	{0x7f, 0x01, 0xe5, 0x27, 0x24, 0x36, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xef, 0xf0, 0x44} },
+{ 0x0f23,	16,	{0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x04, 0xf0, 0xe5, 0x27, 0x24, 0x39, 0xf5} },
+{ 0x0f33,	16,	{0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0x74, 0x80, 0xf0, 0x90, 0xc0, 0x00, 0xf0, 0x0f, 0xe4, 0xfd} },
+{ 0x0f43,	16,	{0x12, 0x15, 0x3d, 0xe4, 0xff, 0x7e, 0xa3, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x26} },
+{ 0x0f53,	16,	{0xf5, 0x83, 0xee, 0xf0, 0xfd, 0x12, 0x15, 0x3d, 0x90, 0x78, 0x41, 0x74, 0x01, 0xf0, 0x90, 0xc0} },
+{ 0x0f63,	16,	{0x00, 0xe4, 0xf0, 0x7f, 0x05, 0x7d, 0x7f, 0x12, 0x15, 0x3d, 0x7f, 0x01, 0x12, 0x14, 0x78, 0x7f} },
+{ 0x0f73,	6,	{0x03, 0x7d, 0x07, 0x12, 0x15, 0x3d} },
+{ 0x0f79,	1,	{0x22} },
+{ 0x0f7a,	16,	{0x53, 0x25, 0x3f, 0x90, 0x7b, 0xf1, 0xe0, 0x30, 0xe3, 0x16, 0x7e, 0x7b, 0x7f, 0xc0, 0x75, 0x26} },
+{ 0x0f8a,	16,	{0x7b, 0x75, 0x27, 0xc0, 0x90, 0x7f, 0x96, 0x74, 0xef, 0xf0, 0x75, 0x28, 0x01, 0x12, 0x08, 0x80} },
+{ 0x0f9a,	16,	{0x90, 0x7c, 0x31, 0xe0, 0x30, 0xe3, 0x16, 0x7e, 0x7c, 0x7f, 0x00, 0x75, 0x26, 0x7c, 0x75, 0x27} },
+{ 0x0faa,	16,	{0x00, 0x90, 0x7f, 0x96, 0x74, 0xdf, 0xf0, 0x75, 0x28, 0x02, 0x12, 0x08, 0x80, 0x90, 0x7c, 0x71} },
+{ 0x0fba,	16,	{0xe0, 0x30, 0xe3, 0x16, 0x7e, 0x7c, 0x7f, 0x40, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x40, 0x90, 0x7f} },
+{ 0x0fca,	16,	{0x96, 0x74, 0xbf, 0xf0, 0x75, 0x28, 0x04, 0x12, 0x08, 0x80, 0x90, 0x7c, 0xb1, 0xe0, 0x30, 0xe3} },
+{ 0x0fda,	16,	{0x16, 0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x80, 0x90, 0x7f, 0x96, 0x74, 0x7f} },
+{ 0x0fea,	16,	{0xf0, 0x75, 0x28, 0x08, 0x12, 0x08, 0x80, 0x05, 0x23, 0xe5, 0x23, 0x54, 0x0f, 0xf5, 0x19, 0x70} },
+{ 0x0ffa,	16,	{0x1f, 0x90, 0x78, 0x41, 0xe0, 0x54, 0xf7, 0xf0, 0x90, 0x7f, 0x99, 0xe0, 0xf5, 0x29, 0x90, 0x78} },
+{ 0x100a,	16,	{0x41, 0xe0, 0x44, 0x08, 0xf0, 0x90, 0x7f, 0x99, 0xe0, 0xf4, 0xf5, 0x24, 0x12, 0x10, 0xc2, 0x22} },
+{ 0x101a,	16,	{0xe5, 0x19, 0xb4, 0x01, 0x04, 0x12, 0x0c, 0x21, 0x22, 0x90, 0x7f, 0xc2, 0xe0, 0x20, 0xe1, 0x08} },
+{ 0x102a,	11,	{0xe5, 0x25, 0x60, 0x04, 0x12, 0x0d, 0xc0, 0x22, 0x12, 0x0c, 0x21} },
+{ 0x1035,	1,	{0x22} },
+{ 0x1036,	12,	{0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x29, 0x02, 0x10, 0x7d} },
+{ 0x1042,	16,	{0x02, 0x11, 0xc8, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2} },
+{ 0x1052,	16,	{0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33} },
+{ 0x1062,	16,	{0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf} },
+{ 0x1072,	16,	{0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x17, 0x67, 0xe4, 0x7e} },
+{ 0x1082,	16,	{0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93} },
+{ 0x1092,	16,	{0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3} },
+{ 0x10a2,	16,	{0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca} },
+{ 0x10b2,	16,	{0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe} },
+{ 0x10c2,	16,	{0x90, 0x7f, 0xd2, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x11, 0x49, 0x90, 0x7b, 0x40, 0xe0, 0x14, 0x60} },
+{ 0x10d2,	16,	{0x26, 0x14, 0x60, 0x3b, 0x14, 0x60, 0x50, 0x24, 0x83, 0x60, 0x64, 0x24, 0x80, 0x70, 0x63, 0x7e} },
+{ 0x10e2,	16,	{0x7b, 0x7f, 0xc0, 0x75, 0x26, 0x7b, 0x75, 0x27, 0xc0, 0x90, 0x7f, 0x96, 0x74, 0xef, 0xf0, 0x75} },
+{ 0x10f2,	16,	{0x28, 0x01, 0x12, 0x00, 0x46, 0x80, 0x4b, 0x7e, 0x7c, 0x7f, 0x00, 0x75, 0x26, 0x7c, 0x75, 0x27} },
+{ 0x1102,	16,	{0x00, 0x90, 0x7f, 0x96, 0x74, 0xdf, 0xf0, 0x75, 0x28, 0x02, 0x12, 0x00, 0x46, 0x80, 0x33, 0x7e} },
+{ 0x1112,	16,	{0x7c, 0x7f, 0x40, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x40, 0x90, 0x7f, 0x96, 0x74, 0xbf, 0xf0, 0x75} },
+{ 0x1122,	16,	{0x28, 0x04, 0x12, 0x00, 0x46, 0x80, 0x1b, 0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x26, 0x7c, 0x75, 0x27} },
+{ 0x1132,	16,	{0x80, 0x90, 0x7f, 0x96, 0x74, 0x7f, 0xf0, 0x75, 0x28, 0x08, 0x12, 0x00, 0x46, 0x80, 0x03, 0x12} },
+{ 0x1142,	8,	{0x16, 0x56, 0xe4, 0x90, 0x7f, 0xd3, 0xf0, 0x22} },
+{ 0x114a,	16,	{0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb, 0xfe, 0x02} },
+{ 0x115a,	9,	{0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x1163,	16,	{0xbb, 0x01, 0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50} },
+{ 0x1173,	16,	{0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22} },
+{ 0x1183,	13,	{0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x1190,	16,	{0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xf0, 0x22, 0x50, 0x02, 0xf7, 0x22, 0xbb, 0xfe, 0x01} },
+{ 0x11a0,	2,	{0xf3, 0x22} },
+{ 0x11a2,	16,	{0xd0, 0x83, 0xd0, 0x82, 0xf8, 0xe4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3} },
+{ 0x11b2,	16,	{0x93, 0xf8, 0x74, 0x01, 0x93, 0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60} },
+{ 0x11c2,	6,	{0xef, 0xa3, 0xa3, 0xa3, 0x80, 0xdf} },
+{ 0x11c8,	16,	{0x90, 0x7f, 0xae, 0xe0, 0xff, 0xd3, 0x92, 0x00, 0xe4, 0x33, 0xfe, 0xef, 0x4e, 0xf0, 0xd2, 0xe8} },
+{ 0x11d8,	16,	{0x43, 0xd8, 0x20, 0x90, 0x7f, 0xde, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xab} },
+{ 0x11e8,	16,	{0x74, 0xff, 0xf0, 0x90, 0x7f, 0xa9, 0xf0, 0x90, 0x7f, 0xaa, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x11f8,	16,	{0xaf, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xae, 0x74, 0x0d, 0xf0, 0xd2, 0xaf, 0xd2, 0x09, 0x12, 0x17} },
+{ 0x1208,	16,	{0x13, 0xc2, 0x01, 0xe4, 0xf5, 0x0e, 0xf5, 0x14, 0xc2, 0x07, 0xc2, 0x02, 0x90, 0x7f, 0xd8, 0xe0} },
+{ 0x1218,	16,	{0x65, 0x0b, 0x60, 0x06, 0x75, 0x15, 0x0f, 0xe0, 0xf5, 0x0b, 0x30, 0x02, 0x03, 0x12, 0x0f, 0x7a} },
+{ 0x1228,	16,	{0x30, 0x01, 0x07, 0xc2, 0x01, 0x12, 0x06, 0x45, 0x80, 0xe2, 0x30, 0x08, 0xdf, 0xc2, 0x08, 0x12} },
+{ 0x1238,	5,	{0x17, 0x95, 0x80, 0xd8, 0x22} },
+{ 0x123d,	16,	{0xe5, 0x25, 0x55, 0x28, 0x60, 0x6a, 0xe5, 0x27, 0x24, 0x3a, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} },
+{ 0x124d,	16,	{0x83, 0xe0, 0x70, 0x5c, 0xe5, 0x28, 0xf4, 0x52, 0x25, 0xe5, 0x27, 0x24, 0x26, 0xff, 0xe4, 0x35} },
+{ 0x125d,	16,	{0x26, 0xfe, 0xe4, 0xfd, 0x0f, 0xef, 0xaa, 0x06, 0x70, 0x01, 0x0e, 0x14, 0xf5, 0x82, 0x8a, 0x83} },
+{ 0x126d,	16,	{0xe0, 0xfc, 0x74, 0x80, 0x2d, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xec, 0xf0, 0x0d, 0xbd} },
+{ 0x127d,	16,	{0x0b, 0xe2, 0x90, 0x7f, 0xc3, 0x74, 0x0b, 0xf0, 0xe5, 0x27, 0x24, 0x3a, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x128d,	16,	{0x26, 0xf5, 0x83, 0x74, 0x10, 0xf0, 0xe5, 0x27, 0x24, 0x2e, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} },
+{ 0x129d,	16,	{0x83, 0xe4, 0xf0, 0xe5, 0x27, 0x24, 0x2f, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe4, 0xf0} },
+{ 0x12ad,	1,	{0x22} },
+{ 0x12ae,	16,	{0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0xf0, 0xf0, 0x90, 0x7f, 0x96, 0xf0, 0xe4} },
+{ 0x12be,	16,	{0x90, 0x78, 0x4a, 0xf0, 0x90, 0x7f, 0x94, 0xf0, 0x90, 0x7f, 0x9d, 0x74, 0xff, 0xf0, 0xe4, 0x90} },
+{ 0x12ce,	16,	{0x7f, 0x97, 0xf0, 0xe5, 0x0c, 0x54, 0xf0, 0x44, 0x08, 0x90, 0x78, 0x41, 0xf0, 0xe4, 0x90, 0x7f} },
+{ 0x12de,	16,	{0x98, 0xf0, 0x90, 0x7f, 0x95, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0xff, 0xf0, 0xe4, 0x90, 0x7f, 0x98} },
+{ 0x12ee,	16,	{0xf0, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0xf0, 0xf0, 0xe4, 0x90, 0x7f, 0x96, 0xf0} },
+{ 0x12fe,	8,	{0x90, 0x7f, 0x92, 0xe0, 0x54, 0xfd, 0xf0, 0x22} },
+{ 0x1306,	16,	{0x8f, 0x1b, 0x05, 0x10, 0xe5, 0x10, 0xae, 0x0f, 0x70, 0x02, 0x05, 0x0f, 0x14, 0xf5, 0x82, 0x8e} },
+{ 0x1316,	16,	{0x83, 0xe5, 0x1b, 0xf0, 0x12, 0x17, 0xe5, 0x05, 0x10, 0xe5, 0x10, 0xac, 0x0f, 0x70, 0x02, 0x05} },
+{ 0x1326,	16,	{0x0f, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x15, 0x08, 0xe5, 0x08, 0x60, 0x1f, 0xe5, 0x27} },
+{ 0x1336,	16,	{0x24, 0x38, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfe, 0x12} },
+{ 0x1346,	14,	{0x17, 0xcd, 0x8f, 0x1b, 0xee, 0x4f, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0x80, 0xb5, 0x22} },
+{ 0x1354,	2,	{0x8f, 0x19} },
+{ 0x1356,	16,	{0xe4, 0xf5, 0x1a, 0x75, 0x1b, 0xff, 0x75, 0x1c, 0x19, 0x75, 0x1d, 0x86, 0xab, 0x1b, 0xaa, 0x1c} },
+{ 0x1366,	16,	{0xa9, 0x1d, 0x90, 0x00, 0x01, 0x12, 0x11, 0x63, 0xb4, 0x03, 0x1d, 0xaf, 0x1a, 0x05, 0x1a, 0xef} },
+{ 0x1376,	16,	{0xb5, 0x19, 0x01, 0x22, 0x12, 0x11, 0x4a, 0x7e, 0x00, 0x29, 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75} },
+{ 0x1386,	14,	{0x1b, 0xff, 0xf5, 0x1c, 0x89, 0x1d, 0x80, 0xd4, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x1394,	1,	{0x22} },
+{ 0x1395,	16,	{0xe4, 0x90, 0x78, 0x41, 0xf0, 0x90, 0x78, 0x4f, 0x74, 0xc0, 0xf0, 0xe4, 0x90, 0x78, 0x50, 0xf0} },
+{ 0x13a5,	16,	{0xe5, 0x0f, 0x90, 0x78, 0x51, 0xf0, 0xae, 0x0f, 0xe5, 0x10, 0x90, 0x78, 0x52, 0xf0, 0x90, 0x78} },
+{ 0x13b5,	16,	{0x54, 0xe5, 0x08, 0xf0, 0x90, 0x78, 0x57, 0x74, 0x04, 0xf0, 0x90, 0x7f, 0xe2, 0xe0, 0x44, 0x10} },
+{ 0x13c5,	16,	{0xf0, 0xe0, 0x54, 0xf7, 0xf0, 0xe4, 0x90, 0x78, 0x55, 0xf0, 0x90, 0x78, 0x55, 0xe0, 0x60, 0xfa} },
+{ 0x13d5,	1,	{0x22} },
+{ 0x13d6,	16,	{0xe4, 0x90, 0x78, 0x41, 0xf0, 0xe5, 0x0f, 0x90, 0x78, 0x4f, 0xf0, 0xae, 0x0f, 0xe5, 0x10, 0x90} },
+{ 0x13e6,	16,	{0x78, 0x50, 0xf0, 0x90, 0x78, 0x51, 0x74, 0xc0, 0xf0, 0xe4, 0x90, 0x78, 0x52, 0xf0, 0x90, 0x78} },
+{ 0x13f6,	16,	{0x54, 0xe5, 0x08, 0xf0, 0x90, 0x78, 0x57, 0x74, 0x04, 0xf0, 0xe4, 0x90, 0x78, 0x55, 0xf0, 0x90} },
+{ 0x1406,	6,	{0x78, 0x55, 0xe0, 0x60, 0xfa, 0x22} },
+{ 0x140c,	16,	{0xe5, 0x27, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x14, 0x60, 0x0f, 0x14} },
+{ 0x141c,	16,	{0x60, 0x13, 0x14, 0x60, 0x17, 0x80, 0x00, 0x90, 0x7f, 0xc7, 0xef, 0xf0, 0x80, 0x13, 0x90, 0x7f} },
+{ 0x142c,	16,	{0xc9, 0xef, 0xf0, 0x80, 0x0c, 0x90, 0x7f, 0xcb, 0xef, 0xf0, 0x80, 0x05, 0x90, 0x7f, 0xcd, 0xef} },
+{ 0x143c,	6,	{0xf0, 0xe5, 0x28, 0x42, 0x0d, 0x22} },
+{ 0x1442,	16,	{0xe5, 0x27, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x14, 0x60, 0x0f, 0x14} },
+{ 0x1452,	16,	{0x60, 0x13, 0x14, 0x60, 0x17, 0x80, 0x00, 0x90, 0x7f, 0xb7, 0xef, 0xf0, 0x80, 0x13, 0x90, 0x7f} },
+{ 0x1462,	16,	{0xb9, 0xef, 0xf0, 0x80, 0x0c, 0x90, 0x7f, 0xbb, 0xef, 0xf0, 0x80, 0x05, 0x90, 0x7f, 0xbd, 0xef} },
+{ 0x1472,	6,	{0xf0, 0xe5, 0x28, 0x42, 0x0d, 0x22} },
+{ 0x1478,	16,	{0xae, 0x07, 0xe4, 0xff, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} },
+{ 0x1488,	16,	{0x54, 0x7f, 0xfd, 0x12, 0x15, 0x3d, 0x90, 0x78, 0x41, 0x74, 0x01, 0xf0, 0x90, 0xc0, 0x00, 0xee} },
+{ 0x1498,	16,	{0xf0, 0xe4, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x80} },
+{ 0x14a8,	5,	{0xfd, 0x12, 0x15, 0x3d, 0x22} },
+{ 0x14ad,	16,	{0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x78, 0x41, 0x74} },
+{ 0x14bd,	16,	{0x02, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x27, 0x24} },
+{ 0x14cd,	16,	{0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x14dd,	16,	{0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x78, 0x41, 0x74} },
+{ 0x14ed,	16,	{0x04, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x27, 0x24} },
+{ 0x14fd,	16,	{0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x150d,	16,	{0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x78, 0x41, 0x74} },
+{ 0x151d,	16,	{0x06, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x27, 0x24} },
+{ 0x152d,	16,	{0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x153d,	16,	{0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x27, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} },
+{ 0x154d,	16,	{0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x07, 0xf0, 0x90, 0xc0} },
+{ 0x155d,	15,	{0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x05, 0xf0, 0x90, 0xc0, 0x00, 0xed, 0xf0, 0x22} },
+{ 0x156c,	16,	{0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0xe4, 0x90, 0x78, 0x41} },
+{ 0x157c,	16,	{0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x27, 0x24, 0x37} },
+{ 0x158c,	15,	{0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x159b,	16,	{0xe5, 0x27, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x14, 0x60, 0x0e, 0x14} },
+{ 0x15ab,	16,	{0x60, 0x11, 0x14, 0x60, 0x14, 0x80, 0x00, 0x90, 0x7f, 0xc6, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xc8} },
+{ 0x15bb,	15,	{0xe0, 0xff, 0x22, 0x90, 0x7f, 0xca, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xcc, 0xe0, 0xff, 0x22} },
+{ 0x15ca,	16,	{0xe5, 0x27, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x14, 0x60, 0x0e, 0x14} },
+{ 0x15da,	16,	{0x60, 0x11, 0x14, 0x60, 0x14, 0x80, 0x00, 0x90, 0x7f, 0xb6, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xb8} },
+{ 0x15ea,	15,	{0xe0, 0xff, 0x22, 0x90, 0x7f, 0xba, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xbc, 0xe0, 0xff, 0x22} },
+{ 0x15f9,	16,	{0xe5, 0x27, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x14, 0x60, 0x0e, 0x14} },
+{ 0x1609,	16,	{0x60, 0x11, 0x14, 0x60, 0x14, 0x80, 0x00, 0x90, 0x7f, 0xc7, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xc9} },
+{ 0x1619,	15,	{0xe0, 0xff, 0x22, 0x90, 0x7f, 0xcb, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xcd, 0xe0, 0xff, 0x22} },
+{ 0x1628,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x30} },
+{ 0x1638,	16,	{0x05, 0x04, 0xc2, 0x05, 0x80, 0x02, 0xd2, 0x08, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x08} },
+{ 0x1648,	14,	{0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x1656,	16,	{0x90, 0x7b, 0x41, 0xe0, 0xf5, 0x17, 0x43, 0x25, 0x10, 0xa3, 0xe0, 0x60, 0x09, 0x90, 0x7f, 0xd7} },
+{ 0x1666,	16,	{0x74, 0x17, 0xf0, 0x74, 0x37, 0xf0, 0x90, 0x7b, 0x43, 0xe0, 0xf5, 0x18, 0x30, 0x00, 0x07, 0xa3} },
+{ 0x1676,	10,	{0xe0, 0x54, 0xf0, 0xf5, 0x0c, 0x22, 0xe4, 0xf5, 0x0c, 0x22} },
+{ 0x1680,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x90} },
+{ 0x1690,	16,	{0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x04, 0xf0, 0xd0, 0x86, 0xd0} },
+{ 0x16a0,	10,	{0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x16aa,	16,	{0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xd2} },
+{ 0x16ba,	16,	{0x01, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85} },
+{ 0x16ca,	7,	{0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x16d1,	16,	{0x12, 0x17, 0xb5, 0xae, 0x07, 0x12, 0x17, 0xb5, 0xad, 0x07, 0xee, 0x6d, 0x60, 0x10, 0x12, 0x17} },
+{ 0x16e1,	16,	{0xb5, 0xae, 0x07, 0xee, 0x6d, 0x60, 0x07, 0x12, 0x17, 0xb5, 0xad, 0x07, 0x80, 0xec, 0xaf, 0x06} },
+{ 0x16f1,	1,	{0x22} },
+{ 0x16f2,	16,	{0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9} },
+{ 0x1702,	1,	{0x22} },
+{ 0x1703,	16,	{0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22} },
+{ 0x1713,	16,	{0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x04, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x09, 0x04, 0xe0, 0x44} },
+{ 0x1723,	16,	{0x02, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x17, 0x34, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0} },
+{ 0x1733,	1,	{0x22} },
+{ 0x1734,	16,	{0x8e, 0x19, 0x8f, 0x1a, 0xe5, 0x1a, 0x15, 0x1a, 0xae, 0x19, 0x70, 0x02, 0x15, 0x19, 0x4e, 0x60} },
+{ 0x1744,	10,	{0x08, 0x12, 0x16, 0xf2, 0x12, 0x16, 0xf2, 0x80, 0xeb, 0x22} },
+{ 0x174e,	16,	{0xe5, 0x27, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x04, 0xff, 0x44, 0x10} },
+{ 0x175e,	9,	{0x90, 0x7f, 0xd7, 0xf0, 0xef, 0x44, 0x30, 0xf0, 0x22} },
+{ 0x1767,	16,	{0x03, 0x16, 0x80, 0x00, 0x00, 0x03, 0x11, 0x81, 0x00, 0x00, 0xc1, 0x85, 0xc1, 0x81, 0xc1, 0x08} },
+{ 0x1777,	7,	{0xc1, 0x00, 0xc1, 0x86, 0x01, 0x09, 0x00} },
+{ 0x177e,	1,	{0x00} },
+{ 0x177f,	16,	{0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x01, 0xf0, 0x7f, 0x0d, 0x7e, 0x00, 0x12, 0x17, 0x34, 0x90, 0x7f} },
+{ 0x178f,	6,	{0xd6, 0xe0, 0x54, 0xfe, 0xf0, 0x22} },
+{ 0x1795,	16,	{0x12, 0x12, 0xae, 0x12, 0x17, 0x03, 0x90, 0x7f, 0xd6, 0xe0, 0x30, 0xe7, 0x03, 0x12, 0x17, 0x7f} },
+{ 0x17a5,	4,	{0x12, 0x0a, 0x6a, 0x22} },
+{ 0x17a9,	12,	{0x90, 0x78, 0x41, 0x74, 0x02, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x17b5,	12,	{0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x17c1,	12,	{0x90, 0x78, 0x41, 0x74, 0x04, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x17cd,	12,	{0x90, 0x78, 0x41, 0x74, 0x05, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x17d9,	12,	{0x90, 0x78, 0x41, 0x74, 0x06, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x17e5,	11,	{0xe4, 0x90, 0x78, 0x41, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x17f0,	4,	{0x53, 0xd8, 0xef, 0x32} },
+{ 0x1800,	15,	{0x02, 0x16, 0xaa, 0x00, 0x02, 0x18, 0x04, 0x00, 0x02, 0x16, 0x80, 0x00, 0x02, 0x16, 0x28} },
+{ 0x1900,	16,	{0x12, 0x01, 0x01, 0x00, 0xff, 0x00, 0x00, 0x40, 0xcd, 0x06, 0x0a, 0x01, 0x00, 0x00, 0x01, 0x02} },
+{ 0x1910,	16,	{0x00, 0x04, 0x09, 0x02, 0x74, 0x00, 0x01, 0x01, 0x00, 0xa0, 0x32, 0x09, 0x04, 0x00, 0x00, 0x0e} },
+{ 0x1920,	16,	{0xff, 0x00, 0x00, 0x00, 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40} },
+{ 0x1930,	16,	{0x00, 0x00, 0x07, 0x05, 0x03, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00, 0x00} },
+{ 0x1940,	16,	{0x07, 0x05, 0x05, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x06, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05} },
+{ 0x1950,	16,	{0x07, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x82, 0x02} },
+{ 0x1960,	16,	{0x40, 0x00, 0x01, 0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x84, 0x02, 0x40, 0x00} },
+{ 0x1970,	16,	{0x01, 0x07, 0x05, 0x85, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x86, 0x02, 0x40, 0x00, 0x01, 0x07} },
+{ 0x1980,	16,	{0x05, 0x87, 0x02, 0x40, 0x00, 0x01, 0x04, 0x03, 0x09, 0x04, 0x48, 0x03, 0x4b, 0x00, 0x65, 0x00} },
+{ 0x1990,	16,	{0x79, 0x00, 0x73, 0x00, 0x70, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x61, 0x00} },
+{ 0x19a0,	16,	{0x20, 0x00, 0x64, 0x00, 0x69, 0x00, 0x76, 0x00, 0x69, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00} },
+{ 0x19b0,	16,	{0x6e, 0x00, 0x20, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x6e, 0x00} },
+{ 0x19c0,	16,	{0x6f, 0x00, 0x53, 0x00, 0x79, 0x00, 0x73, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x63, 0x00} },
+{ 0x19d0,	16,	{0x2e, 0x00, 0x36, 0x03, 0x4b, 0x00, 0x65, 0x00, 0x79, 0x00, 0x73, 0x00, 0x70, 0x00, 0x61, 0x00} },
+{ 0x19e0,	16,	{0x6e, 0x00, 0x20, 0x00, 0x55, 0x00, 0x53, 0x00, 0x42, 0x00, 0x20, 0x00, 0x53, 0x00, 0x65, 0x00} },
+{ 0x19f0,	16,	{0x72, 0x00, 0x69, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x41, 0x00, 0x64, 0x00, 0x61, 0x00} },
+{ 0x1a00,	10,	{0x70, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00} },
+{ 0xffff,	0,	{0x00} }
+};
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/usb-serial.h linux.19p18/drivers/usb/serial/usb-serial.h
--- linux.vanilla/drivers/usb/serial/usb-serial.h	Mon Dec 11 22:13:01 2000
+++ linux.19p18/drivers/usb/serial/usb-serial.h	Tue Jan  9 11:55:48 2001
@@ -11,6 +11,11 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
+ * (10/05/2000) gkh
+ *	Added interrupt_in_endpointAddress and bulk_in_endpointAddress to help
+ *	fix bug with urb->dev not being set properly, now that the usb core
+ *	needs it.
+ * 
  * (09/11/2000) gkh
  *	Added usb_serial_debug_data function to help get rid of #DEBUG in the
  *	drivers.
@@ -57,9 +62,11 @@
 
 	unsigned char *		interrupt_in_buffer;
 	struct urb *		interrupt_in_urb;
+	__u8			interrupt_in_endpointAddress;
 
 	unsigned char *		bulk_in_buffer;
 	struct urb *		read_urb;
+	__u8			bulk_in_endpointAddress;
 
 	unsigned char *		bulk_out_buffer;
 	int			bulk_out_size;
@@ -118,7 +125,9 @@
 	struct list_head	driver_list;
 	
 	/* function call to make before accepting driver */
-	int (*startup) (struct usb_serial *serial);	/* return 0 to continue initialization, anything else to abort */
+	/* return 0 to continue initialization, anything else to abort */
+	int (*startup) (struct usb_serial *serial);
+	
 	void (*shutdown) (struct usb_serial *serial);
 
 	/* serial function calls */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/usbserial.c linux.19p18/drivers/usb/serial/usbserial.c
--- linux.vanilla/drivers/usb/serial/usbserial.c	Mon Dec 11 22:13:01 2000
+++ linux.19p18/drivers/usb/serial/usbserial.c	Sat Mar 10 23:08:59 2001
@@ -14,6 +14,23 @@
  * based on a driver by Brad Keryan)
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ * 2001_02_05 gkh
+ *	Fixed buffer overflows bug with the generic serial driver.  Thanks to
+ *	Todd Squires <squirest@ct0.com> for fixing this.
+ *
+ * (12/12/2000) gkh
+ *	Removed MOD_INC and MOD_DEC from poll and disconnect functions, and
+ *	moved them to the serial_open and serial_close functions.
+ *	Also fixed bug with there not being a MOD_DEC for the generic driver
+ *	(thanks to Gary Brubaker for finding this.)
+ *
+ * (12/29/2000) gkh
+ *	Small NULL pointer initialization cleanup which saves a bit of disk image
+ *
+ * (10/05/2000) gkh
+ *	Fixed bug with urb->dev not being set properly, now that the usb
+ *	core needs it.
  * 
  * (09/11/2000) gkh
  *	Removed DEBUG #ifdefs with call to usb_serial_debug_data
@@ -239,9 +256,9 @@
 #include <linux/init.h>
 #include <linux/malloc.h>
 #include <linux/fcntl.h>
+#include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
-#include <linux/tty.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <linux/list.h>
@@ -327,7 +344,7 @@
 static struct tty_struct *	serial_tty[SERIAL_TTY_MINORS];
 static struct termios *		serial_termios[SERIAL_TTY_MINORS];
 static struct termios *		serial_termios_locked[SERIAL_TTY_MINORS];
-static struct usb_serial	*serial_table[SERIAL_TTY_MINORS] = {NULL, };
+static struct usb_serial	*serial_table[SERIAL_TTY_MINORS];	/* initially all NULL */
 
 LIST_HEAD(usb_serial_driver_list);
 
@@ -449,6 +466,8 @@
 		return -ENODEV;
 	}
 
+	MOD_INC_USE_COUNT;
+	
 	/* set up our port structure making the tty driver remember our port object, and us it */
 	portNumber = MINOR(tty->device) - serial->minor;
 	port = &serial->port[portNumber];
@@ -486,6 +505,8 @@
 	} else {
 		generic_close(port, filp);
 	}
+
+	MOD_DEC_USE_COUNT;
 }	
 
 
@@ -694,25 +715,40 @@
 {
 	struct usb_serial *serial = port->serial;
 	unsigned long flags;
+	int result;
 
 	if (port_paranoia_check (port, __FUNCTION__))
 		return -ENODEV;
 
+	MOD_INC_USE_COUNT;
+
 	dbg(__FUNCTION__ " - port %d", port->number);
 
 	spin_lock_irqsave (&port->port_lock, flags);
 	
 	++port->open_count;
-	MOD_INC_USE_COUNT;
 	
 	if (!port->active) {
 		port->active = 1;
 
+		/* force low_latency on so that our tty_push actually forces the data through, 
+		   otherwise it is scheduled, and with high data rates (like with OHCI) data
+		   can get lost. */
+		port->tty->low_latency = 1;
+		
 		/* if we have a bulk interrupt, start reading from it */
 		if (serial->num_bulk_in) {
-			/*Start reading from the device*/
-			if (usb_submit_urb(port->read_urb))
-				dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed");
+			/* Start reading from the device */
+			FILL_BULK_URB(port->read_urb, serial->dev, 
+				      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+				      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
+				      ((serial->type->read_bulk_callback) ?
+				       serial->type->read_bulk_callback :
+				       generic_read_bulk_callback), 
+				      port);
+			result = usb_submit_urb(port->read_urb);
+			if (result)
+				err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
 		}
 	}
 	
@@ -745,6 +781,7 @@
 	}
 
 	spin_unlock_irqrestore (&port->port_lock, flags);
+	MOD_DEC_USE_COUNT;
 }
 
 
@@ -752,6 +789,7 @@
 {
 	struct usb_serial *serial = port->serial;
 	unsigned long flags;
+	int result;
 
 	dbg(__FUNCTION__ " - port %d", port->number);
 
@@ -779,11 +817,19 @@
 			memcpy (port->write_urb->transfer_buffer, buf, count);
 		}  
 
-		/* send the data out the bulk port */
-		port->write_urb->transfer_buffer_length = count;
+		/* set up our urb */
+		FILL_BULK_URB(port->write_urb, serial->dev, 
+			      usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
+			      port->write_urb->transfer_buffer, count,
+			      ((serial->type->write_bulk_callback) ? 
+			       serial->type->write_bulk_callback : 
+			       generic_write_bulk_callback), 
+			      port);
 
-		if (usb_submit_urb(port->write_urb)) {
-			dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed");
+		/* send the data out the bulk port */
+		result = usb_submit_urb(port->write_urb);
+		if (result) {
+			err(__FUNCTION__ " - failed submitting write urb, error %d", result);
 			spin_unlock_irqrestore (&port->port_lock, flags);
 			return 0;
 		}
@@ -836,6 +882,7 @@
 	struct tty_struct *tty;
 	unsigned char *data = urb->transfer_buffer;
 	int i;
+	int result;
 
 	dbg(__FUNCTION__ " - port %d", port->number);
 	
@@ -854,16 +901,27 @@
 	tty = port->tty;
 	if (urb->actual_length) {
 		for (i = 0; i < urb->actual_length ; ++i) {
-			 tty_insert_flip_char(tty, data[i], 0);
-	  	}
+			/* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */
+			if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
+				tty_flip_buffer_push(tty);
+			}
+			/* this doesn't actually push the data through unless tty->low_latency is set */
+			tty_insert_flip_char(tty, data[i], 0);
+		}
 	  	tty_flip_buffer_push(tty);
 	}
 
 	/* Continue trying to always read  */
-	if (usb_submit_urb(urb))
-		dbg(__FUNCTION__ " - failed resubmitting read urb");
-
-	return;
+	FILL_BULK_URB(port->read_urb, serial->dev, 
+		      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+		      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
+		      ((serial->type->read_bulk_callback) ?
+		       serial->type->read_bulk_callback :
+		       generic_read_bulk_callback), 
+		      port);
+	result = usb_submit_urb(port->read_urb);
+	if (result)
+		err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
 }
 
 
@@ -1024,7 +1082,6 @@
 	}
 
 	/* found all that we need */
-	MOD_INC_USE_COUNT;
 	info("%s converter detected", type->name);
 
 #ifdef CONFIG_USB_SERIAL_GENERIC
@@ -1032,7 +1089,6 @@
 		num_ports = num_bulk_out;
 		if (num_ports == 0) {
 			err("Generic device with no bulk out, not allowed.");
-			MOD_DEC_USE_COUNT;
 			return NULL;
 		}
 	} else
@@ -1042,7 +1098,6 @@
 	serial = get_free_serial (num_ports, &minor);
 	if (serial == NULL) {
 		err("No more free serial devices");
-		MOD_DEC_USE_COUNT;
 		return NULL;
 	}
 	
@@ -1072,6 +1127,7 @@
 			goto probe_error;
 		}
 		buffer_size = endpoint->wMaxPacketSize;
+		port->bulk_in_endpointAddress = endpoint->bEndpointAddress;
 		port->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
 		if (!port->bulk_in_buffer) {
 			err("Couldn't allocate bulk_in_buffer");
@@ -1120,6 +1176,7 @@
 			goto probe_error;
 		}
 		buffer_size = endpoint->wMaxPacketSize;
+		port->interrupt_in_endpointAddress = endpoint->bEndpointAddress;
 		port->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
 		if (!port->interrupt_in_buffer) {
 			err("Couldn't allocate interrupt_in_buffer");
@@ -1137,6 +1194,7 @@
 	/* we don't use num_ports here cauz some devices have more endpoint pairs than ports */
 	max_endpoints = MAX(num_bulk_in, num_bulk_out);
 	max_endpoints = MAX(max_endpoints, num_interrupt_in);
+	dbg (__FUNCTION__ " - setting up %d port structures for this device", max_endpoints);
 	for (i = 0; i < max_endpoints; ++i) {
 		port = &serial->port[i];
 		port->number = i + serial->minor;
@@ -1185,7 +1243,6 @@
 
 	/* free up any memory that we allocated */
 	kfree (serial);
-	MOD_DEC_USE_COUNT;
 	return NULL;
 }
 
@@ -1252,14 +1309,13 @@
 		info("device disconnected");
 	}
 	
-	MOD_DEC_USE_COUNT;
 }
 
 
 static struct tty_driver serial_tty_driver = {
 	magic:			TTY_DRIVER_MAGIC,
 	driver_name:		"usb-serial",
-	name:			"usb/tts/%d",
+	name:			"ttyUSB",
 	major:			SERIAL_TTY_MAJOR,
 	minor_start:		0,
 	num:			SERIAL_TTY_MINORS,
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/serial/visor.c linux.19p18/drivers/usb/serial/visor.c
--- linux.vanilla/drivers/usb/serial/visor.c	Mon Dec 11 22:13:01 2000
+++ linux.19p18/drivers/usb/serial/visor.c	Sat Mar 10 23:09:22 2001
@@ -10,11 +10,26 @@
  *	(at your option) any later version.
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ * (01/21/2000) gkh
+ *	Added write_room and chars_in_buffer, as they were previously using the
+ *	generic driver versions which is all wrong now that we are using an urb
+ *	pool.  Thanks to Wolfgang Grandegger for pointing this out to me.
+ *	Removed count assignment in the write function, which was not needed anymore
+ *	either.  Thanks to Al Borchers for pointing this out.
+ *
+ * (12/12/2000) gkh
+ *	Moved MOD_DEC to end of visor_close to be nicer, as the final write 
+ *	message can sleep.
  * 
  * (11/12/2000) gkh
  *	Fixed bug with data being dropped on the floor by forcing tty->low_latency
  *	to be on.  This fixes the OHCI issue!
  *
+ * (10/05/2000) gkh
+ *	Fixed bug with urb->dev not being set properly, now that the usb
+ *	core needs it.
+ * 
  * (09/11/2000) gkh
  *	Got rid of always calling kmalloc for every urb we wrote out to the
  *	device.
@@ -69,9 +84,9 @@
 #include <linux/init.h>
 #include <linux/malloc.h>
 #include <linux/fcntl.h>
+#include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
-#include <linux/tty.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
 
@@ -92,6 +107,8 @@
 static int  visor_open		(struct usb_serial_port *port, struct file *filp);
 static void visor_close		(struct usb_serial_port *port, struct file *filp);
 static int  visor_write		(struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
+static int  visor_write_room		(struct usb_serial_port *port);
+static int  visor_chars_in_buffer	(struct usb_serial_port *port);
 static void visor_throttle	(struct usb_serial_port *port);
 static void visor_unthrottle	(struct usb_serial_port *port);
 static int  visor_startup	(struct usb_serial *serial);
@@ -124,6 +141,8 @@
 	ioctl:			visor_ioctl,
 	set_termios:		visor_set_termios,
 	write:			visor_write,
+	write_room:		visor_write_room,
+	chars_in_buffer:	visor_chars_in_buffer,
 	write_bulk_callback:	visor_write_bulk_callback,
 	read_bulk_callback:	visor_read_bulk_callback,
 };
@@ -142,7 +161,9 @@
  ******************************************************************************/
 static int visor_open (struct usb_serial_port *port, struct file *filp)
 {
+	struct usb_serial *serial = port->serial;
 	unsigned long flags;
+	int result;
 
 	if (port_paranoia_check (port, __FUNCTION__))
 		return -ENODEV;
@@ -160,13 +181,18 @@
 		bytes_out = 0;
 
 		/* force low_latency on so that our tty_push actually forces the data through, 
-		  otherwise it is scheduled, and with high data rates (like with OHCI) data
-		  can get lost. */
+		   otherwise it is scheduled, and with high data rates (like with OHCI) data
+		   can get lost. */
 		port->tty->low_latency = 1;
-
-		/*Start reading from the device*/
-		if (usb_submit_urb(port->read_urb))
-			dbg(__FUNCTION__  " - usb_submit_urb(read bulk) failed");
+		
+		/* Start reading from the device */
+		FILL_BULK_URB(port->read_urb, serial->dev, 
+			      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+			      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
+			      visor_read_bulk_callback, port);
+		result = usb_submit_urb(port->read_urb);
+		if (result)
+			err(__FUNCTION__ " - failed submitting read urb, error %d", result);
 	}
 	
 	spin_unlock_irqrestore (&port->port_lock, flags);
@@ -193,7 +219,6 @@
 	spin_lock_irqsave (&port->port_lock, flags);
 
 	--port->open_count;
-	MOD_DEC_USE_COUNT;
 
 	if (port->open_count <= 0) {
 		transfer_buffer =  kmalloc (0x12, GFP_KERNEL);
@@ -216,6 +241,8 @@
 
 	/* Uncomment the following line if you want to see some statistics in your syslog */
 	/* info ("Bytes In = %d  Bytes Out = %d", bytes_in, bytes_out); */
+
+	MOD_DEC_USE_COUNT;
 }
 
 
@@ -263,8 +290,6 @@
 		else
 			memcpy (urb->transfer_buffer, current_position, transfer_size);
 		
-		count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
-
 		/* build up our urb */
 		FILL_BULK_URB (urb, serial->dev, usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress), 
 				urb->transfer_buffer, transfer_size, visor_write_bulk_callback, port);
@@ -286,6 +311,52 @@
 } 
 
 
+static int visor_write_room (struct usb_serial_port *port)
+{
+	unsigned long flags;
+	int i;
+	int room = 0;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+	
+	spin_lock_irqsave (&port->port_lock, flags);
+
+	for (i = 0; i < NUM_URBS; ++i) {
+		if (write_urb_pool[i]->status != -EINPROGRESS) {
+			room += URB_TRANSFER_BUFFER_SIZE;
+		}
+	}
+	
+	spin_unlock_irqrestore (&port->port_lock, flags);
+	
+	dbg(__FUNCTION__ " - returns %d", room);
+	return (room);
+}
+
+
+static int visor_chars_in_buffer (struct usb_serial_port *port)
+{
+	unsigned long flags;
+	int i;
+	int chars = 0;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+	
+	spin_lock_irqsave (&port->port_lock, flags);
+
+	for (i = 0; i < NUM_URBS; ++i) {
+		if (write_urb_pool[i]->status == -EINPROGRESS) {
+			chars += URB_TRANSFER_BUFFER_SIZE;
+		}
+	}
+	
+	spin_unlock_irqrestore (&port->port_lock, flags);
+
+	dbg (__FUNCTION__ " - returns %d", chars);
+	return (chars);
+}
+
+
 static void visor_write_bulk_callback (struct urb *urb)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
@@ -310,15 +381,22 @@
 static void visor_read_bulk_callback (struct urb *urb)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 	struct tty_struct *tty;
 	unsigned char *data = urb->transfer_buffer;
 	int i;
+	int result;
 
 	if (port_paranoia_check (port, __FUNCTION__))
 		return;
 
 	dbg(__FUNCTION__ " - port %d", port->number);
 
+	if (!serial) {
+		dbg(__FUNCTION__ " - bad serial pointer, exiting");
+		return;
+	}
+
 	if (urb->status) {
 		dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
 		return;
@@ -341,8 +419,13 @@
 	}
 
 	/* Continue trying to always read  */
-	if (usb_submit_urb(urb))
-		dbg(__FUNCTION__ " - failed resubmitting read urb");
+	FILL_BULK_URB(port->read_urb, serial->dev, 
+		      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+		      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
+		      visor_read_bulk_callback, port);
+	result = usb_submit_urb(port->read_urb);
+	if (result)
+		err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
 	return;
 }
 
@@ -366,13 +449,16 @@
 static void visor_unthrottle (struct usb_serial_port *port)
 {
 	unsigned long flags;
+	int result;
 
 	dbg(__FUNCTION__ " - port %d", port->number);
 
 	spin_lock_irqsave (&port->port_lock, flags);
 
-	if (usb_submit_urb (port->read_urb))
-		dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed");
+	port->read_urb->dev = port->serial->dev;
+	result = usb_submit_urb(port->read_urb);
+	if (result)
+		err(__FUNCTION__ " - failed submitting read urb, error %d", result);
 
 	spin_unlock_irqrestore (&port->port_lock, flags);
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/usb/usb.c linux.19p18/drivers/usb/usb.c
--- linux.vanilla/drivers/usb/usb.c	Mon Dec 11 22:13:01 2000
+++ linux.19p18/drivers/usb/usb.c	Mon Feb 19 18:30:00 2001
@@ -187,6 +187,19 @@
 	return NULL;
 }
 
+struct usb_endpoint_descriptor *usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum)
+{
+	int i, j, k;
+
+	for (i = 0; i < dev->actconfig->bNumInterfaces; i++)
+		for (j = 0; j < dev->actconfig->interface[i].num_altsetting; j++)
+			for (k = 0; k < dev->actconfig->interface[i].altsetting[j].bNumEndpoints; k++)
+				if (epnum == dev->actconfig->interface[i].altsetting[j].endpoint[k].bEndpointAddress)
+					return &dev->actconfig->interface[i].altsetting[j].endpoint[k];
+
+	return NULL;
+}
+
 /*
  * usb_calc_bus_time:
  *
@@ -283,11 +296,13 @@
 	else
 		dev->bus->bandwidth_int_reqs++;
 	urb->bandwidth = bustime;
-	
-	dbg("bw_alloc increased by %d to %d for %d requesters",
+
+#ifdef USB_BANDWIDTH_MESSAGES
+	dbg("bandwidth alloc increased by %d to %d for %d requesters",
 		bustime,
 		dev->bus->bandwidth_allocated,
 		dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
+#endif
 }
 
 /*
@@ -303,10 +318,12 @@
 	else
 		dev->bus->bandwidth_int_reqs--;
 
-	dbg("bw_alloc reduced by %d to %d for %d requesters",
+#ifdef USB_BANDWIDTH_MESSAGES
+	dbg("bandwidth alloc reduced by %d to %d for %d requesters",
 		urb->bandwidth,
 		dev->bus->bandwidth_allocated,
 		dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
+#endif
 	urb->bandwidth = 0;
 }
 
@@ -484,12 +501,17 @@
 			
 		tmp = tmp->next;
 		down(&driver->serialize);
+		if (usb_interface_claimed(interface)) {
+			up(&driver->serialize);
+			return -1;
+		}
 		private = driver->probe(dev, ifnum);
-		up(&driver->serialize);
-		if (!private)
+		if (!private) {
+			up(&driver->serialize);
 			continue;
+		}
 		usb_driver_claim_interface(driver, interface, private);
-
+		up(&driver->serialize);
 		return 0;
 	}
 	
@@ -737,7 +759,7 @@
 		dbg("unhandled interfaces on device");
 
 	if (!claimed) {
-		warn("USB device %d (prod/vend 0x%x/0x%x) is not claimed by any active driver.",
+		warn("USB device %d (vend/prod 0x%x/0x%x) is not claimed by any active driver.",
 			dev->devnum,
 			dev->descriptor.idVendor,
 			dev->descriptor.idProduct);
@@ -2037,6 +2059,7 @@
  * then these symbols need to be exported for the modules to use.
  */
 EXPORT_SYMBOL(usb_ifnum_to_if);
+EXPORT_SYMBOL(usb_epnum_to_ep_desc);
 
 EXPORT_SYMBOL(usb_register);
 EXPORT_SYMBOL(usb_deregister);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/Config.in linux.19p18/drivers/video/Config.in
--- linux.vanilla/drivers/video/Config.in	Mon Dec 11 22:13:02 2000
+++ linux.19p18/drivers/video/Config.in	Thu Feb 15 16:19:20 2001
@@ -50,7 +50,7 @@
   if [ "$CONFIG_ATARI" = "y" ]; then
     bool 'Atari native chipset support' CONFIG_FB_ATARI
   fi
-  if [ "$CONFIG_ATARI" = "y" -o "$CONFIG_PCI" != "n" ]; then
+  if [ "$CONFIG_ATARI" = "y" -o "$CONFIG_PCI" = "y" ]; then
     tristate 'ATI Mach64 display support' CONFIG_FB_ATY
   fi
   if [ "$CONFIG_PPC" = "y" ]; then
@@ -86,7 +86,7 @@
     define_bool CONFIG_BUS_I2C y
   fi
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-    if [ "$CONFIG_PCI" != "n" -a "$ARCH" != "sparc" -a "$ARCH" != "sparc64" ]; then
+    if [ "$CONFIG_PCI" = "y" -a "$ARCH" != "sparc" -a "$ARCH" != "sparc64" ]; then
       tristate 'Matrox acceleration' CONFIG_FB_MATROX
       if  [ "$CONFIG_FB_MATROX" != "n" ]; then
         bool '  Millennium I/II support' CONFIG_FB_MATROX_MILLENIUM
@@ -114,7 +114,7 @@
     fi
   fi
   if [ "$ARCH" = "sparc" ]; then
-    if [ "$CONFIG_PCI" != "n" ]; then
+    if [ "$CONFIG_PCI" = "y" ]; then
       bool 'PCI framebuffers' CONFIG_FB_PCI
       if [ "$CONFIG_FB_PCI" != "n" ]; then
         bool '  IGA 168x display support' CONFIG_FB_IGA
@@ -188,7 +188,8 @@
 	 "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
          "$CONFIG_FB_IGA" = "y" -o "$CONFIG_FB_MATROX" = "y" -o \
 	 "$CONFIG_FB_CT65550" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
-	 "$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" ]; then
+	 "$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" -o \
+	 "$CONFIG_FB_ATY128" = "y" ]; then
       define_bool CONFIG_FBCON_CFB8 y
     else
       if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
@@ -202,14 +203,15 @@
 	   "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
            "$CONFIG_FB_IGA" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \
 	   "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
-	   "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" ]; then
+	   "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" -o \
+	   "$CONFIG_FB_ATY128" = "m" ]; then
 	define_bool CONFIG_FBCON_CFB8 m
       fi
     fi
     if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \
 	 "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_VESA" = "y" -o \
 	 "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_TBOX" = "y" -o \
-	 "$CONFIG_FB_Q40" = "y" -o \
+	 "$CONFIG_FB_Q40" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \
 	 "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
 	 "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \
 	 "$CONFIG_FB_VALKYRIE" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
@@ -221,7 +223,7 @@
       if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
 	   "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_VESA" = "m" -o \
 	   "$CONFIG_FB_VIRTUAL" = "m" -o "$CONFIG_FB_TBOX" = "m" -o \
-	 "$CONFIG_FB_Q40" = "m" -o \
+	   "$CONFIG_FB_Q40" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \
 	   "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
 	   "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \
  	   "$CONFIG_FB_VALKYRIE" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
@@ -234,13 +236,13 @@
     if [ "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
 	 "$CONFIG_FB_CLGEN" = "y" -o "$CONFIG_FB_VESA" = "y" -o \
 	  "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
-	 "$CONFIG_FB_CYBER2000" = "y" ]; then
+	 "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_ATY128" = "y" ]; then
       define_bool CONFIG_FBCON_CFB24 y
     else
       if [ "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
 	   "$CONFIG_FB_CLGEN" = "m" -o "$CONFIG_FB_VESA" = "m" -o \
 	   "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
-	   "$CONFIG_FB_CYBER2000" = "m" ]; then
+	   "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_ATY128" = "m" ]; then
 	define_bool CONFIG_FBCON_CFB24 m
       fi
     fi
@@ -249,7 +251,8 @@
 	 "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
 	 "$CONFIG_FB_TGA" = "y" -o "$CONFIG_FB_PLATINUM" = "y" -o \
 	 "$CONFIG_FB_MATROX" = "y" -o "$CONFIG_FB_PM2" = "y" -o \
-	 "$CONFIG_FB_FM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" ]; then
+	 "$CONFIG_FB_FM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \
+	 "$CONFIG_FB_ATY128" = "y" ]; then
       define_bool CONFIG_FBCON_CFB32 y
     else
       if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
@@ -257,7 +260,7 @@
 	   "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
 	   "$CONFIG_FB_TGA" = "m" -o "$CONFIG_FB_PLATINUM" = "m" -o \
 	   "$CONFIG_FB_MATROX" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
-           "$CONFIG_FB_SGIVW" = "m" ]; then
+           "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_ATY128" = "m" ]; then
 	define_bool CONFIG_FBCON_CFB32 m
       fi
     fi
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/Makefile linux.19p18/drivers/video/Makefile
--- linux.vanilla/drivers/video/Makefile	Mon Dec 11 22:13:02 2000
+++ linux.19p18/drivers/video/Makefile	Thu Feb  1 14:59:36 2001
@@ -106,6 +106,10 @@
 
 ifeq ($(CONFIG_FB_ATY128),y)
   L_OBJS += aty128fb.o
+else
+  ifeq ($(CONFIG_FB_ATY128),m)
+  M_OBJS += aty128fb.o
+  endif
 endif
 
 ifeq ($(CONFIG_FB_IGA),y)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/aty128fb.c linux.19p18/drivers/video/aty128fb.c
--- linux.vanilla/drivers/video/aty128fb.c	Mon Dec 11 22:13:02 2000
+++ linux.19p18/drivers/video/aty128fb.c	Thu Feb 15 16:12:01 2001
@@ -262,7 +262,6 @@
     int chip_gen;
     struct aty128fb_par default_par, current_par;
     struct display disp;
-    struct display_switch dispsw;       /* for cursor and font */
     struct { u8 red, green, blue, pad; } palette[256];
 #ifdef CONFIG_PMAC_PBOOK
     unsigned char *save_framebuffer;
@@ -1436,29 +1435,25 @@
     switch (bpp) {
 #ifdef FBCON_HAS_CFB8
     case 8:
-	info->dispsw = accel ? fbcon_aty128_8 : fbcon_cfb8;
-        disp->dispsw = &info->dispsw;
+	disp->dispsw = accel ? &fbcon_aty128_8 : &fbcon_cfb8;
 	break;
 #endif
 #ifdef FBCON_HAS_CFB16
     case 15:
     case 16:
-	info->dispsw = accel ? fbcon_aty128_16 : fbcon_cfb16;
-        disp->dispsw = &info->dispsw;
+	disp->dispsw = accel ? &fbcon_aty128_16 : &fbcon_cfb16;
 	disp->dispsw_data = info->fbcon_cmap.cfb16;
 	break;
 #endif
 #ifdef FBCON_HAS_CFB24
     case 24:
-	info->dispsw = accel ? fbcon_aty128_24 : fbcon_cfb24;
-        disp->dispsw = &info->dispsw;
+	disp->dispsw = accel ? &fbcon_aty128_24 : &fbcon_cfb24;
 	disp->dispsw_data = info->fbcon_cmap.cfb24;
 	break;
 #endif
 #ifdef FBCON_HAS_CFB32
     case 32:
-	info->dispsw = accel ? fbcon_aty128_32 : fbcon_cfb32;
-        disp->dispsw = &info->dispsw;
+	disp->dispsw = accel ? &fbcon_aty128_32 : &fbcon_cfb32;
 	disp->dispsw_data = info->fbcon_cmap.cfb32;
 	break;
 #endif
@@ -1752,18 +1747,17 @@
     memset(&var, 0, sizeof(var));
 
 #ifdef CONFIG_FB_OF
-    if (default_vmode == VMODE_CHOOSE) {
-#endif /* CONFIG_FB_OF */
+    /* New iBook */
+    if (default_vmode == VMODE_CHOOSE &&
+    	machine_is_compatible("PowerBook2,2"))
+        default_vmode = VMODE_800_600_60;
+        
+    if (default_vmode == VMODE_CHOOSE)
+        var = default_var;
+    else if (mac_vmode_to_var(default_vmode, default_cmode, &var))
+	var = default_var;
+#else /* CONFIG_FB_OF */
         var = default_var;
-
-#ifdef CONFIG_FB_OF
-	/* New iBook */
-	if (machine_is_compatible("PowerBook2,2"))
-		default_vmode = VMODE_800_600_60;
-    } else {
-	if (mac_vmode_to_var(default_vmode, default_cmode, &var))
-	    var = default_var;
-    }
 #endif /* CONFIG_FB_OF */
 
 #endif /* MODULE */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/mdacon.c linux.19p18/drivers/video/mdacon.c
--- linux.vanilla/drivers/video/mdacon.c	Sun Jun 11 21:44:18 2000
+++ linux.19p18/drivers/video/mdacon.c	Tue Dec 19 02:11:55 2000
@@ -75,14 +75,10 @@
 
 static struct vc_data	*mda_display_fg = NULL;
 
-#ifdef MODULE_PARM
 MODULE_PARM(mda_first_vc, "1-255i");
 MODULE_PARM(mda_last_vc,  "1-255i");
-#endif
-
 
-/* MDA register values
- */
+/* MDA register values */
 
 #define MDA_CURSOR_BLINKING	0x00
 #define MDA_CURSOR_OFF		0x20
@@ -200,11 +196,7 @@
 }
 #endif
 
-#ifdef MODULE
-static int mda_detect(void)
-#else
 __initfunc(static int mda_detect(void))
-#endif
 {
 	int count=0;
 	u16 *p, p_save;
@@ -287,11 +279,7 @@
 	return 1;
 }
 
-#ifdef MODULE
-static void mda_initialize(void)
-#else
 __initfunc(static void mda_initialize(void))
-#endif
 {
 	write_mda_b(97, 0x00);		/* horizontal total */
 	write_mda_b(80, 0x01);		/* horizontal displayed */
@@ -316,11 +304,7 @@
 	outb_p(0x00, mda_gfx_port);
 }
 
-#ifdef MODULE
-static const char *mdacon_startup(void)
-#else
 __initfunc(static const char *mdacon_startup(void))
-#endif
 {
 	mda_num_columns = 80;
 	mda_num_lines   = 25;
@@ -606,11 +590,7 @@
 	mdacon_invert_region,	/* con_invert_region */
 };
 
-#ifdef MODULE
-void mda_console_init(void)
-#else
 __initfunc(void mda_console_init(void))
-#endif
 {
 	if (mda_first_vc > mda_last_vc)
 		return;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/promcon.c linux.19p18/drivers/video/promcon.c
--- linux.vanilla/drivers/video/promcon.c	Fri Apr 21 12:46:40 2000
+++ linux.19p18/drivers/video/promcon.c	Tue Feb 20 13:28:55 2001
@@ -1,4 +1,4 @@
-/* $Id: promcon.c,v 1.15 1999/04/22 06:35:32 davem Exp $
+/* $Id: promcon.c,v 1.14 1999/03/09 14:02:42 davem Exp $
  * Console driver utilizing PROM sun terminal emulation
  *
  * Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/drivers/video/tgafb.c linux.19p18/drivers/video/tgafb.c
--- linux.vanilla/drivers/video/tgafb.c	Fri Apr 21 12:46:40 2000
+++ linux.19p18/drivers/video/tgafb.c	Thu Feb  1 15:26:38 2001
@@ -59,7 +59,7 @@
 static int current_par_valid = 0;
 static struct display disp;
 
-static char __initdata default_fontname[40] = { 0 };
+static char default_fontname[40] __initdata = { 0 };
 static struct fb_var_screeninfo default_var;
 static int default_var_valid = 0;
 
@@ -1083,6 +1083,11 @@
 	fb_info.gen.info.modename);
 }
 
+    /*
+     *  Modularisation
+     */
+
+#ifdef MODULE
 
     /*
      *  Cleanup
@@ -1093,12 +1098,6 @@
     unregister_framebuffer(info);
 }
 
-
-    /*
-     *  Modularisation
-     */
-
-#ifdef MODULE
 int init_module(void)
 {
     tgafb_init();
@@ -1107,7 +1106,7 @@
 
 void cleanup_module(void)
 {
-    tgafb_cleanup(void);
+    tgafb_cleanup(&fb_info.gen.info);
 }
 #endif /* MODULE */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/Config.in linux.19p18/fs/Config.in
--- linux.vanilla/fs/Config.in	Mon Dec 11 22:13:02 2000
+++ linux.19p18/fs/Config.in	Wed Feb  7 09:38:47 2001
@@ -76,9 +76,11 @@
     bool '   Root file system on NFS' CONFIG_ROOT_NFS
   fi
   tristate 'NFS server support' CONFIG_NFSD
-  if [ "$CONFIG_NFSD" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
-    bool '   NFS Version 3 server support (EXPERIMENTAL)' CONFIG_NFSD_V3
-    bool '   NFS server TCP support (VERY EXPERIMENTAL)' CONFIG_NFSD_TCP
+  if [ "$CONFIG_NFSD" != "n" ]; then
+    bool '   NFS Version 3 server support' CONFIG_NFSD_V3
+    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      bool '   NFS server TCP support (VERY EXPERIMENTAL)' CONFIG_NFSD_TCP
+    fi
   fi
   if [ "$CONFIG_NFS_FS" = "y" -o "$CONFIG_NFSD" = "y" ]; then
     define_bool CONFIG_SUNRPC y
@@ -115,6 +117,7 @@
 
 bool 'BSD disklabel (BSD partition tables) support' CONFIG_BSD_DISKLABEL
 bool 'Macintosh partition map support' CONFIG_MAC_PARTITION
+bool 'Minix subpartition support' CONFIG_MINIX_SUBPARTITION
 bool 'SMD disklabel (Sun partition tables) support' CONFIG_SMD_DISKLABEL
 bool 'Solaris (x86) partition table support' CONFIG_SOLARIS_X86_PARTITION
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/binfmt_aout.c linux.19p18/fs/binfmt_aout.c
--- linux.vanilla/fs/binfmt_aout.c	Fri Apr 21 12:46:41 2000
+++ linux.19p18/fs/binfmt_aout.c	Wed Feb  7 09:52:29 2001
@@ -62,9 +62,9 @@
 static int dump_write(struct file *file, const void *addr, int nr)
 {
 	int r;
-	down(&file->f_dentry->d_inode->i_sem);
+	fs_down(&file->f_dentry->d_inode->i_sem);
 	r = file->f_op->write(file, addr, nr, &file->f_pos) == nr;
-	up(&file->f_dentry->d_inode->i_sem);
+	fs_up(&file->f_dentry->d_inode->i_sem);
 	return r;
 }
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/binfmt_elf.c linux.19p18/fs/binfmt_elf.c
--- linux.vanilla/fs/binfmt_elf.c	Mon Dec 11 22:13:02 2000
+++ linux.19p18/fs/binfmt_elf.c	Tue Feb 27 16:30:13 2001
@@ -113,6 +113,7 @@
 	char *k_platform, *u_platform;
 	long hwcap;
 	size_t platform_len = 0;
+	long len;
 
 	/*
 	 * Get hold of platform and hardware capabilities masks for
@@ -191,13 +192,21 @@
 	current->mm->arg_start = (unsigned long) p;
 	while (argc-->0) {
 		__put_user((elf_caddr_t)(unsigned long)p,argv++);
-		p += strlen_user(p);
+		len = strnlen_user(p, PAGE_SIZE*MAX_ARG_PAGES);
+		/* "can't happen" */
+		if (!len || len > PAGE_SIZE*MAX_ARG_PAGES)
+			return NULL;
+		p += len;
 	}
 	__put_user(NULL, argv);
 	current->mm->arg_end = current->mm->env_start = (unsigned long) p;
 	while (envc-->0) {
 		__put_user((elf_caddr_t)(unsigned long)p,envp++);
-		p += strlen_user(p);
+		len = strnlen_user(p, PAGE_SIZE*MAX_ARG_PAGES);
+		/* "can't happen" */
+		if (!len || len > PAGE_SIZE*MAX_ARG_PAGES)
+			return NULL;
+		p += len;
 	}
 	__put_user(NULL, envp);
 	current->mm->env_end = (unsigned long) p;
@@ -706,7 +715,7 @@
 				elf_interpreter);
 			kfree(elf_interpreter);
 			kfree(elf_phdata);
-			send_sig(SIGSEGV, current, 0);
+			force_sig(SIGSEGV, current);
 			return 0;
 		}
 
@@ -729,9 +738,6 @@
 	if (current->binfmt && current->binfmt->module)
 		__MOD_INC_USE_COUNT(current->binfmt->module);
 
-#ifndef VM_STACK_FLAGS
-	current->executable = dget(bprm->dentry);
-#endif
 	compute_creds(bprm);
 	current->flags &= ~PF_FORKNOEXEC;
 	bprm->p = (unsigned long)
@@ -742,6 +748,10 @@
 			load_addr, load_bias,
 			interp_load_addr,
 			(interpreter_type == INTERPRETER_AOUT ? 0 : 1));
+	if (!bprm->p) {
+		force_sig(SIGSEGV, current);
+		return 0;
+	}
 	/* N.B. passed_fileno might not be initialized? */
 	if (interpreter_type == INTERPRETER_AOUT)
 		current->mm->arg_start += strlen(passed_fileno) + 1;
@@ -948,9 +958,9 @@
 static int dump_write(struct file *file, const void *addr, int nr)
 {
 	int r;
-	down(&file->f_dentry->d_inode->i_sem);
+	fs_down(&file->f_dentry->d_inode->i_sem);
 	r = file->f_op->write(file, addr, nr, &file->f_pos) == nr;
-	up(&file->f_dentry->d_inode->i_sem);
+	fs_up(&file->f_dentry->d_inode->i_sem);
 	return r;
 }
 
@@ -1056,7 +1066,7 @@
 #undef DUMP_SEEK
 
 #define DUMP_WRITE(addr, nr)	\
-	if (!dump_write(file, (addr), (nr))) \
+	if ((size += (nr)) > limit || !dump_write(file, (addr), (nr))) \
 		goto close_coredump;
 #define DUMP_SEEK(off)	\
 	if (!dump_seek(file, (off))) \
@@ -1078,7 +1088,7 @@
 	char corefile[6+sizeof(current->comm)];
 	int segs;
 	int i;
-	size_t size;
+	size_t size = 0;
 	struct vm_area_struct *vma;
 	struct elfhdr elf;
 	off_t offset = 0, dataoff;
@@ -1099,24 +1109,10 @@
 	MOD_INC_USE_COUNT;
 #endif
 
-	/* Count what's needed to dump, up to the limit of coredump size */
-	segs = 0;
-	size = 0;
-	for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
-		if (maydump(vma))
-		{
-			unsigned long sz = vma->vm_end-vma->vm_start;
-
-			if (size+sz >= limit)
-				break;
-			else
-				size += sz;
-		}
+	segs = current->mm->map_count;
 
-		segs++;
-	}
 #ifdef DEBUG
-	printk("elf_core_dump: %d segs taking %d bytes\n", segs, size);
+	printk("elf_core_dump: %d segs %lu limit\n", segs, limit);
 #endif
 
 	/* Set up header */
@@ -1294,13 +1290,10 @@
 	dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
 
 	/* Write program headers for segments dump */
-	for(vma = current->mm->mmap, i = 0;
-		i < segs && vma != NULL; vma = vma->vm_next) {
+	for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
 		struct elf_phdr phdr;
 		size_t sz;
 
-		i++;
-
 		sz = vma->vm_end - vma->vm_start;
 
 		phdr.p_type = PT_LOAD;
@@ -1326,19 +1319,36 @@
 
 	DUMP_SEEK(dataoff);
 
-	for(i = 0, vma = current->mm->mmap;
-	    i < segs && vma != NULL;
-	    vma = vma->vm_next) {
-		unsigned long addr = vma->vm_start;
-		unsigned long len = vma->vm_end - vma->vm_start;
+	for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
+		unsigned long addr;
 
-		i++;
 		if (!maydump(vma))
 			continue;
 #ifdef DEBUG
 		printk("elf_core_dump: writing %08lx %lx\n", addr, len);
 #endif
-		DUMP_WRITE((void *)addr, len);
+		for (addr = vma->vm_start;
+		     addr < vma->vm_end;
+		     addr += PAGE_SIZE) {
+			pgd_t *pgd;
+			pmd_t *pmd;
+			pte_t *pte;
+
+			pgd = pgd_offset(vma->vm_mm, addr);
+			pmd = pmd_alloc(pgd, addr);
+	
+			if (!pmd)
+				goto end_coredump;
+			pte = pte_alloc(pmd, addr);
+			if (!pte)
+				goto end_coredump;
+			if (!pte_present(*pte) &&
+			    pte_none(*pte)) {
+				DUMP_SEEK (file->f_pos + PAGE_SIZE);
+			} else {
+				DUMP_WRITE((void*)addr, PAGE_SIZE);
+			}
+		}
 	}
 
 	if ((off_t) file->f_pos != offset) {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/binfmt_misc.c linux.19p18/fs/binfmt_misc.c
--- linux.vanilla/fs/binfmt_misc.c	Mon Dec 11 22:13:02 2000
+++ linux.19p18/fs/binfmt_misc.c	Sun Mar 11 13:49:55 2001
@@ -41,9 +41,11 @@
 #error You really need /proc support for binfmt_misc. Please reconfigure!
 #endif
 
-#define VERBOSE_STATUS /* undef this to save 400 bytes kernel memory */
+enum {
+	VERBOSE_STATUS = 1 /* define as zero to save 400 bytes kernel memory */
+};
 
-struct binfmt_entry {
+typedef struct binfmt_entry {
 	struct binfmt_entry *next;
 	long id;
 	int flags;			/* type, status, etc. */
@@ -52,16 +54,15 @@
 	char *magic;			/* magic or filename extension */
 	char *mask;			/* mask, NULL for exact match */
 	char *interpreter;		/* filename of interpreter */
-	char *proc_name;
+	char *name;
 	struct proc_dir_entry *proc_dir;
-};
+} Node;
 
-#define ENTRY_ENABLED 1		/* the old binfmt_entry.enabled */
-#define	ENTRY_MAGIC 8		/* not filename detection */
+enum { Enabled, Magic };
 
 static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs);
-static void entry_proc_cleanup(struct binfmt_entry *e);
-static int entry_proc_setup(struct binfmt_entry *e);
+static void entry_proc_cleanup(Node *e);
+static int entry_proc_setup(Node *e);
 
 static struct linux_binfmt misc_format = {
 #ifndef MODULE
@@ -73,7 +74,7 @@
 
 static struct proc_dir_entry *bm_dir = NULL;
 
-static struct binfmt_entry *entries = NULL;
+static Node *entries = NULL;
 static int free_id = 1;
 static int enabled = 1;
 
@@ -85,7 +86,7 @@
  */
 static void clear_entry(int id)
 {
-	struct binfmt_entry **ep, *e;
+	Node **ep, *e;
 
 	write_lock(&entries_lock);
 	ep = &entries;
@@ -106,7 +107,7 @@
  */
 static void clear_entries(void)
 {
-	struct binfmt_entry *e, *n;
+	Node *e, *n;
 
 	write_lock(&entries_lock);
 	n = entries;
@@ -123,9 +124,9 @@
 /*
  * Find entry through id and lock it
  */
-static struct binfmt_entry *get_entry(int id)
+static Node *get_entry(int id)
 {
-	struct binfmt_entry *e;
+	Node *e;
 
 	read_lock(&entries_lock);
 	e = entries;
@@ -139,7 +140,7 @@
 /*
  * unlock entry
  */
-static inline void put_entry(struct binfmt_entry *e)
+static inline void put_entry(Node *e)
 {
 	if (e)
 		read_unlock(&entries_lock);
@@ -148,19 +149,19 @@
 
 /* 
  * Check if we support the binfmt
- * if we do, return the binfmt_entry, else NULL
+ * if we do, return the node, else NULL
  * locking is done in load_misc_binary
  */
-static struct binfmt_entry *check_file(struct linux_binprm *bprm)
+static Node *check_file(struct linux_binprm *bprm)
 {
-	struct binfmt_entry *e;
+	Node *e;
 	char *p = strrchr(bprm->filename, '.');
 	int j;
 
 	e = entries;
 	while (e) {
-		if (e->flags & ENTRY_ENABLED) {
-			if (!(e->flags & ENTRY_MAGIC)) {
+		if (test_bit(Enabled, &e->flags)) {
+			if (!test_bit(Magic, &e->flags)) {
 				if (p && !strcmp(e->magic, p + 1))
 					return e;
 			} else {
@@ -183,7 +184,7 @@
  */
 static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 {
-	struct binfmt_entry *fmt;
+	Node *fmt;
 	struct dentry * dentry;
 	char iname[128];
 	char *iname_addr = iname;
@@ -233,46 +234,44 @@
 	return retval;
 }
 
-
-
-/*
- * /proc handling routines
- */
-
 /*
  * parses and copies one argument enclosed in del from *sp to *dp,
  * recognising the \x special.
  * returns pointer to the copied argument or NULL in case of an
  * error (and sets err) or null argument length.
  */
-static char *copyarg(char **dp, const char **sp, int *count,
-		     char del, int special, int *err)
+static char *scanarg(char *s, char del)
 {
-	char c = 0, *res = *dp;
+	char c;
 
-	while (!*err && ((c = *((*sp)++)), (*count)--) && (c != del)) {
-		switch (c) {
-		case '\\':
-			if (special && (**sp == 'x')) {
-				if (!isxdigit(c = toupper(*(++*sp))))
-					*err = -EINVAL;
-				**dp = (c - (isdigit(c) ? '0' : 'A' - 10)) * 16;
-				if (!isxdigit(c = toupper(*(++*sp))))
-					*err = -EINVAL;
-				*((*dp)++) += c - (isdigit(c) ? '0' : 'A' - 10);
-				++*sp;
-				*count -= 3;
-				break;
-			}
-		default:
-			*((*dp)++) = c;
+	while ((c = *s++) != del) {
+		if (c == '\\' && *s == 'x') {
+			s++;
+			if (!isxdigit(*s++))
+				return NULL;
+			if (!isxdigit(*s++))
+				return NULL;
+		}
+	}
+	return s;
+}
+
+static int unquote(char *from)
+{
+	char c = 0, *s = from, *p = from;
+
+	while ((c = *s++) != '\0') {
+		if (c == '\\' && *s == 'x') {
+			s++;
+			c = toupper(*s++);
+			*p = (c - (isdigit(c) ? '0' : 'A' - 10)) << 4;
+			c = toupper(*s++);
+			*p++ |= c - (isdigit(c) ? '0' : 'A' - 10);
+			continue;
 		}
+		*p++ = c;
 	}
-	if (*err || (c != del) || (res == *dp))
-		res = NULL;
-	else if (!special)
-		*((*dp)++) = '\0';
-	return res;
+	return p - from;
 }
 
 /*
@@ -280,59 +279,197 @@
  * ':name:type:offset:magic:mask:interpreter:'
  * where the ':' is the IFS, that can be chosen with the first char
  */
-static int proc_write_register(struct file *file, const char *buffer,
-			       unsigned long count, void *data)
+static Node *create_entry(const char *buffer, size_t count)
 {
-	const char *sp;
-	char del, *dp;
-	struct binfmt_entry *e;
-	int memsize, cnt = count - 1, err;
+	Node *e;
+	int memsize, err;
+	char *buf, *p;
+	char del;
 
 	/* some sanity checks */
 	err = -EINVAL;
 	if ((count < 11) || (count > 256))
-		goto _err;
+		goto out;
 
 	err = -ENOMEM;
-	memsize = sizeof(struct binfmt_entry) + count;
-	if (!(e = (struct binfmt_entry *) kmalloc(memsize, GFP_USER)))
-		goto _err;
-
-	err = 0;
-	sp = buffer + 1;
-	del = buffer[0];
-	dp = (char *)e + sizeof(struct binfmt_entry);
-
-	e->proc_name = copyarg(&dp, &sp, &cnt, del, 0, &err);
-
-	/* we can use bit 3 of type for ext/magic
-	   flag due to the nice encoding of E and M */
-	if ((*sp & ~('E' | 'M')) || (sp[1] != del))
-		err = -EINVAL;
-	else
-		e->flags = (*sp++ & (ENTRY_MAGIC | ENTRY_ENABLED));
-	cnt -= 2; sp++;
+	memsize = sizeof(Node) + count + 8;
+	e = (Node *) kmalloc(memsize, GFP_USER);
+	if (!e)
+		goto out;
 
-	e->offset = 0;
-	while (cnt-- && isdigit(*sp))
-		e->offset = e->offset * 10 + *sp++ - '0';
-	if (*sp++ != del)
-		err = -EINVAL;
-
-	e->magic = copyarg(&dp, &sp, &cnt, del, (e->flags & ENTRY_MAGIC), &err);
-	e->size = dp - e->magic;
-	e->mask = copyarg(&dp, &sp, &cnt, del, 1, &err);
-	if (e->mask && ((dp - e->mask) != e->size))
-		err = -EINVAL;
-	e->interpreter = copyarg(&dp, &sp, &cnt, del, 0, &err);
-	e->id = free_id++;
+	p = buf = (char *)e + sizeof(Node);
+
+	memset(e, 0, sizeof(Node));
+	if (copy_from_user(buf, buffer, count))
+		goto Efault;
+
+	del = *p++;	/* delimeter */
+
+	memset(buf+count, del, 8);
+
+	e->name = p;
+	p = strchr(p, del);
+	if (!p)
+		goto Einval;
+	*p++ = '\0';
+	if (!e->name[0] ||
+	    !strcmp(e->name, ".") ||
+	    !strcmp(e->name, "..") ||
+	    strchr(e->name, '/'))
+		goto Einval;
+	switch (*p++) {
+		case 'E': e->flags = 1<<Enabled; break;
+		case 'M': e->flags = (1<<Enabled) | (1<<Magic); break;
+		default: goto Einval;
+	}
+	if (*p++ != del)
+		goto Einval;
+	if (test_bit(Magic, &e->flags)) {
+		char *s = strchr(p, del);
+		if (!s)
+			goto Einval;
+		*s++ = '\0';
+		e->offset = simple_strtoul(p, &p, 10);
+		if (*p++)
+			goto Einval;
+		e->magic = p;
+		p = scanarg(p, del);
+		if (!p)
+			goto Einval;
+		p[-1] = '\0';
+		if (!e->magic[0])
+			goto Einval;
+		e->mask = p;
+		p = scanarg(p, del);
+		if (!p)
+			goto Einval;
+		p[-1] = '\0';
+		if (!e->mask[0])
+			e->mask = NULL;
+		e->size = unquote(e->magic);
+		if (e->mask && unquote(e->mask) != e->size)
+			goto Einval;
+		if (e->size + e->offset > 128)
+			goto Einval;
+	} else {
+		p = strchr(p, del);
+		if (!p)
+			goto Einval;
+		*p++ = '\0';
+		e->magic = p;
+		p = strchr(p, del);
+		if (!p)
+			goto Einval;
+		*p++ = '\0';
+		if (!e->magic[0] || strchr(e->magic, '/'))
+			goto Einval;
+		p = strchr(p, del);
+		if (!p)
+			goto Einval;
+		*p++ = '\0';
+	}
+	e->interpreter = p;
+	p = strchr(p, del);
+	if (!p)
+		goto Einval;
+	*p++ = '\0';
+	if (!e->interpreter[0])
+		goto Einval;
+
+	if (*p == '\n')
+		p++;
+	if (p != buf + count)
+		goto Einval;
+	return e;
+
+out:
+	return ERR_PTR(err);
+
+Efault:
+	kfree(e);
+	return ERR_PTR(-EFAULT);
+Einval:
+	kfree(e);
+	return ERR_PTR(-EINVAL);
+}
+
+/*
+ * Set status of entry/binfmt_misc:
+ * '1' enables, '0' disables and '-1' clears entry/binfmt_misc
+ */
+static int parse_command(const char *buffer, size_t count)
+{
+	char s[4];
+
+	if (!count)
+		return 0;
+	if (count > 3)
+		return -EINVAL;
+	if (copy_from_user(s, buffer, count))
+		return -EFAULT;
+	if (s[count-1] == '\n')
+		count--;
+	if (count == 1 && s[0] == '0')
+		return 1;
+	if (count == 1 && s[0] == '1')
+		return 2;
+	if (count == 2 && s[0] == '-' && s[1] == '1')
+		return 3;
+	return -EINVAL;
+}
+
+static void entry_status(Node *e, char *page)
+{
+	char *dp;
+	char *status = "disabled";
 
-	/* more sanity checks */
-	if (err || !(!cnt || (!(--cnt) && (*sp == '\n'))) ||
-	    (e->size < 1) || ((e->size + e->offset) > 127) ||
-	    !(e->proc_name) || !(e->interpreter) || entry_proc_setup(e))
+	if (test_bit(Enabled, &e->flags))
+		status = "enabled";
+
+	if (!VERBOSE_STATUS) {
+		sprintf(page, "%s\n", status);
+		return;
+	}
+
+	sprintf(page, "%s\ninterpreter %s\n", status, e->interpreter);
+	dp = page + strlen(page);
+	if (!test_bit(Magic, &e->flags)) {
+		sprintf(dp, "extension .%s\n", e->magic);
+	} else {
+		int i;
+
+		sprintf(dp, "offset %i\nmagic ", e->offset);
+		dp = page + strlen(page);
+		for (i = 0; i < e->size; i++) {
+			sprintf(dp, "%02x", 0xff & (int) (e->magic[i]));
+			dp += 2;
+		}
+		if (e->mask) {
+			sprintf(dp, "\nmask ");
+			dp += 6;
+			for (i = 0; i < e->size; i++) {
+				sprintf(dp, "%02x", 0xff & (int) (e->mask[i]));
+				dp += 2;
+			}
+		}
+		*dp++ = '\n';
+		*dp = '\0';
+	}
+}
+
+static int proc_write_register(struct file *file, const char *buffer,
+			       unsigned long count, void *data)
+{
+	Node *e = create_entry(buffer, count);
+	int err;
+
+	if (IS_ERR(e))
+		return PTR_ERR(e);
+	
+	if (entry_proc_setup(e))
 		goto free_err;
 
+	e->id = free_id++;
 	write_lock(&entries_lock);
 	e->next = entries;
 	entries = e;
@@ -355,68 +492,24 @@
 static int proc_read_status(char *page, char **start, off_t off,
 			    int count, int *eof, void *data)
 {
-	struct binfmt_entry *e;
-	char *dp;
-	int elen, i, err;
+	Node *e;
+	int elen;
 
-#ifndef VERBOSE_STATUS
-	if (data) {
-		if (!(e = get_entry((int) data))) {
-			err = -ENOENT;
-			goto _err;
-		}
-		i = e->flags & ENTRY_ENABLED;
-		put_entry(e);
-	} else {
-		i = enabled;
-	} 
-	sprintf(page, "%s\n", (i ? "enabled" : "disabled"));
-#else
-	if (!data)
+	if (!data) {
 		sprintf(page, "%s\n", (enabled ? "enabled" : "disabled"));
-	else {
-		if (!(e = get_entry((long) data))) {
-			err = -ENOENT;
-			goto _err;
-		}
-		sprintf(page, "%s\ninterpreter %s\n",
-		        (e->flags & ENTRY_ENABLED ? "enabled" : "disabled"),
-			e->interpreter);
-		dp = page + strlen(page);
-		if (!(e->flags & ENTRY_MAGIC)) {
-			sprintf(dp, "extension .%s\n", e->magic);
-			dp = page + strlen(page);
-		} else {
-			sprintf(dp, "offset %i\nmagic ", e->offset);
-			dp = page + strlen(page);
-			for (i = 0; i < e->size; i++) {
-				sprintf(dp, "%02x", 0xff & (int) (e->magic[i]));
-				dp += 2;
-			}
-			if (e->mask) {
-				sprintf(dp, "\nmask ");
-				dp += 6;
-				for (i = 0; i < e->size; i++) {
-					sprintf(dp, "%02x", 0xff & (int) (e->mask[i]));
-					dp += 2;
-				}
-			}
-			*dp++ = '\n';
-			*dp = '\0';
-		}
+	} else {
+		if (!(e = get_entry((long) data)))
+			return -ENOENT;
+		entry_status(e, page);
 		put_entry(e);
 	}
-#endif
 
 	elen = strlen(page) - off;
 	if (elen < 0)
 		elen = 0;
 	*eof = (elen <= count) ? 1 : 0;
 	*start = page + off;
-	err = elen;
-
-_err:
-	return err;
+	return elen;
 }
 
 /*
@@ -426,45 +519,50 @@
 static int proc_write_status(struct file *file, const char *buffer,
 			     unsigned long count, void *data)
 {
-	struct binfmt_entry *e;
-	int res = count;
+	Node *e;
+	int res = parse_command(buffer, count);
 
-	if (buffer[count-1] == '\n')
-		count--;
-	if ((count == 1) && !(buffer[0] & ~('0' | '1'))) {
-		if (data) {
-			if ((e = get_entry((long) data)))
-				e->flags = (e->flags & ~ENTRY_ENABLED)
-					    | (int)(buffer[0] - '0');
-			put_entry(e);
-		} else {
-			enabled = buffer[0] - '0';
-		}
-	} else if ((count == 2) && (buffer[0] == '-') && (buffer[1] == '1')) {
-		if (data)
-			clear_entry((long) data);
-		else
-			clear_entries();
-	} else {
-		res = -EINVAL;
+	switch(res) {
+		case 1: if (data) {
+				if ((e = get_entry((long) data)))
+					clear_bit(Enabled, &e->flags);
+				put_entry(e);
+			} else {
+				enabled = 0;
+			}
+			break;
+		case 2: if (data) {
+				if ((e = get_entry((long) data)))
+					set_bit(Enabled, &e->flags);
+				put_entry(e);
+			} else {
+				enabled = 1;
+			}
+			break;
+		case 3: if (data)
+				clear_entry((long) data);
+			else
+				clear_entries();
+			break;
+		default: return res;
 	}
-	return res;
+	return count;
 }
 
 /*
  * Remove the /proc-dir entries of one binfmt
  */
-static void entry_proc_cleanup(struct binfmt_entry *e)
+static void entry_proc_cleanup(Node *e)
 {
-	remove_proc_entry(e->proc_name, bm_dir);
+	remove_proc_entry(e->name, bm_dir);
 }
 
 /*
  * Create the /proc-dir entry for binfmt
  */
-static int entry_proc_setup(struct binfmt_entry *e)
+static int entry_proc_setup(Node *e)
 {
-	if (!(e->proc_dir = create_proc_entry(e->proc_name,
+	if (!(e->proc_dir = create_proc_entry(e->name,
 			 	S_IFREG | S_IRUGO | S_IWUSR, bm_dir)))
 	{
 		printk(KERN_WARNING "Unable to create /proc entry.\n");
@@ -545,4 +643,3 @@
 	remove_proc_entry("sys/fs/binfmt_misc", NULL);
 }
 #endif
-#undef VERBOSE_STATUS
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/buffer.c linux.19p18/fs/buffer.c
--- linux.vanilla/fs/buffer.c	Mon Dec 11 22:13:02 2000
+++ linux.19p18/fs/buffer.c	Sat Dec 16 17:21:47 2000
@@ -83,6 +83,7 @@
 
 static int nr_buffers = 0;
 static int nr_buffers_type[NR_LIST] = {0,};
+static unsigned long size_buffers_type[NR_LIST];
 static int nr_buffer_heads = 0;
 static int nr_unused_buffer_heads = 0;
 static int nr_hashed_buffers = 0;
@@ -359,9 +360,9 @@
 		goto out_putf;
 
 	/* We need to protect against concurrent writers.. */
-	down(&inode->i_sem);
+	fs_down(&inode->i_sem);
 	err = file->f_op->fsync(file, dentry);
-	up(&inode->i_sem);
+	fs_up(&inode->i_sem);
 
 out_putf:
 	fput(file);
@@ -396,9 +397,9 @@
 		goto out_putf;
 
 	/* this needs further work, at the moment it is identical to fsync() */
-	down(&inode->i_sem);
+	fs_down(&inode->i_sem);
 	err = file->f_op->fsync(file, dentry);
-	up(&inode->i_sem);
+	fs_up(&inode->i_sem);
 
 out_putf:
 	fput(file);
@@ -474,6 +475,7 @@
 		return;
 	}
 	nr_buffers_type[bh->b_list]--;
+	size_buffers_type[bh->b_list] -= bh->b_size;
 	remove_from_hash_queue(bh);
 	remove_from_lru_list(bh);
 }
@@ -523,6 +525,7 @@
 		(*bhp)->b_prev_free = bh;
 
 		nr_buffers_type[bh->b_list]++;
+		size_buffers_type[bh->b_list] += bh->b_size;
 
 		/* Put the buffer in new hash-queue if it has a device. */
 		bh->b_next = NULL;
@@ -571,8 +574,10 @@
 {
 	struct buffer_head * bh;
 	bh = find_buffer(dev,block,size);
-	if (bh)
+	if (bh) {
 		bh->b_count++;
+		touch_buffer(bh);
+	}
 	return bh;
 }
 
@@ -816,6 +821,46 @@
 	insert_into_queues(bh);
 }
 
+/* -1 -> no need to flush
+    0 -> async flush
+    1 -> sync flush (wait for I/O completation) */
+static int balance_dirty_state(kdev_t dev)
+{
+	unsigned long dirty, tot, hard_dirty_limit, soft_dirty_limit;
+
+	dirty = size_buffers_type[BUF_DIRTY] >> PAGE_SHIFT;
+	tot = (buffermem >> PAGE_SHIFT) + nr_free_pages;
+	tot -= size_buffers_type[BUF_PROTECTED] >> PAGE_SHIFT;
+
+	dirty *= 200;
+	soft_dirty_limit = tot * bdf_prm.b_un.nfract;
+	hard_dirty_limit = soft_dirty_limit * 2;
+
+	if (dirty > soft_dirty_limit)
+	{
+		if (dirty > hard_dirty_limit)
+			return 1;
+		return 0;
+	}
+	return -1;
+}
+
+/*
+ * if a new dirty buffer is created we need to balance bdflush.
+ *
+ * in the future we might want to make bdflush aware of different
+ * pressures on different devices - thus the (currently unused)
+ * 'dev' parameter.
+ */
+void balance_dirty(kdev_t dev)
+{
+	int state = balance_dirty_state(dev);
+
+	if (state < 0)
+		return;
+	wakeup_bdflush(state);
+}
+
 /*
  * A buffer may need to be moved from one buffer list to another
  * (e.g. in case it is not shared any more). Handle this.
@@ -828,7 +873,9 @@
 		printk("Attempt to refile free buffer\n");
 		return;
 	}
-	if (buffer_dirty(buf))
+	if (buffer_protected(buf))
+		dispose = BUF_PROTECTED;
+	else if (buffer_dirty(buf))
 		dispose = BUF_DIRTY;
 	else if (buffer_locked(buf))
 		dispose = BUF_LOCKED;
@@ -837,13 +884,7 @@
 	if(dispose != buf->b_list) {
 		file_buffer(buf, dispose);
 		if(dispose == BUF_DIRTY) {
-			int too_many = (nr_buffers * bdf_prm.b_un.nfract/100);
-
-			/* This buffer is dirty, maybe we need to start flushing.
-			 * If too high a percentage of the buffers are dirty...
-			 */
-			if (nr_buffers_type[BUF_DIRTY] > too_many)
-				wakeup_bdflush(1);
+			balance_dirty(buf->b_dev);
 
 			/* If this is a loop device, and
 			 * more than half of the buffers are dirty...
@@ -864,7 +905,6 @@
 	/* If dirty, mark the time this buffer should be written back. */
 	set_writetime(buf, 0);
 	refile_buffer(buf);
-	touch_buffer(buf);
 
 	if (buf->b_count) {
 		buf->b_count--;
@@ -1457,6 +1497,7 @@
 	}
 	tmp->b_this_page = bh;
 	free_list[isize] = bh;
+	mem_map[MAP_NR(page)].flags = 0;
 	mem_map[MAP_NR(page)].buffers = bh;
 	buffermem += PAGE_SIZE;
 	return 1;
@@ -1468,33 +1509,34 @@
 #define BUFFER_BUSY_BITS	((1<<BH_Dirty) | (1<<BH_Lock) | (1<<BH_Protected))
 #define buffer_busy(bh)		((bh)->b_count || ((bh)->b_state & BUFFER_BUSY_BITS))
 
-static int sync_page_buffers(struct page * page, int wait)
+static void sync_page_buffers(struct page * page)
 {
-	struct buffer_head * bh = page->buffers;
-	struct buffer_head * tmp = bh;
+	struct buffer_head * tmp, * bh = page->buffers;
 
+	/*
+	 * Here we'll probably sleep and so we must make sure that
+	 * the page doesn't go away from under us. We also prefer any
+	 * concurrent try_to_free_buffers() not to work in any way on
+	 * our current page from under us since we're just working on it.
+	 * As always in 2.2.x we're serialized by the big kernel lock
+	 * during those hacky page-visibility manipulations.
+	 *
+	 * SUBTLE NOTE: for things like LVM snapshotting WRITEA will block too!
+	 */
 	page->buffers = NULL;
 
+	tmp = bh;
 	do {
 		struct buffer_head *p = tmp;
 		tmp = tmp->b_this_page;
-		if (buffer_locked(p)) {
-			if (wait)
-				__wait_on_buffer(p);
-		} else if (buffer_dirty(p))
-			ll_rw_block(WRITE, 1, &p);
-	} while (tmp != bh);
-
-	page->buffers = bh;
 
-	do {
-		struct buffer_head *p = tmp;
-		tmp = tmp->b_this_page;
-		if (buffer_busy(p))
-			return 1;
+		if (buffer_dirty(p))
+			if (test_and_set_bit(BH_Wait_IO, &p->b_state))
+				ll_rw_block(WRITE, 1, &p);
 	} while (tmp != bh);
 
-	return 0;
+	/* Restore the visibility of the page before returning. */
+	page->buffers = bh;
 }
 
 /*
@@ -1504,10 +1546,9 @@
  * Wake up bdflush() if this fails - if we're running low on memory due
  * to dirty buffers, we need to flush them out as quickly as possible.
  */
-int try_to_free_buffers(struct page * page_map, int wait)
+int try_to_free_buffers(struct page * page_map, int gfp_mask)
 {
 	struct buffer_head * tmp, * bh = page_map->buffers;
-	int too_many;
 
 	tmp = bh;
 	do {
@@ -1516,8 +1557,6 @@
 		tmp = tmp->b_this_page;
 	} while (tmp != bh);
 
- succeed:
-	tmp = bh;
 	do {
 		struct buffer_head * p = tmp;
 		tmp = tmp->b_this_page;
@@ -1536,25 +1575,12 @@
 	return 1;
 
  busy:
-	too_many = (nr_buffers * bdf_prm.b_un.nfract/100);
-
-	if (!sync_page_buffers(page_map, wait)) {
-
-		/* If a high percentage of the buffers are dirty, 
-		 * wake kflushd 
-		 */
-		if (nr_buffers_type[BUF_DIRTY] > too_many)
-			wakeup_bdflush(0);
-			
-		/*
-		 * We can jump after the busy check because
-		 * we rely on the kernel lock.
-		 */
-		goto succeed;
-	}
+	if (gfp_mask & __GFP_IO)
+		sync_page_buffers(page_map);
 
-	if(nr_buffers_type[BUF_DIRTY] > too_many)
+	if (balance_dirty_state(NODEV) >= 0)
 		wakeup_bdflush(0);
+
 	return 0;
 }
 
@@ -1566,7 +1592,7 @@
 	int found = 0, locked = 0, dirty = 0, used = 0, lastused = 0;
 	int protected = 0;
 	int nlist;
-	static char *buf_types[NR_LIST] = {"CLEAN","LOCKED","DIRTY"};
+	static char *buf_types[NR_LIST] = {"CLEAN","LOCKED","DIRTY","PROTECTED",};
 
 	printk("Buffer memory:   %8ldkB\n",buffermem>>10);
 	printk("Buffer heads:    %6d\n",nr_buffer_heads);
@@ -1590,7 +1616,7 @@
 			used++, lastused = found;
 		bh = bh->b_next_free;
 	  } while (bh != lru_list[nlist]);
-	  printk("%8s: %d buffers, %d used (last=%d), "
+	  printk("%9s: %d buffers, %d used (last=%d), "
 		 "%d locked, %d protected, %d dirty\n",
 		 buf_types[nlist], found, used, lastused,
 		 locked, protected, dirty);
@@ -1935,7 +1961,8 @@
 		
 		/* If there are still a lot of dirty buffers around, skip the sleep
 		   and flush some more */
-		if(ndirty == 0 || nr_buffers_type[BUF_DIRTY] <= nr_buffers * bdf_prm.b_un.nfract/100) {
+		if (!ndirty || balance_dirty_state(NODEV) < 0)
+		{
 			spin_lock_irq(&current->sigmask_lock);
 			flush_signals(current);
 			spin_unlock_irq(&current->sigmask_lock);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/coda/file.c linux.19p18/fs/coda/file.c
--- linux.vanilla/fs/coda/file.c	Sat Sep  9 18:42:46 2000
+++ linux.19p18/fs/coda/file.c	Sat Dec 16 17:21:47 2000
@@ -190,10 +190,10 @@
                 return -1;
         }
 
-	down(&cont_inode->i_sem);
+	fs_down(&cont_inode->i_sem);
         result = cont_file.f_op->write(&cont_file , buff, count, 
 				       &(cont_file.f_pos));
-	up(&cont_inode->i_sem);
+	fs_up(&cont_inode->i_sem);
         coda_restore_codafile(coda_inode, coda_file, cont_inode, &cont_file);
 	
 	if (result)
@@ -228,14 +228,14 @@
         coda_prepare_openfile(coda_inode, coda_file, cont_inode, 
 			      &cont_file, &cont_dentry);
 
-	down(&cont_inode->i_sem);
+	fs_down(&cont_inode->i_sem);
 
         result = file_fsync(&cont_file ,&cont_dentry);
 	if ( result == 0 ) {
 		result = venus_fsync(coda_inode->i_sb, &(cnp->c_fid));
 	}
 
-	up(&cont_inode->i_sem);
+	fs_up(&cont_inode->i_sem);
 
         coda_restore_codafile(coda_inode, coda_file, cont_inode, &cont_file);
         return result;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/dcache.c linux.19p18/fs/dcache.c
--- linux.vanilla/fs/dcache.c	Sun Jun 11 21:44:18 2000
+++ linux.19p18/fs/dcache.c	Mon Feb 12 14:52:42 2001
@@ -253,10 +253,15 @@
 
 		if (tmp == &dentry_unused)
 			break;
-		dentry_stat.nr_unused--;
 		list_del(tmp);
-		INIT_LIST_HEAD(tmp);
 		dentry = list_entry(tmp, struct dentry, d_lru);
+		if (dentry->d_flags & DCACHE_REFERENCED) {
+			dentry->d_flags &= ~DCACHE_REFERENCED;
+			list_add(&dentry->d_lru, &dentry_unused);
+			continue;
+		}
+		dentry_stat.nr_unused--;
+		INIT_LIST_HEAD(tmp);
 		if (!dentry->d_count) {
 			i_nr -= prune_one_dentry(dentry);
 			if (!i_nr)
@@ -475,9 +480,9 @@
  */
 void shrink_dcache_memory(int priority, unsigned int gfp_mask)
 {
-	if (gfp_mask & __GFP_IO) {
+	if (gfp_mask & __GFP_IO && !current->fs_locks) {
 		int count = 0;
-		if (priority)
+		if (priority > 1)
 			count = dentry_stat.nr_unused / priority;
 		prune_dcache(count, -1);
 	}
@@ -568,7 +573,7 @@
 static inline struct list_head * d_hash(struct dentry * parent, unsigned long hash)
 {
 	hash += (unsigned long) parent / L1_CACHE_BYTES;
-	hash = hash ^ (hash >> D_HASHBITS) ^ (hash >> D_HASHBITS*2);
+	hash = hash ^ (hash >> D_HASHBITS);
 	return dentry_hashtable + (hash & D_HASHMASK);
 }
 
@@ -598,6 +603,7 @@
 			if (memcmp(dentry->d_name.name, str, len))
 				continue;
 		}
+		dentry->d_flags |= DCACHE_REFERENCED;
 		return dget(dentry);
 	}
 	return NULL;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/dquot.c linux.19p18/fs/dquot.c
--- linux.vanilla/fs/dquot.c	Mon Dec 11 22:13:02 2000
+++ linux.19p18/fs/dquot.c	Wed Jan  3 13:50:15 2001
@@ -570,7 +570,7 @@
 	 */
 	if (prune_dcache(0, 128))
 	{
-		free_inode_memory(10);
+		free_inode_memory();
 		goto repeat;
 	}
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/exec.c linux.19p18/fs/exec.c
--- linux.vanilla/fs/exec.c	Mon Dec 11 22:13:02 2000
+++ linux.19p18/fs/exec.c	Sat Mar  3 22:32:17 2001
@@ -517,8 +517,9 @@
 
 	current->sas_ss_sp = current->sas_ss_size = 0;
 
+	bprm->dumpable = 0;
 	if (current->euid == current->uid && current->egid == current->gid)
-		current->dumpable = 1;
+		bprm->dumpable = !bprm->priv_change;
 	name = bprm->filename;
 	for (i=0; (ch = *(name++)) != '\0';) {
 		if (ch == '/')
@@ -531,10 +532,10 @@
 
 	flush_thread();
 
-	if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || 
-	    permission(bprm->dentry->d_inode,MAY_READ))
-		current->dumpable = 0;
-		
+	if (bprm->e_uid != current->euid || bprm->e_gid != current->egid ||
+	    permission(bprm->dentry->d_inode, MAY_READ))
+		bprm->dumpable = 0;
+
 	current->self_exec_id++;
 
 	flush_signal_handlers(current);
@@ -646,7 +647,8 @@
 		}
 	}
 
-	if (id_change || cap_raised) {
+	bprm->priv_change = id_change || cap_raised;
+	if (bprm->priv_change) {
 		/* We can't suid-execute if we're sharing parts of the executable */
 		/* or if we're being traced (or if suid execs are not allowed)    */
 		/* (current->mm->count > 1 is ok, as we'll get a new mm anyway)   */
@@ -704,7 +706,7 @@
         current->sgid = current->egid = current->fsgid = bprm->e_gid;
         if (current->euid != current->uid || current->egid != current->gid ||
 	    !cap_issubset(new_permitted, current->cap_permitted))
-                current->dumpable = 0;
+                bprm->dumpable = 0;
 
         current->keep_capabilities = 0;
 }
@@ -823,6 +825,7 @@
 {
 	struct linux_binprm bprm;
 	struct dentry * dentry;
+	int was_dumpable;
 	int retval;
 	int i;
 
@@ -851,6 +854,9 @@
 		return bprm.envc;
 	}
 
+	was_dumpable = current->dumpable;
+	current->dumpable = 0;
+
 	retval = prepare_binprm(&bprm);
 	
 	if (retval >= 0) {
@@ -864,9 +870,12 @@
 
 	if (retval >= 0)
 		retval = search_binary_handler(&bprm,regs);
-	if (retval >= 0)
+
+	if (retval >= 0) {
 		/* execve success */
+		current->dumpable = bprm.dumpable;
 		return retval;
+	}
 
 	/* Something went wrong, return the inode and free the argument pages*/
 	if (bprm.dentry)
@@ -874,6 +883,8 @@
 
 	for (i=0 ; i<MAX_ARG_PAGES ; i++)
 		free_page(bprm.page[i]);
+
+	current->dumpable = was_dumpable;
 
 	return retval;
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/fat/misc.c linux.19p18/fs/fat/misc.c
--- linux.vanilla/fs/fat/misc.c	Fri Apr 21 12:46:42 2000
+++ linux.19p18/fs/fat/misc.c	Tue Dec 19 02:06:27 2000
@@ -2,6 +2,8 @@
  *  linux/fs/fat/misc.c
  *
  *  Written 1992,1993 by Werner Almesberger
+ *  22/11/2000 - Fixed fat_date_unix2dos for dates earlier than 01/01/1980
+ *		 and date_dos2unix for date==0 by Igor Zhbanov(bsg@uniyar.ac.ru)
  */
 
 #include <linux/fs.h>
@@ -288,7 +290,9 @@
 {
 	int month,year,secs;
 
-	month = ((date >> 5) & 15)-1;
+	/* first subtract and mask after that... Otherwise, if
+	   date == 0, bad things happen */
+	month = ((date >> 5) - 1) & 15;
 	year = date >> 9;
 	secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400*
 	    ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
@@ -309,6 +313,10 @@
 
 	unix_date -= sys_tz.tz_minuteswest*60;
 	if (sys_tz.tz_dsttime) unix_date += 3600;
+
+	/* Jan 1 GMT 00:00:00 1980. But what about another time zone? */
+	if (unix_date < 315532800)
+		unix_date = 315532800;
 
 	*time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
 	    (((unix_date/3600) % 24) << 11);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/file_table.c linux.19p18/fs/file_table.c
--- linux.vanilla/fs/file_table.c	Fri Apr 21 12:46:42 2000
+++ linux.19p18/fs/file_table.c	Wed Dec 13 21:48:45 2000
@@ -13,9 +13,7 @@
 static kmem_cache_t *filp_cache;
 
 /* sysctl tunables... */
-int nr_files = 0;	/* read only */
-int nr_free_files = 0;	/* read only */
-int max_files = NR_FILE;/* tunable */
+struct files_stat_struct files_stat = {0, 0, NR_FILE};
 
 /* Free list management, if you are here you must have f_count == 0 */
 static struct file * free_filps = NULL;
@@ -26,7 +24,7 @@
 		free_filps->f_pprev = &file->f_next;
 	free_filps = file;
 	file->f_pprev = &free_filps;
-	nr_free_files++;
+	files_stat.nr_free_files++;
 }
 
 /* The list of in-use filp's must be exported (ugh...) */
@@ -72,11 +70,11 @@
 	static int old_max = 0;
 	struct file * f;
 
-	if (nr_free_files > NR_RESERVED_FILES) {
+	if (files_stat.nr_free_files > NR_RESERVED_FILES) {
 	used_one:
 		f = free_filps;
 		remove_filp(f);
-		nr_free_files--;
+		files_stat.nr_free_files--;
 	new_one:
 		memset(f, 0, sizeof(*f));
 		f->f_count = 1;
@@ -89,23 +87,23 @@
 	/*
 	 * Use a reserved one if we're the superuser
 	 */
-	if (nr_free_files && !current->euid)
+	if (files_stat.nr_free_files && !current->euid)
 		goto used_one;
 	/*
 	 * Allocate a new one if we're below the limit.
 	 */
-	if (nr_files < max_files) {
+	if (files_stat.nr_files < files_stat.max_files) {
 		f = kmem_cache_alloc(filp_cache, SLAB_KERNEL);
 		if (f) {
-			nr_files++;
+			files_stat.nr_files++;
 			goto new_one;
 		}
 		/* Big problems... */
 		printk("VFS: filp allocation failed\n");
 
-	} else if (max_files > old_max) {
-		printk("VFS: file-max limit %d reached\n", max_files);
-		old_max = max_files;
+	} else if (files_stat.max_files > old_max) {
+		printk("VFS: file-max limit %d reached\n", files_stat.max_files);
+		old_max = files_stat.max_files;
 	}
 	return NULL;
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/inode.c linux.19p18/fs/inode.c
--- linux.vanilla/fs/inode.c	Mon Dec 11 22:13:02 2000
+++ linux.19p18/fs/inode.c	Mon Feb 12 14:52:43 2001
@@ -435,7 +435,7 @@
  * This is the externally visible routine for
  * inode memory management.
  */
-void free_inode_memory(int goal)
+void free_inode_memory(void)
 {
 	spin_lock(&inode_lock);
 	free_inodes();
@@ -681,7 +681,7 @@
 static inline unsigned long hash(struct super_block *sb, unsigned long i_ino)
 {
 	unsigned long tmp = i_ino | (unsigned long) sb;
-	tmp = tmp + (tmp >> HASH_BITS) + (tmp >> HASH_BITS*2);
+	tmp = tmp + (tmp >> HASH_BITS);
 	return tmp & HASH_MASK;
 }
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/isofs/dir.c linux.19p18/fs/isofs/dir.c
--- linux.vanilla/fs/isofs/dir.c	Sat Sep  9 18:42:47 2000
+++ linux.19p18/fs/isofs/dir.c	Wed Dec 13 21:58:21 2000
@@ -67,14 +67,18 @@
 	NULL			/* permission */
 };
 
-static int isofs_name_translate(char * old, int len, char * new)
+int isofs_name_translate(struct iso_directory_record *de, char *new,
+			 struct inode *inode)
 {
-	int i, c;
+	char * old = de->name;
+	int len = de->name_len[0];
+	int i;
 			
 	for (i = 0; i < len; i++) {
-		c = old[i];
+		unsigned char c = old[i];
 		if (!c)
 			break;
+
 		if (c >= 'A' && c <= 'Z')
 			c |= 0x20;	/* lower case */
 
@@ -101,8 +105,7 @@
 {
 	int std;
 	unsigned char * chr;
-	int retnamlen = isofs_name_translate(de->name,
-				de->name_len[0], retname);
+	int retnamlen = isofs_name_translate(de, retname, inode);
 	if (retnamlen == 0) return 0;
 	std = sizeof(struct iso_directory_record) + de->name_len[0];
 	if (std & 1) std++;
@@ -122,7 +125,9 @@
 }
 
 /*
- * This should _really_ be cleaned up some day..
+ * Read directory and call the filldir() argument until either
+ * all entries were handled, or filldir() returns an error.
+ * Return 0.
  */
 static int do_isofs_readdir(struct inode *inode, struct file *filp,
 		void *dirent, filldir_t filldir,
@@ -132,7 +137,7 @@
 	unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
 	unsigned int block, offset;
 	int inode_number = 0;	/* Quiet GCC */
-	struct buffer_head *bh;
+	struct buffer_head *bh = NULL;
 	int len;
 	int map;
 	int high_sierra;
@@ -140,78 +145,59 @@
 	char *p = NULL;		/* Quiet GCC */
 	struct iso_directory_record *de;
 
- 	if (filp->f_pos >= inode->i_size)
-		return 0;
- 
 	offset = filp->f_pos & (bufsize - 1);
-	block = isofs_bmap(inode, filp->f_pos >> bufbits);
+	block = filp->f_pos >> bufbits;
 	high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra;
 
-	if (!block)
-		return 0;
-
-	if (!(bh = breada(inode->i_dev, block, bufsize, filp->f_pos, inode->i_size)))
-		return 0;
-
 	while (filp->f_pos < inode->i_size) {
 		int de_len;
-#ifdef DEBUG
-		printk("Block, offset, f_pos: %x %x %x\n",
-		       block, offset, filp->f_pos);
-	        printk("inode->i_size = %x\n",inode->i_size);
-#endif
+
+		if (!bh) {
+			bh = isofs_bread(inode, bufsize, block);
+			if (!bh)
+				return 0;
+		}
+
 		de = (struct iso_directory_record *) (bh->b_data + offset);
-		if(first_de) inode_number = (block << bufbits) + (offset & (bufsize - 1));
+		if (first_de)
+			inode_number = (bh->b_blocknr << bufbits) + offset;
 
-		/* Check boundaries and get length. by GO! */
-		if (offset < bufsize) de_len = *(unsigned char *) de;
-#ifdef DEBUG
-		if (offset < bufsize) printk("de_len = %ld\n", de_len);
-		else printk("Move to next sector\n");
-#endif
-	    
+		de_len = *(unsigned char *) de;
 
 		/* If the length byte is zero, we should move on to the next
 		   CDROM sector.  If we are at the end of the directory, we
 		   kick out of the while loop. */
 
-		if ((offset >= bufsize) || (de_len == 0) ) {
+		if (de_len == 0) {
 			brelse(bh);
-			if (offset >= bufsize) {	/*Check first. by GO!*/
-				offset -= bufsize;
-				filp->f_pos += offset;
-			} else {
-				filp->f_pos = ((filp->f_pos & ~(ISOFS_BLOCK_SIZE - 1))
-					       + ISOFS_BLOCK_SIZE);
-				offset = 0;
-			}
-
-			if (filp->f_pos >= inode->i_size)
-				return 0;
-
-			block = isofs_bmap(inode, (filp->f_pos) >> bufbits);
-			if (!block)
-				return 0;
-			bh = breada(inode->i_dev, block, bufsize, filp->f_pos, inode->i_size);
-			if (!bh)
-				return 0;
+			bh = NULL;
+			filp->f_pos = (filp->f_pos & ~(ISOFS_BLOCK_SIZE - 1))
+					       + ISOFS_BLOCK_SIZE;
+			block = filp->f_pos >> bufbits;
+			offset = 0;
 			continue;
 		}
 
-		offset +=  de_len;
-		if (offset > bufsize) {
-			/*
-			 * This would only normally happen if we had
-			 * a buggy cdrom image.  All directory
-			 * entries should terminate with a null size
-			 * or end exactly at the end of the sector.
-			 */
-		        printk("next_offset (%x) > bufsize (%lx)\n",
-			       offset,bufsize);
-			break;
+		offset += de_len;
+
+		/* Make sure we have a full directory entry */
+		if (offset >= bufsize) {
+			int slop = bufsize - offset + de_len;
+			memcpy(tmpde, de, slop);
+			offset &= bufsize - 1;
+			block++;
+			brelse(bh);
+			bh = NULL;
+			if (offset) {
+				bh = isofs_bread(inode, bufsize, block);
+				if (!bh)
+					return 0;
+				memcpy((void *) tmpde + slop, bh->b_data, offset);
+			}
+			de = tmpde;
 		}
 
-		if(de->flags[-high_sierra] & 0x80) {
+		if (de->flags[-high_sierra] & 0x80) {
 			first_de = 0;
 			filp->f_pos += de_len;
 			continue;
@@ -250,7 +236,7 @@
 		map = 1;
 		if (inode->i_sb->u.isofs_sb.s_rock) {
 			len = get_rock_ridge_filename(de, tmpname, inode);
-			if (len != 0) {
+			if (len != 0) {		/* may be -1 */
 				p = tmpname;
 				map = 0;
 			}
@@ -258,7 +244,7 @@
 		if (map) {
 #ifdef CONFIG_JOLIET
 			if (inode->i_sb->u.isofs_sb.s_joliet_level) {
-				len = get_joliet_filename(de, inode, tmpname);
+				len = get_joliet_filename(de, tmpname, inode);
 				p = tmpname;
 			} else
 #endif
@@ -267,8 +253,7 @@
 				p = tmpname;
 			} else
 			if (inode->i_sb->u.isofs_sb.s_mapping == 'n') {
-				len = isofs_name_translate(de->name,
-					de->name_len[0], tmpname);
+				len = isofs_name_translate(de, tmpname, inode);
 				p = tmpname;
 			} else {
 				p = de->name;
@@ -283,7 +268,8 @@
 
 		continue;
 	}
-	brelse(bh);
+	if (bh)
+		brelse(bh);
 	return 0;
 }
 
@@ -296,17 +282,17 @@
 		void *dirent, filldir_t filldir)
 {
 	int result;
-	char * tmpname;
+	char * page;
 	struct iso_directory_record * tmpde;
 	struct inode *inode = filp->f_dentry->d_inode;
 
-	tmpname = (char *) __get_free_page(GFP_KERNEL);
-	if (!tmpname)
+	page = (char *) __get_free_page(GFP_KERNEL);
+	if (!page)
 		return -ENOMEM;
-	tmpde = (struct iso_directory_record *) (tmpname+1024);
+	tmpde = (struct iso_directory_record *) (page+1024);
 
-	result = do_isofs_readdir(inode, filp, dirent, filldir, tmpname, tmpde);
+	result = do_isofs_readdir(inode, filp, dirent, filldir, page, tmpde);
 
-	free_page((unsigned long) tmpname);
+	free_page((unsigned long) page);
 	return result;
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/isofs/inode.c linux.19p18/fs/isofs/inode.c
--- linux.vanilla/fs/isofs/inode.c	Sat Sep  9 18:42:47 2000
+++ linux.19p18/fs/isofs/inode.c	Wed Dec 13 21:58:21 2000
@@ -54,7 +54,7 @@
 static int isofs_cmp_ms(struct dentry *dentry, struct qstr *a, struct qstr *b);
 #endif
 
-void isofs_put_super(struct super_block *sb)
+static void isofs_put_super(struct super_block *sb)
 {
 #ifdef CONFIG_JOLIET
 	if (sb->u.isofs_sb.s_nls_iocharset) {
@@ -72,6 +72,9 @@
 	return;
 }
 
+static void isofs_read_inode(struct inode *);
+static int isofs_statfs (struct super_block *, struct statfs *, int);
+
 static struct super_operations isofs_sops = {
 	isofs_read_inode,
 	NULL,			/* write_inode */
@@ -452,7 +455,7 @@
 				       (unsigned long) &ms_info);
       set_fs(old_fs);
 #if 0
-      printk("isofs.inode: CDROMMULTISESSION: rc=%d\n",i);
+      printk("isofs.inode: CDROMMULTISESSION: rc=%d\n", i);
       if (i==0)
 	{
 	  printk("isofs.inode: XA disk: %s\n", ms_info.xa_flag ? "yes":"no");
@@ -474,8 +477,8 @@
  * Note: a check_disk_change() has been done immediately prior
  * to this call, so we don't need to check again.
  */
-struct super_block *isofs_read_super(struct super_block *s, void *data,
-				     int silent)
+static struct super_block *isofs_read_super(struct super_block *s, void *data,
+					    int silent)
 {
 	kdev_t				dev = s->s_dev;
 	struct buffer_head	      * bh = NULL, *pri_bh = NULL;
@@ -521,15 +524,13 @@
  	 * that value.
  	 */
  	blocksize = get_hardblocksize(dev);
- 	if(    (blocksize != 0)
- 	    && (blocksize > opt.blocksize) )
- 	  {
+ 	if (blocksize > opt.blocksize) {
  	    /*
  	     * Force the blocksize we are going to use to be the
  	     * hardware blocksize.
  	     */
  	    opt.blocksize = blocksize;
- 	  }
+	}
  
 	blocksize_bits = 0;
 	{
@@ -625,9 +626,7 @@
 	pri_bh = NULL;
 
 root_found:
-	brelse(pri_bh);
-
-	if (joliet_level && opt.rock == 'n') {
+	if (joliet_level && (pri == NULL || opt.rock == 'n')) {
 	    /* This is the case of Joliet with the norock mount flag.
 	     * A disc with both Joliet and Rock Ridge is handled later
 	     */
@@ -724,6 +723,7 @@
 	 * We're all done using the volume descriptor, and may need
 	 * to change the device blocksize, so release the buffer now.
 	 */
+	brelse(pri_bh);
 	brelse(bh);
 
 	/*
@@ -776,8 +776,9 @@
 	s->u.isofs_sb.s_gid = opt.gid;
 	s->u.isofs_sb.s_utf8 = opt.utf8;
 	/*
-	 * It would be incredibly stupid to allow people to mark every file on the disk
-	 * as suid, so we merely allow them to set the default permissions.
+	 * It would be incredibly stupid to allow people to mark every file
+	 * on the disk as suid, so we merely allow them to set the default
+	 * permissions.
 	 */
 	s->u.isofs_sb.s_mode = opt.mode & 0777;
 
@@ -880,8 +881,8 @@
 	return NULL;
 }
 
-int isofs_statfs (struct super_block *sb, struct statfs *buf, int bufsiz)
-{
+static int
+isofs_statfs (struct super_block *sb, struct statfs *buf, int bufsiz) {
 	struct statfs tmp;
 
 	tmp.f_type = ISOFS_SUPER_MAGIC;
@@ -896,6 +897,15 @@
 	return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
 }
 
+struct buffer_head *isofs_bread(struct inode *inode, unsigned int bufsize,
+				unsigned int block)
+{
+	unsigned int blknr = isofs_bmap(inode, block);
+	if (!blknr)
+		return NULL;
+	return bread(inode->i_dev, blknr, bufsize);
+}
+
 int isofs_bmap(struct inode * inode,int block)
 {
 	off_t b_off, offset, size;
@@ -942,10 +952,6 @@
 	firstext = inode->u.isofs_i.i_first_extent;
 	size = inode->u.isofs_i.i_section_size;
 	nextino = inode->u.isofs_i.i_next_section_ino;
-#ifdef DEBUG
-	printk("first inode: inode=%x nextino=%x firstext=%u size=%lu\n",
-		inode->i_ino, nextino, firstext, size);
-#endif
 	i = 0;
 	if (nextino) {
 		while(b_off >= offset + size) {
@@ -956,10 +962,6 @@
 			if(!ino) return 0;
 			firstext = ino->u.isofs_i.i_first_extent;
 			size = ino->u.isofs_i.i_section_size;
-#ifdef DEBUG
-			printk("read inode: inode=%lu ino=%lu nextino=%lu firstext=%u size=%lu\n",
-			       inode->i_ino, nextino, ino->u.isofs_i.i_next_section_ino, firstext, size);
-#endif
 			nextino = ino->u.isofs_i.i_next_section_ino;
 			iput(ino);
 		
@@ -971,10 +973,6 @@
 			}
 		}
 	}
-#ifdef DEBUG
-	printk("isofs_bmap: mapped inode:block %x:%d to block %lu\n",
-		inode->i_ino, block, (b_off - offset + firstext) >> ISOFS_BUFFER_BITS(inode));
-#endif
 	return firstext + ((b_off - offset) >> ISOFS_BUFFER_BITS(inode));
 }
 
@@ -995,118 +993,144 @@
 
 static int isofs_read_level3_size(struct inode * inode)
 {
-	unsigned long ino = inode->i_ino;
+	unsigned long f_pos = inode->i_ino;
 	unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
 	int high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra;
 	struct buffer_head * bh = NULL;
-	int block = 0;
+	unsigned long block, offset;
 	int i = 0;
 	int more_entries = 0;
-	void *cpnt;
-	struct iso_directory_record * raw_inode;
+	struct iso_directory_record * tmpde = NULL;
 
 	inode->i_size = 0;
 	inode->u.isofs_i.i_next_section_ino = 0;
+
+	block = f_pos >> ISOFS_BUFFER_BITS(inode);
+	offset = f_pos & (bufsize-1);
+
 	do {
-		unsigned char *pnt;
-		unsigned int reclen;
-		int offset = (ino & (bufsize - 1));
-
-		cpnt = NULL;
-		/* Check whether to update our buffer */
-		if (block != ino >> ISOFS_BUFFER_BITS(inode)) {
-			block = ino >> ISOFS_BUFFER_BITS(inode);
+		struct iso_directory_record * de;
+		unsigned int de_len;
+
+		if (!bh) {
 			brelse(bh);
 			bh = bread(inode->i_dev, block, bufsize);
 			if (!bh)
 				goto out_noread;
 		}
-		pnt = ((unsigned char *) bh->b_data + offset);
-		/*
-		 * Note: this is invariant even if the record
-		 * spans buffers and must be copied ...
-		 */
-		reclen = *pnt;
 
-		/* N.B. this test doesn't trigger the i++ code ... */	
-		if(reclen == 0) {
-			ino = (ino & ~(ISOFS_BLOCK_SIZE - 1)) + ISOFS_BLOCK_SIZE;
+		de = (struct iso_directory_record *) (bh->b_data + offset);
+		de_len = *(unsigned char *) de;
+
+		if (de_len == 0) {
+			brelse(bh);
+			bh = NULL;
+			f_pos = (f_pos + ISOFS_BLOCK_SIZE) & ~(ISOFS_BLOCK_SIZE - 1);
+			block = f_pos >> ISOFS_BUFFER_BITS(inode);
+			offset = 0;
 			continue;
 		}
-		raw_inode = ((struct iso_directory_record *) pnt);
 
-		/* Check whether the raw inode spans the buffer ... */	
-		if (offset + reclen > bufsize){
-		        int frag1 = bufsize - offset;
-	
-		        cpnt = kmalloc(reclen, GFP_KERNEL);
-			if (cpnt == NULL)
-				goto out_nomem;
-			memcpy(cpnt, pnt, frag1);
+		offset += de_len;
+
+		/* Make sure we have a full directory entry */
+		if (offset >= bufsize) {
+			int slop = bufsize - offset + de_len;
+			if (!tmpde) {
+				tmpde = kmalloc(256, GFP_KERNEL);
+				if (!tmpde)
+					goto out_nomem;
+			}
+			memcpy(tmpde, de, slop);
+			offset &= bufsize - 1;
+			block++;
 			brelse(bh);
-			bh = bread(inode->i_dev, ++block, bufsize);
-			if (!bh)
-				goto out_noread;
-			offset += reclen - bufsize;
-			memcpy((char *)cpnt+frag1, bh->b_data, offset);
-			raw_inode = ((struct iso_directory_record *) cpnt);
+			bh = NULL;
+			if (offset) {
+				bh = bread(inode->i_dev, ++block, bufsize);
+				if (!bh)
+					goto out_noread;
+				memcpy((void *) tmpde + slop, bh->b_data, offset);
+			}
+			de = tmpde;
 		}
 
-		inode->i_size += isonum_733 (raw_inode->size);
-		if(i == 1) inode->u.isofs_i.i_next_section_ino = ino;
+		inode->i_size += isonum_733 (de->size);
+		if(i == 1)
+			inode->u.isofs_i.i_next_section_ino = f_pos;
+
+		more_entries = de->flags[-high_sierra] & 0x80;
+
+		f_pos += de_len;
 
-		more_entries = raw_inode->flags[-high_sierra] & 0x80;
-		
-		ino += reclen;
-		if (cpnt)
-			kfree (cpnt);
 		i++;
 		if(i > 100)
 			goto out_toomany;
 	} while(more_entries);
 out:
-	brelse(bh);
+	if (tmpde)
+		kfree(tmpde);
+	if (bh)
+		brelse(bh);
 	return 0;
 
 out_nomem:
-	printk(KERN_INFO "ISOFS: NoMem ISO inode %lu\n", inode->i_ino);
-	brelse(bh);
-	return 1;
+	if (bh)
+		brelse(bh);
+	return -ENOMEM;
+
 out_noread:
-	printk(KERN_INFO "ISOFS: unable to read i-node block %d\n", block);
-	if (cpnt)
-		kfree(cpnt);
-	return 1;
+	printk(KERN_INFO "ISOFS: unable to read i-node block %lu\n", block);
+	if (tmpde)
+		kfree(tmpde);
+	return -EIO;
+
 out_toomany:
 	printk(KERN_INFO "isofs_read_level3_size: "
 		"More than 100 file sections ?!?, aborting...\n"
 	  	"isofs_read_level3_size: inode=%lu ino=%lu\n",
-		inode->i_ino, ino);
+		inode->i_ino, f_pos);
 	goto out;
 }
 
-void isofs_read_inode(struct inode * inode)
+static void isofs_read_inode(struct inode * inode)
 {
 	struct super_block *sb = inode->i_sb;
 	unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
 	int block = inode->i_ino >> ISOFS_BUFFER_BITS(inode);
 	int high_sierra = sb->u.isofs_sb.s_high_sierra;
-	struct buffer_head * bh;
-	struct iso_directory_record * raw_inode;
-	unsigned char *pnt;
-	int volume_seq_no, i;
+	struct buffer_head * bh = NULL;
+	struct iso_directory_record * de;
+	struct iso_directory_record * tmpde = NULL;
+	unsigned int de_len;
+	int volume_seq_no, i, offset;
 
 	bh = bread(inode->i_dev, block, bufsize);
-	if (!bh) {
-		printk(KERN_WARNING "ISOFS: unable to read i-node block\n");
-		goto fail;
-	}
+	if (!bh)
+		goto out_badread;
 
-	pnt = ((unsigned char *) bh->b_data
-	       + (inode->i_ino & (bufsize - 1)));
-	raw_inode = ((struct iso_directory_record *) pnt);
+	offset = (inode->i_ino & (bufsize - 1));
+	de = (struct iso_directory_record *) (bh->b_data + offset);
+	de_len = *(unsigned char *) de;
+
+	if (offset + de_len > bufsize){
+		int frag1 = bufsize - offset;
+
+		tmpde = kmalloc(de_len, GFP_KERNEL);
+		if (tmpde == NULL) {
+			printk(KERN_INFO "isofs_read_inode: out of memory\n");
+			goto fail;
+		}
+		memcpy(tmpde, bh->b_data + offset, frag1);
+		brelse(bh);
+		bh = bread(inode->i_dev, ++block, bufsize);
+		if (!bh)
+			goto out_badread;
+		memcpy((char *)tmpde+frag1, bh->b_data, de_len - frag1);
+		de = tmpde;
+	}
 
-	if (raw_inode->flags[-high_sierra] & 2) {
+	if (de->flags[-high_sierra] & 2) {
 		inode->i_mode = S_IRUGO | S_IXUGO | S_IFDIR;
 		inode->i_nlink = 1; /* Set to 1.  We know there are 2, but
 				       the find utility tries to optimize
@@ -1121,10 +1145,10 @@
 		/* If there are no periods in the name,
 		 * then set the execute permission bit
 		 */
-		for(i=0; i< raw_inode->name_len[0]; i++)
-			if(raw_inode->name[i]=='.' || raw_inode->name[i]==';')
+		for(i=0; i< de->name_len[0]; i++)
+			if(de->name[i]=='.' || de->name[i]==';')
 				break;
-		if(i == raw_inode->name_len[0] || raw_inode->name[i] == ';')
+		if(i == de->name_len[0] || de->name[i] == ';')
 			inode->i_mode |= S_IXUGO; /* execute permission */
 	}
 	inode->i_uid = inode->i_sb->u.isofs_sb.s_uid;
@@ -1132,49 +1156,54 @@
 	inode->i_blocks = inode->i_blksize = 0;
 
 
-	inode->u.isofs_i.i_section_size = isonum_733 (raw_inode->size);
-	if(raw_inode->flags[-high_sierra] & 0x80) {
+	inode->u.isofs_i.i_section_size = isonum_733 (de->size);
+	if(de->flags[-high_sierra] & 0x80) {
 		if(isofs_read_level3_size(inode)) goto fail;
 	} else {
-		inode->i_size = isonum_733 (raw_inode->size);
+		inode->i_size = isonum_733 (de->size);
 	}
 
 	/* There are defective discs out there - we do this to protect
 	   ourselves.  A cdrom will never contain more than 800Mb 
 	   .. but a DVD may be up to 1Gig (Ulrich Habel) */
+
 	if((inode->i_size < 0 || inode->i_size > 1073741824) &&
-	    inode->i_sb->u.isofs_sb.s_cruft == 'n') {
-	  printk("Warning: defective cdrom.  Enabling \"cruft\" mount option.\n");
-	  inode->i_sb->u.isofs_sb.s_cruft = 'y';
+	   inode->i_sb->u.isofs_sb.s_cruft == 'n') {
+		printk(KERN_WARNING "Warning: defective cdrom.  "
+		       "Enabling \"cruft\" mount option.\n");
+		inode->i_sb->u.isofs_sb.s_cruft = 'y';
 	}
 
-/* Some dipshit decided to store some other bit of information in the high
-   byte of the file length.  Catch this and holler.  WARNING: this will make
-   it impossible for a file to be > 16Mb on the CDROM!!!*/
+	/*
+	 * Some dipshit decided to store some other bit of information
+	 * in the high byte of the file length.  Catch this and holler.
+	 * WARNING: this will make it impossible for a file to be > 16MB
+	 * on the CDROM.
+	 */
 
 	if(inode->i_sb->u.isofs_sb.s_cruft == 'y' &&
 	   inode->i_size & 0xff000000){
-/*	  printk("Illegal format on cdrom.  Pester manufacturer.\n"); */
-	  inode->i_size &= 0x00ffffff;
+		inode->i_size &= 0x00ffffff;
 	}
 
-	if (raw_inode->interleave[0]) {
+	if (de->interleave[0]) {
 		printk("Interleaved files not (yet) supported.\n");
 		inode->i_size = 0;
 	}
 
 	/* I have no idea what file_unit_size is used for, so
 	   we will flag it for now */
-	if(raw_inode->file_unit_size[0] != 0){
-		printk("File unit size != 0 for ISO file (%ld).\n",inode->i_ino);
+	if (de->file_unit_size[0] != 0){
+		printk("File unit size != 0 for ISO file (%ld).\n",
+		       inode->i_ino);
 	}
 
 	/* I have no idea what other flag bits are used for, so
 	   we will flag it for now */
 #ifdef DEBUG
-	if((raw_inode->flags[-high_sierra] & ~2)!= 0){
+	if ((de->flags[-high_sierra] & ~2)!= 0){
 		printk("Unusual flag settings for ISO file (%ld %x).\n",
-		       inode->i_ino, raw_inode->flags[-high_sierra]);
+		       inode->i_ino, de->flags[-high_sierra]);
 	}
 #endif
 
@@ -1184,32 +1213,25 @@
 #endif
 
 	inode->i_mtime = inode->i_atime = inode->i_ctime =
-	  iso_date(raw_inode->date, high_sierra);
+		iso_date(de->date, high_sierra);
 
-	inode->u.isofs_i.i_first_extent = (isonum_733 (raw_inode->extent) +
-					   isonum_711 (raw_inode->ext_attr_length));
+	inode->u.isofs_i.i_first_extent = (isonum_733 (de->extent) +
+					   isonum_711 (de->ext_attr_length));
 
-/* Now test for possible Rock Ridge extensions which will override some of
-   these numbers in the inode structure. */
+	/*
+	 * Now test for possible Rock Ridge extensions which will override
+	 * some of these numbers in the inode structure.
+	 */
 
 	if (!high_sierra) {
-	  parse_rock_ridge_inode(raw_inode, inode);
-	  /* hmm..if we want uid or gid set, override the rock ridge setting */
-	 test_and_set_uid(&inode->i_uid, inode->i_sb->u.isofs_sb.s_uid);
-         test_and_set_gid(&inode->i_gid, inode->i_sb->u.isofs_sb.s_gid);
+		parse_rock_ridge_inode(de, inode);
+		/* if we want uid/gid set, override the rock ridge setting */
+		test_and_set_uid(&inode->i_uid, inode->i_sb->u.isofs_sb.s_uid);
+		test_and_set_gid(&inode->i_gid, inode->i_sb->u.isofs_sb.s_gid);
 	}
 
-#ifdef DEBUG
-	printk("Inode: %x extent: %x\n",inode->i_ino, inode->u.isofs_i.i_first_extent);
-#endif
-
 	/* get the volume sequence number */
-	volume_seq_no = isonum_723 (raw_inode->volume_sequence_number) ;
-
-	/*
-	 * All done with buffer ... no more references to buffer memory!
-	 */
-	brelse(bh);
+	volume_seq_no = isonum_723 (de->volume_sequence_number) ;
 
 	/*
 	 * Disable checking if we see any volume number other than 0 or 1.
@@ -1219,8 +1241,10 @@
 	 */
 	if (inode->i_sb->u.isofs_sb.s_cruft == 'n' &&
 	    (volume_seq_no != 0) && (volume_seq_no != 1)) {
-	  printk("Warning: defective cdrom (volume sequence number). Enabling \"cruft\" mount option.\n");
-	  inode->i_sb->u.isofs_sb.s_cruft = 'y';
+		printk("Warning: defective cdrom "
+		       "(volume sequence number %d). "
+		       "Enabling \"cruft\" mount option.\n", volume_seq_no);
+		inode->i_sb->u.isofs_sb.s_cruft = 'y';
 	}
 
 	/* Install the inode operations vector */
@@ -1228,26 +1252,34 @@
 #ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS
 	if (inode->i_sb->u.isofs_sb.s_cruft != 'y' &&
 	    (volume_seq_no != 0) && (volume_seq_no != 1)) {
-		printk("Multi volume CD somehow got mounted.\n");
+		printk(KERN_WARNING "Multi volume CD somehow got mounted.\n");
 	} else
 #endif IGNORE_WRONG_MULTI_VOLUME_SPECS
 	{
-	  if (S_ISREG(inode->i_mode))
-	    inode->i_op = &isofs_file_inode_operations;
-	  else if (S_ISDIR(inode->i_mode))
-	    inode->i_op = &isofs_dir_inode_operations;
-	  else if (S_ISLNK(inode->i_mode))
-	    inode->i_op = &isofs_symlink_inode_operations;
-	  else if (S_ISCHR(inode->i_mode))
-	    inode->i_op = &chrdev_inode_operations;
-	  else if (S_ISBLK(inode->i_mode))
-	    inode->i_op = &blkdev_inode_operations;
-	  else if (S_ISFIFO(inode->i_mode))
-	    init_fifo(inode);
+		if (S_ISREG(inode->i_mode))
+			inode->i_op = &isofs_file_inode_operations;
+		else if (S_ISDIR(inode->i_mode))
+			inode->i_op = &isofs_dir_inode_operations;
+		else if (S_ISLNK(inode->i_mode))
+			inode->i_op = &isofs_symlink_inode_operations;
+		else if (S_ISCHR(inode->i_mode))
+			inode->i_op = &chrdev_inode_operations;
+		else if (S_ISBLK(inode->i_mode))
+			inode->i_op = &blkdev_inode_operations;
+		else if (S_ISFIFO(inode->i_mode))
+			init_fifo(inode);
 	}
+
+ out:
+	if (tmpde)
+		kfree(tmpde);
+	if (bh)
+		brelse(bh);
 	return;
 
-      fail:
+ out_badread:
+	printk(KERN_WARNING "ISOFS: unable to read i-node block\n");
+ fail:
 	/* With a data error we return this information */
 	inode->i_mtime = inode->i_atime = inode->i_ctime = 0;
 	inode->u.isofs_i.i_first_extent = 0;
@@ -1257,144 +1289,7 @@
 	inode->i_uid = inode->i_gid = 0;
 	inode->i_mode = S_IFREG;  /*Regular file, no one gets to read*/
 	inode->i_op = NULL;
-	return;
-}
-
-/* There are times when we need to know the inode number of a parent of
-   a particular directory.  When control passes through a routine that
-   has access to the parent information, it fills it into the inode structure,
-   but sometimes the inode gets flushed out of the queue, and someone
-   remembers the number.  When they try to open up again, we have lost
-   the information.  The '..' entry on the disc points to the data area
-   for a particular inode, so we can follow these links back up, but since
-   we do not know the inode number, we do not actually know how large the
-   directory is.  The disc is almost always correct, and there is
-   enough error checking on the drive itself, but an open ended search
-   makes me a little nervous.
-
-   The BSD iso filesystem uses the extent number for an inode, and this
-   would work really nicely for us except that the read_inode function
-   would not have any clean way of finding the actual directory record
-   that goes with the file.  If we had such info, then it would pay
-   to change the inode numbers and eliminate this function.
-*/
-
-int isofs_lookup_grandparent(struct inode * parent, int extent)
-{
-	unsigned long bufsize = ISOFS_BUFFER_SIZE(parent);
-	unsigned char bufbits = ISOFS_BUFFER_BITS(parent);
-	unsigned int block,offset;
-	int parent_dir, inode_number;
-	int result;
-	int directory_size;
-	struct buffer_head * bh;
-	struct iso_directory_record * de;
-
-	offset = 0;
-	block = extent << (ISOFS_ZONE_BITS(parent) - bufbits);
-	if (!(bh = bread(parent->i_dev, block, bufsize)))  return -1;
-
-	while (1 == 1) {
-		de = (struct iso_directory_record *) (bh->b_data + offset);
-		if (*((unsigned char *) de) == 0)
-		{
-			brelse(bh);
-			printk("Directory .. not found\n");
-			return -1;
-		}
-
-		offset += *((unsigned char *) de);
-
-		if (offset >= bufsize)
-		{
-			printk(".. Directory not in first block"
-			       " of directory.\n");
-			brelse(bh);
-			return -1;
-		}
-
-		if (de->name_len[0] == 1 && de->name[0] == 1)
-		{
-			parent_dir = find_rock_ridge_relocation(de, parent);
-			directory_size = isonum_733 (de->size);
-			brelse(bh);
-			break;
-		}
-	}
-#ifdef DEBUG
-	printk("Parent dir:%x\n",parent_dir);
-#endif
-	/* Now we know the extent where the parent dir starts on. */
-
-	result = -1;
-
-	offset = 0;
-	block = parent_dir << (ISOFS_ZONE_BITS(parent) - bufbits);
-	if (!block || !(bh = bread(parent->i_dev,block, bufsize)))
-	{
-		return -1;
-	}
-
-	for(;;)
-	{
-		de = (struct iso_directory_record *) (bh->b_data + offset);
-		inode_number = (block << bufbits)+(offset & (bufsize - 1));
-
-		/* If the length byte is zero, we should move on to the next
-		   CDROM sector.  If we are at the end of the directory, we
-		   kick out of the while loop. */
-
- 		if ((*((unsigned char *) de) == 0) || (offset == bufsize) )
-		{
-			brelse(bh);
-			offset = 0;
-			block++;
-			directory_size -= bufsize;
-			if(directory_size < 0) return -1;
-			if((block & 1) && (ISOFS_ZONE_BITS(parent) - bufbits) == 1)
-			{
-				return -1;
-			}
-			if((block & 3) && (ISOFS_ZONE_BITS(parent) - bufbits) == 2)
-			{
-				return -1;
-			}
-			if (!block
-			    || !(bh = bread(parent->i_dev,block, bufsize)))
-			{
-				return -1;
-			}
-			continue;
-		}
-
-		/* Make sure that the entire directory record is in the current
-		   bh block.  If not, we malloc a buffer, and put the two
-		   halves together, so that we can cleanly read the block.  */
-
-		offset += *((unsigned char *) de);
-
-		if (offset > bufsize)
-		{
- 			printk("Directory overrun\n");
- 			goto out;
-		}
-
-		if (find_rock_ridge_relocation(de, parent) == extent){
-			result = inode_number;
-			goto out;
-		}
-
-	}
-
-	/* We go here for any condition we cannot handle.
-	   We also drop through to here at the end of the directory. */
-
- out:
-	brelse(bh);
-#ifdef DEBUG
-	printk("Resultant Inode %d\n",result);
-#endif
-	return result;
+	goto out;
 }
 
 #ifdef LEAK_CHECK
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/isofs/joliet.c linux.19p18/fs/isofs/joliet.c
--- linux.vanilla/fs/isofs/joliet.c	Sun Jun 11 21:44:18 2000
+++ linux.19p18/fs/isofs/joliet.c	Wed Dec 13 21:58:21 2000
@@ -19,8 +19,6 @@
 	    struct nls_table *nls)
 {
 	unsigned char *ip, *op;
-	unsigned char ch, cl;
-	unsigned char *uni_page;
 
 	ip = uni;
 	op = ascii;
@@ -68,8 +66,8 @@
 }
 
 int
-get_joliet_filename(struct iso_directory_record * de, struct inode * inode,
-		    unsigned char *outname)
+get_joliet_filename(struct iso_directory_record * de, unsigned char *outname,
+		    struct inode * inode)
 {
 	unsigned char utf8;
 	struct nls_table *nls;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/isofs/namei.c linux.19p18/fs/isofs/namei.c
--- linux.vanilla/fs/isofs/namei.c	Fri Apr 21 12:46:43 2000
+++ linux.19p18/fs/isofs/namei.c	Wed Dec 13 21:58:21 2000
@@ -53,200 +53,130 @@
  *	isofs_find_entry()
  *
  * finds an entry in the specified directory with the wanted name. It
- * returns the cache buffer in which the entry was found, and the entry
- * itself (as an inode number). It does NOT read the inode of the
- * entry - you'll have to do that yourself if you want to.
+ * returns the inode number of the found entry, or 0 on error.
  */
-static struct buffer_head *
-isofs_find_entry(struct inode *dir, struct dentry *dentry, unsigned long *ino)
+static unsigned long
+isofs_find_entry(struct inode *dir, struct dentry *dentry,
+		 char *tmpname, struct iso_directory_record *tmpde)
 {
+	unsigned long inode_number;
 	unsigned long bufsize = ISOFS_BUFFER_SIZE(dir);
 	unsigned char bufbits = ISOFS_BUFFER_BITS(dir);
-	unsigned int block, i, f_pos, offset, 
-		inode_number = 0; /* shut gcc up */
-	struct buffer_head * bh , * retval = NULL;
-	unsigned int old_offset;
-	int dlen, match;
-	char * dpnt;
-	unsigned char *page = NULL;
-	struct iso_directory_record * de = NULL; /* shut gcc up */
-	char de_not_in_buf = 0;	  /* true if de is in kmalloc'd memory */
-	char c;
-
-	*ino = 0;
-	
-	if (!(block = dir->u.isofs_i.i_first_extent)) return NULL;
+	unsigned int block, f_pos, offset;
+	struct buffer_head * bh = NULL;
+
+	if (!dir->u.isofs_i.i_first_extent)
+		return 0;
   
 	f_pos = 0;
+	offset = 0;
+	block = 0;
 
-	offset = f_pos & (bufsize - 1);
-	block = isofs_bmap(dir,f_pos >> bufbits);
+	while (f_pos < dir->i_size) {
+		struct iso_directory_record * de;
+		int de_len, match, i, dlen;
+		char *dpnt;
 
-	if (!block || !(bh = bread(dir->i_dev,block,bufsize))) return NULL;
+		if (!bh) {
+			bh = isofs_bread(dir, bufsize, block);
+			if (!bh)
+				return 0;
+		}
 
-	while (f_pos < dir->i_size) {
+		de = (struct iso_directory_record *) (bh->b_data + offset);
+		inode_number = (bh->b_blocknr << bufbits) + offset;
 
-		/* if de is in kmalloc'd memory, do not point to the
-                   next de, instead we will move to the next sector */
-		if(!de_not_in_buf) {
-			de = (struct iso_directory_record *) 
-				(bh->b_data + offset);
-		}
-		inode_number = (block << bufbits) + (offset & (bufsize - 1));
-
-		/* If byte is zero, or we had to fetch this de past
-		   the end of the buffer, this is the end of file, or
-		   time to move to the next sector. Usually 2048 byte
-		   boundaries. */
-		
-		if (*((unsigned char *) de) == 0 || de_not_in_buf) {
-			if(de_not_in_buf) {
-				/* james@bpgc.com: Since we slopped
-                                   past the end of the last buffer, we
-                                   must start some way into the new
-                                   one */
-				de_not_in_buf = 0;
-				kfree(de);
-				f_pos += offset;
-			}
-			else { 
-				offset = 0;
-				f_pos = ((f_pos & ~(ISOFS_BLOCK_SIZE - 1))
-					 + ISOFS_BLOCK_SIZE);
-			}
+		de_len = *(unsigned char *) de;
+		if (!de_len) {
 			brelse(bh);
 			bh = NULL;
-
-			if (f_pos >= dir->i_size) 
-				break;
-
-			block = isofs_bmap(dir,f_pos>>bufbits);
-			if (!block || !(bh = bread(dir->i_dev,block,bufsize)))
-				break;
-
-			continue; /* Will kick out if past end of directory */
+			f_pos = (f_pos + ISOFS_BLOCK_SIZE) & ~(ISOFS_BLOCK_SIZE - 1);
+			block = f_pos >> bufbits;
+			offset = 0;
+			continue;
 		}
 
-		old_offset = offset;
-		offset += *((unsigned char *) de);
-		f_pos += *((unsigned char *) de);
+		offset += de_len;
+		f_pos += de_len;
 
-		/* james@bpgc.com: new code to handle case where the
-		   directory entry spans two blocks.  Usually 1024
-		   byte boundaries */
+		/* Make sure we have a full directory entry */
 		if (offset >= bufsize) {
-			struct buffer_head *bh_next;
-
-			/* james@bpgc.com: read the next block, and
-                           copy the split de into a newly kmalloc'd
-                           buffer */
-			block = isofs_bmap(dir,f_pos>>bufbits);
-			if (!block || 
-			    !(bh_next = bread(dir->i_dev,block,bufsize)))
-				break;
-			
-			de = (struct iso_directory_record *)
-				kmalloc(offset - old_offset, GFP_KERNEL);
-			if(de==NULL)
-				break;
-			memcpy((char *)de, bh->b_data + old_offset, 
-			       bufsize - old_offset);
-			memcpy((char *)de + bufsize - old_offset,
-			       bh_next->b_data, offset - bufsize);
-			brelse(bh_next);
-			de_not_in_buf = 1;
-			offset -= bufsize;
+			int slop = bufsize - offset + de_len;
+			memcpy(tmpde, de, slop);
+			offset &= bufsize - 1;
+			block++;
+			brelse(bh);
+			bh = NULL;
+			if (offset) {
+				bh = isofs_bread(dir, bufsize, block);
+				if (!bh)
+					return 0;
+				memcpy((void *) tmpde + slop, bh->b_data, offset);
+			}
+			de = tmpde;
 		}
+
 		dlen = de->name_len[0];
 		dpnt = de->name;
 
-		if (dir->i_sb->u.isofs_sb.s_rock ||
-		    dir->i_sb->u.isofs_sb.s_joliet_level || 
-		    dir->i_sb->u.isofs_sb.s_mapping == 'n' ||
-		    dir->i_sb->u.isofs_sb.s_mapping == 'a') {
-			if (! page) {
-				page = (unsigned char *)
-					__get_free_page(GFP_KERNEL);
-				if (!page) break;
-			}
-		}
 		if (dir->i_sb->u.isofs_sb.s_rock &&
-		    ((i = get_rock_ridge_filename(de, page, dir)))) {
-			dlen = i;
-			dpnt = page;
+		    ((i = get_rock_ridge_filename(de, tmpname, dir)))) {
+			dlen = i; 	/* possibly -1 */
+			dpnt = tmpname;
 #ifdef CONFIG_JOLIET
 		} else if (dir->i_sb->u.isofs_sb.s_joliet_level) {
-			dlen = get_joliet_filename(de, dir, page);
-			dpnt = page;
+			dlen = get_joliet_filename(de, tmpname, dir);
+			dpnt = tmpname;
 #endif
 		} else if (dir->i_sb->u.isofs_sb.s_mapping == 'a') {
-			dlen = get_acorn_filename(de, page, dir);
-			dpnt = page;
+			dlen = get_acorn_filename(de, tmpname, dir);
+			dpnt = tmpname;
 		} else if (dir->i_sb->u.isofs_sb.s_mapping == 'n') {
-			for (i = 0; i < dlen; i++) {
-				c = dpnt[i];
-				/* lower case */
-				if (c >= 'A' && c <= 'Z') c |= 0x20;
-				if (c == ';' && i == dlen-2 && dpnt[i+1] == '1') {
-					dlen -= 2;
-					break;
-				}
-				if (c == ';') c = '.';
-				page[i] = c;
-			}
-			/* This allows us to match with and without
-			 * a trailing period. */
-			if(page[dlen-1] == '.' && dentry->d_name.len == dlen-1)
-				dlen--;
-			dpnt = page;
+			dlen = isofs_name_translate(de, tmpname, dir);
+			dpnt = tmpname;
 		}
+
 		/*
 		 * Skip hidden or associated files unless unhide is set 
 		 */
 		match = 0;
-		if ((!(de->flags[-dir->i_sb->u.isofs_sb.s_high_sierra] & 5)
-		    || dir->i_sb->u.isofs_sb.s_unhide == 'y') && dlen)
+		if (dlen > 0 &&
+		    (!(de->flags[-dir->i_sb->u.isofs_sb.s_high_sierra] & 5)
+		     || dir->i_sb->u.isofs_sb.s_unhide == 'y'))
 		{
 			match = (isofs_cmp(dentry,dpnt,dlen) == 0);
 		}
 		if (match) {
-			if(inode_number == -1) {
-				/* Should only happen for the '..' entry */
-				inode_number = 
-					isofs_lookup_grandparent(dir,
-					   find_rock_ridge_relocation(de,dir));
-			}
-			*ino = inode_number;
-			retval = bh;
-			bh = NULL;
-			break;
+			if (bh)
+				brelse(bh);
+			return inode_number;
 		}
 	}
-	if (page) free_page((unsigned long) page);
-	if (bh) brelse(bh);
-	if(de_not_in_buf) 
-		kfree(de);
-	return retval;
+	if (bh)
+		brelse(bh);
+	return 0;
 }
 
 struct dentry *isofs_lookup(struct inode * dir, struct dentry * dentry)
 {
 	unsigned long ino;
-	struct buffer_head * bh;
 	struct inode *inode;
+	char *page;
+	struct iso_directory_record * tmpde;
 
-#ifdef DEBUG
-	printk("lookup: %x %s\n",dir->i_ino, dentry->d_name.name);
-#endif
 	dentry->d_op = dir->i_sb->s_root->d_op;
 
-	bh = isofs_find_entry(dir, dentry, &ino);
+	page = (char *) __get_free_page(GFP_USER);
+	if (!page)
+		return ERR_PTR(-ENOMEM);
+	tmpde = (struct iso_directory_record *) (page+1024);
 
-	inode = NULL;
-	if (bh) {
-		brelse(bh);
+	ino = isofs_find_entry(dir, dentry, page, tmpde);
+	free_page((unsigned long) page);
 
-		inode = iget(dir->i_sb,ino);
+	inode = NULL;
+	if (ino) {
+		inode = iget(dir->i_sb, ino);
 		if (!inode)
 			return ERR_PTR(-EACCES);
 	}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/isofs/rock.c linux.19p18/fs/isofs/rock.c
--- linux.vanilla/fs/isofs/rock.c	Fri Apr 21 12:46:43 2000
+++ linux.19p18/fs/isofs/rock.c	Wed Dec 13 21:58:21 2000
@@ -70,7 +70,7 @@
       cont_size = 0; \
       cont_offset = 0; \
       goto LABEL; \
-    };    \
+    }    \
     printk("Unable to read rock-ridge attributes\n");    \
   }}
 
@@ -118,22 +118,16 @@
 	CHECK_SP(goto out);
 	break;
       case SIG('C','L'):
-#ifdef DEBUG
-	printk("RR: CL\n");
-#endif
 	if (flag == 0) {
 	  retval = isonum_733(rr->u.CL.location);
 	  goto out;
-	};
+	}
 	break;
       case SIG('P','L'):
-#ifdef DEBUG
-	printk("RR: PL\n");
-#endif
 	if (flag != 0) {
 	  retval = isonum_733(rr->u.PL.location);
 	  goto out;
-	};
+	}
 	break;
       case SIG('C','E'):
 	CHECK_CE; /* This tells is if there is a continuation record */
@@ -141,8 +135,8 @@
       default:
 	break;
       }
-    };
-  };
+    }
+  }
   MAYBE_CONTINUE(repeat, inode);
   return retval;
  out:
@@ -150,6 +144,7 @@
   return retval;
 }
 
+/* return length of name field; 0: not found, -1: to be ignored */
 int get_rock_ridge_filename(struct iso_directory_record * de,
 			    char * retname, struct inode * inode)
 {
@@ -200,24 +195,21 @@
 	if (rr->u.NM.flags & ~1) {
 	  printk("Unsupported NM flag settings (%d)\n",rr->u.NM.flags);
 	  break;
-	};
+	}
 	if((strlen(retname) + rr->len - 5) >= 254) {
 	  truncate = 1;
 	  break;
-	};
+	}
 	strncat(retname, rr->u.NM.name, rr->len - 5);
 	retnamlen += rr->len - 5;
 	break;
       case SIG('R','E'):
-#ifdef DEBUG
-	printk("RR: RE (%x)\n", inode->i_ino);
-#endif
 	if (buffer) kfree(buffer);
 	return -1;
       default:
 	break;
       }
-    };
+    }
   }
   MAYBE_CONTINUE(repeat,inode);
   return retnamlen; /* If 0, this file did not have a NM field */
@@ -263,10 +255,10 @@
 	break;
       case SIG('E','R'):
 	inode->i_sb->u.isofs_sb.s_rock = 1;
-	printk(KERN_DEBUG"ISO 9660 Extensions: ");
+	printk(KERN_DEBUG "ISO 9660 Extensions: ");
 	{ int p;
 	  for(p=0;p<rr->u.ER.len_id;p++) printk("%c",rr->u.ER.data[p]);
-	};
+	}
 	  printk("\n");
 	break;
       case SIG('P','X'):
@@ -337,27 +329,24 @@
 	   slp = (struct SL_component *) (((char *) slp) + slp->len + 2);
 
 	   if(slen < 2) {
-	     if(    ((rr->u.SL.flags & 1) != 0) 
-		    && ((oldslp->flags & 1) == 0) ) inode->i_size += 1;
+	     if((rr->u.SL.flags & 1) != 0 && (oldslp->flags & 1) == 0)
+		     inode->i_size += 1;
 	     break;
 	   }
 
 	   /*
 	    * If this component record isn't continued, then append a '/'.
 	    */
-	   if(   (!rootflag)
-		 && ((oldslp->flags & 1) == 0) ) inode->i_size += 1;
+	   if(!rootflag && (oldslp->flags & 1) == 0)
+		   inode->i_size += 1;
 	 }
 	}
 	symlink_len = inode->i_size;
 	break;
       case SIG('R','E'):
-	printk("Attempt to read inode for relocated directory\n");
+	printk(KERN_WARNING "Attempt to read inode for relocated directory\n");
 	goto out;
       case SIG('C','L'):
-#ifdef DEBUG
-	printk("RR CL (%x)\n",inode->i_ino);
-#endif
 	inode->u.isofs_i.i_first_extent = isonum_733(rr->u.CL.location);
 	reloc = iget(inode->i_sb,
 		     (inode->u.isofs_i.i_first_extent <<
@@ -378,7 +367,7 @@
       default:
 	break;
       }
-    };
+    }
   }
   MAYBE_CONTINUE(repeat,inode);
   return 0;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/isofs/util.c linux.19p18/fs/isofs/util.c
--- linux.vanilla/fs/isofs/util.c	Fri Apr 21 12:46:43 2000
+++ linux.19p18/fs/isofs/util.c	Wed Dec 13 21:58:21 2000
@@ -98,7 +98,7 @@
 
 int iso_date(char * p, int flag)
 {
-	int year, month, day, hour ,minute, second, tz;
+	int year, month, day, hour, minute, second, tz;
 	int crtime, days, i;
 
 	year = p[0] - 70;
@@ -114,7 +114,6 @@
 		crtime = 0;
 	} else {
 		int monlen[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
-		extern struct timezone sys_tz;
 
 		days = year * 365;
 		if (year > 2)
@@ -126,8 +125,6 @@
 		days += day - 1;
 		crtime = ((((days * 24) + hour) * 60 + minute) * 60)
 			+ second;
-		if (sys_tz.tz_dsttime)
-			crtime -= 3600;
 
 		/* sign extend */
 		if (tz & 0x80)
@@ -149,7 +146,7 @@
 		 * NOTE: mkisofs in versions prior to mkisofs-1.10 had
 		 * the sign wrong on the timezone offset.  This has now
 		 * been corrected there too, but if you are getting screwy
-		 * results this may be the explaination.  If enough people
+		 * results this may be the explanation.  If enough people
 		 * complain, a user configuration option could be added
 		 * to add the timezone offset in with the wrong sign
 		 * for 'compatibility' with older discs, but I cannot see how
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/lockd/clntlock.c linux.19p18/fs/lockd/clntlock.c
--- linux.vanilla/fs/lockd/clntlock.c	Mon Dec 11 22:13:02 2000
+++ linux.19p18/fs/lockd/clntlock.c	Mon Feb 12 14:51:59 2001
@@ -138,18 +138,15 @@
 void
 nlmclnt_recovery(struct nlm_host *host, u32 newstate)
 {
-	if (!host->h_reclaiming++) {
+	if (host->h_reclaiming++) {
 		if (host->h_nsmstate == newstate)
 			return;
 		printk(KERN_WARNING
 			"lockd: Uh-oh! Interfering reclaims for host %s",
 			host->h_name);
-		host->h_monitored = 0;
 		host->h_nsmstate = newstate;
 		host->h_state++;
-		nlm_release_host(host);
 	} else {
-		host->h_monitored = 0;
 		host->h_nsmstate = newstate;
 		host->h_state++;
 		nlm_get_host(host);
@@ -168,7 +165,11 @@
 	/* This one ensures that our parent doesn't terminate while the
 	 * reclaim is in progress */
 	lock_kernel();
+	daemonize();
+
 	lockd_up();
+
+	exit_files(current);
 
 	/* First, reclaim all locks that have been granted previously. */
 	do {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/lockd/clntproc.c linux.19p18/fs/lockd/clntproc.c
--- linux.vanilla/fs/lockd/clntproc.c	Mon Dec 11 22:13:02 2000
+++ linux.19p18/fs/lockd/clntproc.c	Mon Feb 12 14:51:59 2001
@@ -46,13 +46,11 @@
 {
 	struct nlm_args	*argp = &req->a_args;
 	struct nlm_lock	*lock = &argp->lock;
-	struct dentry   *dentry = fl->fl_file->f_dentry;
-	struct nfs_fh   *fh = NFS_FH(dentry);
 
 	memset(argp, 0, sizeof(*argp));
 	nlmclnt_next_cookie(&argp->cookie);
 	argp->state   = nsm_local_state;
-	memcpy(&lock->fh, fh, sizeof(*fh));
+	memcpy(&lock->fh, NFS_FH(fl->fl_file->f_dentry->d_inode), sizeof(lock->fh));
 	lock->caller  = system_utsname.nodename;
 	lock->oh.data = req->a_owner;
 	lock->oh.len  = sprintf(req->a_owner, "%d@%s",
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/lockd/host.c linux.19p18/fs/lockd/host.c
--- linux.vanilla/fs/lockd/host.c	Mon Dec 11 22:13:02 2000
+++ linux.19p18/fs/lockd/host.c	Mon Feb 12 14:51:59 2001
@@ -26,7 +26,6 @@
 #define NLM_HOST_REBIND		(60 * HZ)
 #define NLM_HOST_EXPIRE		((nrhosts > NLM_HOST_MAX)? 300 * HZ : 120 * HZ)
 #define NLM_HOST_COLLECT	((nrhosts > NLM_HOST_MAX)? 120 * HZ :  60 * HZ)
-#define NLM_HOST_ADDR(sv)	(&(sv)->s_nlmclnt->cl_xprt->addr)
 
 static struct nlm_host *	nlm_hosts[NLM_HOST_NRHASH];
 static unsigned long		next_gc = 0;
@@ -37,24 +36,6 @@
 static void			nlm_gc_hosts(void);
 
 /*
- * Find an NLM server handle in the cache. If there is none, create it.
- */
-struct nlm_host *
-nlmclnt_lookup_host(struct sockaddr_in *sin, int proto, int version)
-{
-	return nlm_lookup_host(NULL, sin, proto, version);
-}
-
-/*
- * Find an NLM client handle in the cache. If there is none, create it.
- */
-struct nlm_host *
-nlmsvc_lookup_host(struct svc_rqst *rqstp)
-{
-	return nlm_lookup_host(rqstp->rq_client, &rqstp->rq_addr, 0, 0);
-}
-
-/*
  * Match the given host against client/address
  */
 static inline int
@@ -67,60 +48,33 @@
 }
 
 /*
- * Common host lookup routine for server & client
+ * Hash the host
  */
-struct nlm_host *
-nlm_lookup_host(struct svc_client *clnt, struct sockaddr_in *sin,
-					int proto, int version)
+static inline int
+nlm_hash_host(struct svc_client *clnt, struct sockaddr_in *sin)
 {
-	struct nlm_host	*host, **hp;
-	u32		addr;
-	int		hash;
-
-	if (!clnt && !sin) {
-		printk(KERN_NOTICE "lockd: no clnt or addr in lookup_host!\n");
-		return NULL;
-	}
-
-	dprintk("lockd: nlm_lookup_host(%08x, p=%d, v=%d)\n",
-			(unsigned)(sin? ntohl(sin->sin_addr.s_addr) : 0), proto, version);
-
 	if (clnt)
-		hash = NLM_PTRHASH(clnt);
-	else
-		hash = NLM_ADDRHASH(sin->sin_addr.s_addr);
+		return NLM_PTRHASH(clnt);
+	return NLM_ADDRHASH(sin->sin_addr.s_addr);
+}
 
-	/* Lock hash table */
-	down(&nlm_host_sema);
+static struct nlm_host *
+nlm_create_host(struct svc_client *clnt, struct sockaddr_in *sin,
+		int proto, int version)
+{
+	struct nlm_host	*host;
+	u32		addr;
+	int		hash;
 
 	if (time_after_eq(jiffies, next_gc))
 		nlm_gc_hosts();
 
-	for (hp = &nlm_hosts[hash]; (host = *hp); hp = &host->h_next) {
-		if (host->h_version != version || host->h_proto != proto)
-			continue;
-
-		if (nlm_match_host(host, clnt, sin)) {
-			if (hp != nlm_hosts + hash) {
-				*hp = host->h_next;
-				host->h_next = nlm_hosts[hash];
-				nlm_hosts[hash] = host;
-			}
-			nlm_get_host(host);
-			up(&nlm_host_sema);
-			return host;
-		}
+	if (!(host = (struct nlm_host *) kmalloc(sizeof(*host), GFP_KERNEL))) {
+		dprintk("lockd: attempt to create host entry failed.\n");
+		return NULL;
 	}
 
-	/* special hack for nlmsvc_invalidate_client */
-	if (sin == NULL)
-		goto nohost;
-
-	/* Ooops, no host found, create it */
-	dprintk("lockd: creating host entry\n");
-
-	if (!(host = (struct nlm_host *) kmalloc(sizeof(*host), GFP_KERNEL)))
-		goto nohost;
+	dprintk("lockd: creating host entry.\n");
 	memset(host, 0, sizeof(*host));
 
 	addr = sin->sin_addr.s_addr;
@@ -135,22 +89,103 @@
 	host->h_version    = version;
 	host->h_proto      = proto;
 	host->h_authflavor = RPC_AUTH_UNIX;
-	host->h_rpcclnt    = NULL;
 	host->h_sema	   = MUTEX;
-	host->h_nextrebind = jiffies + NLM_HOST_REBIND;
 	host->h_expires    = jiffies + NLM_HOST_EXPIRE;
 	host->h_count      = 1;
-	host->h_state      = 0;			/* pseudo NSM state */
-	host->h_nsmstate   = 0;			/* real NSM state */
 	host->h_exportent  = clnt;
 
+	hash = nlm_hash_host(clnt, sin);
 	host->h_next       = nlm_hosts[hash];
 	nlm_hosts[hash]    = host;
 
 	if (++nrhosts > NLM_HOST_MAX)
-		next_gc = 0;
+		next_gc = jiffies;
+
+	return host;
+}
+
+static struct nlm_host *
+__nlm_lookup_host(struct svc_client *clnt, struct sockaddr_in *sin,
+		  int proto, int version)
+{
+	struct nlm_host	*host, **hp;
+	int hash;
+
+	if (!clnt && !sin) {
+		printk(KERN_NOTICE "lockd: no clnt or addr in lookup_host!\n");
+		return NULL;
+	}
+
+	dprintk("lockd: nlm_lookup_host(%08x, p=%d, v=%d)\n",
+			(unsigned)(sin? ntohl(sin->sin_addr.s_addr) : 0), proto, version);
+
+	hash = nlm_hash_host(clnt, sin);
+	for (hp = &nlm_hosts[hash]; (host = *hp); hp = &host->h_next) {
+		if (proto && host->h_proto != proto)
+			continue;
+		if (version && host->h_version != version)
+			continue;
+
+		if (nlm_match_host(host, clnt, sin)) {
+			if (hp != nlm_hosts + hash) {
+				*hp = host->h_next;
+				host->h_next = nlm_hosts[hash];
+				nlm_hosts[hash] = host;
+			}
+			nlm_get_host(host);
+			break;
+		}
+	}
+	return host;
+}
+
+/*
+ * Common host lookup routine for server & client
+ */
+struct nlm_host *
+nlm_lookup_host(struct svc_client *clnt, struct sockaddr_in *sin,
+		int proto, int version)
+{
+	struct nlm_host *host;
 
-nohost:
+	/* Lock hash table */
+	down(&nlm_host_sema);
+	host = __nlm_lookup_host(clnt, sin, proto, version);
+	up(&nlm_host_sema);
+	return host;
+}
+
+/*
+ * Find an NLM server handle in the cache. If there is none, create it.
+ */
+struct nlm_host *
+nlmclnt_lookup_host(struct sockaddr_in *sin, int prot, int vers)
+{
+	struct nlm_host *host;
+
+	/* Lock hash table */
+	down(&nlm_host_sema);
+	if ((host = __nlm_lookup_host(NULL, sin, prot, vers)) == NULL)
+		host = nlm_create_host(NULL, sin, prot, vers);
+	up(&nlm_host_sema);
+	return host;
+}
+
+/*
+ * Find an NLM client handle in the cache. If there is none, create it.
+ */
+struct nlm_host *
+nlmsvc_lookup_host(struct svc_rqst *rqstp)
+{
+	struct nlm_host *host;
+	struct svc_client *clnt = rqstp->rq_client;
+	int prot = rqstp->rq_prot,
+	    vers = rqstp->rq_vers;
+
+	/* Lock hash table */
+	down(&nlm_host_sema);
+	if ((host = __nlm_lookup_host(clnt, NULL, prot, vers)) == NULL)
+		host = nlm_create_host(clnt, &rqstp->rq_addr, prot, vers);
 	up(&nlm_host_sema);
 	return host;
 }
@@ -206,6 +241,7 @@
 		clnt->cl_autobind = 1;	/* turn on pmap queries */
 		xprt->nocong = 1;	/* No congestion control for NLM */
 
+		host->h_nextrebind = jiffies + NLM_HOST_REBIND;
 		host->h_rpcclnt = clnt;
 	}
 
@@ -272,7 +308,7 @@
 	dprintk("lockd: nuking all hosts...\n");
 	for (i = 0; i < NLM_HOST_NRHASH; i++) {
 		for (host = nlm_hosts[i]; host; host = host->h_next)
-			host->h_expires = 0;
+			host->h_expires = jiffies;
 	}
 
 	/* Then, perform a garbage collection pass */
@@ -326,15 +362,8 @@
 			*q = host->h_next;
 			if (host->h_monitored)
 				nsm_unmonitor(host);
-			if ((clnt = host->h_rpcclnt) != NULL) {
-				if (atomic_read(&clnt->cl_users)) {
-					printk(KERN_WARNING
-						"lockd: active RPC handle\n");
-					clnt->cl_dead = 1;
-				} else {
-					rpc_destroy_client(host->h_rpcclnt);
-				}
-			}
+			if ((clnt = host->h_rpcclnt) != NULL)
+				rpc_shutdown_client(clnt);
 			kfree(host);
 			nrhosts--;
 		}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/lockd/mon.c linux.19p18/fs/lockd/mon.c
--- linux.vanilla/fs/lockd/mon.c	Mon Dec 11 22:13:02 2000
+++ linux.19p18/fs/lockd/mon.c	Mon Feb 12 14:51:59 2001
@@ -47,7 +47,7 @@
 
 	args.addr = host->h_addr.sin_addr.s_addr;
 	args.prog = NLM_PROGRAM;
-	args.vers = 1;
+	args.vers = host->h_version;
 	args.proc = NLMPROC_NSM_NOTIFY;
 	memset(res, 0, sizeof(*res));
 
@@ -76,8 +76,10 @@
 
 	if (status < 0 || res.status != 0)
 		printk(KERN_NOTICE "lockd: cannot monitor %s\n", host->h_name);
-	else
+	else {
 		host->h_monitored = 1;
+		host->h_nsmstate = res.state;
+	}
 	return status;
 }
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/lockd/svc.c linux.19p18/fs/lockd/svc.c
--- linux.vanilla/fs/lockd/svc.c	Mon Dec 11 22:13:02 2000
+++ linux.19p18/fs/lockd/svc.c	Mon Feb 12 14:51:59 2001
@@ -77,9 +77,7 @@
 	nlmsvc_pid = current->pid;
 	up(&lockd_start);
 
-	exit_mm(current);
-	current->session = 1;
-	current->pgrp = 1;
+	daemonize();
 	sprintf(current->comm, "lockd");
 
 	/* Process request with signals blocked.  */
@@ -105,12 +103,8 @@
 #ifdef RPC_DEBUG
 	nlmsvc_grace_period = 10 * HZ;
 #else
-	if (nlm_grace_period) {
-		nlmsvc_grace_period += (1 + nlm_grace_period / nlm_timeout)
-						* nlm_timeout * HZ;
-	} else {
-		nlmsvc_grace_period += 5 * nlm_timeout * HZ;
-	}
+	nlmsvc_grace_period = (1 + nlm_grace_period / nlm_timeout)
+				* nlm_timeout * HZ;
 #endif
 
 	grace_period_expire = nlmsvc_grace_period + jiffies;
@@ -138,8 +132,11 @@
 		 */
 		if (!nlmsvc_grace_period) {
 			timeout = nlmsvc_retry_blocked();
-		} else if (time_before(nlmsvc_grace_period, jiffies))
+		} else if (time_before(grace_period_expire, jiffies)) {
 			nlmsvc_grace_period = 0;
+			continue;
+		} else
+			timeout = nlmsvc_timeout;
 
 		/*
 		 * Find a socket with data available and call its
@@ -349,7 +346,7 @@
  * Define NLM program and procedures
  */
 static struct svc_version	nlmsvc_version1 = {
-	1, 16, nlmsvc_procedures, NULL
+	1, 17, nlmsvc_procedures, NULL
 };
 static struct svc_version	nlmsvc_version3 = {
 	3, 24, nlmsvc_procedures, NULL
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/lockd/svc4proc.c linux.19p18/fs/lockd/svc4proc.c
--- linux.vanilla/fs/lockd/svc4proc.c	Mon Dec 11 22:13:02 2000
+++ linux.19p18/fs/lockd/svc4proc.c	Mon Feb 12 14:51:59 2001
@@ -422,6 +422,8 @@
 					      void	        *resp)
 {
 	struct sockaddr_in	saddr = rqstp->rq_addr;
+	int			vers = rqstp->rq_vers;
+	int			prot = rqstp->rq_prot;
 	struct nlm_host		*host;
 
 	dprintk("lockd: SM_NOTIFY     called\n");
@@ -438,7 +440,7 @@
 	 * reclaim all locks we hold on this server.
 	 */
 	saddr.sin_addr.s_addr = argp->addr;	
-	if ((host = nlm_lookup_host(NULL, &saddr, IPPROTO_UDP, 1)) != NULL) {
+	if ((host = nlmclnt_lookup_host(&saddr, prot, vers)) != NULL) {
 		nlmclnt_recovery(host, argp->state);
 		nlm_release_host(host);
 	}
@@ -448,7 +450,7 @@
 		struct svc_client	*clnt;
 		saddr.sin_addr.s_addr = argp->addr;	
 		if ((clnt = nlmsvc_ops->exp_getclient(&saddr)) != NULL 
-		 && (host = nlm_lookup_host(clnt, &saddr, 0, 0)) != NULL) {
+		 && (host = nlm_lookup_host(clnt, NULL, 0, 0)) != NULL) {
 			nlmsvc_free_host_resources(host);
 			nlm_release_host(host);
 		}
@@ -551,7 +553,8 @@
   PROC(cancel_res,	cancelres,	norep,		res,	void),
   PROC(unlock_res,	unlockres,	norep,		res,	void),
   PROC(granted_res,	grantedres,	norep,		res,	void),
-  PROC(none,		void,		void,		void,	void),
+  /* statd callback */
+  PROC(sm_notify,	reboot,		void,		reboot,	void),
   PROC(none,		void,		void,		void,	void),
   PROC(none,		void,		void,		void,	void),
   PROC(none,		void,		void,		void,	void),
@@ -560,6 +563,4 @@
   PROC(nm_lock,		lockargs,	res,		args,	res),
   PROC(free_all,	notify,		void,		args,	void),
 
-  /* statd callback */
-  PROC(sm_notify,	reboot,		void,		reboot,	void),
 };
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/lockd/svclock.c linux.19p18/fs/lockd/svclock.c
--- linux.vanilla/fs/lockd/svclock.c	Mon Dec 11 22:13:03 2000
+++ linux.19p18/fs/lockd/svclock.c	Mon Feb 12 14:51:59 2001
@@ -53,9 +53,15 @@
 	dprintk("lockd: nlmsvc_insert_block(%p, %ld)\n", block, when);
 	if (block->b_queued)
 		nlmsvc_remove_block(block);
-	for (bp = &nlm_blocked; (b = *bp); bp = &b->b_next)
-		if (when < b->b_when)
-			break;
+	bp = &nlm_blocked;
+	if (when != NLM_NEVER) {
+		if ((when += jiffies) == NLM_NEVER)
+			when ++;
+		while ((b = *bp) && time_before_eq(b->b_when,when))
+			bp = &b->b_next;
+	} else
+		while ((b = *bp))
+			bp = &b->b_next;
 
 	block->b_queued = 1;
 	block->b_when = when;
@@ -159,8 +165,7 @@
 	struct nlm_rqst		*call;
 
 	/* Create host handle for callback */
-	host = nlmclnt_lookup_host(&rqstp->rq_addr,
-				rqstp->rq_prot, rqstp->rq_vers);
+	host = nlmsvc_lookup_host(rqstp);
 	if (host == NULL)
 		return NULL;
 
@@ -169,10 +174,11 @@
 		goto failed;
 	memset(block, 0, sizeof(*block));
 
-	/* Set notifier function for VFS, and init args */
-	lock->fl.fl_notify = nlmsvc_notify_blocked;
 	if (!nlmclnt_setgrantargs(&block->b_call, lock))
 		goto failed_free;
+
+	/* Set notifier function for VFS, and init args */
+	block->b_call.a_args.lock.fl.fl_notify = nlmsvc_notify_blocked;
 	block->b_call.a_args.cookie = *cookie;	/* see above */
 
 	dprintk("lockd: created block %p...\n", block);
@@ -263,12 +269,12 @@
 	down(&file->f_sema);
 	for (block = file->f_blocks; block; block = next) {
 		next = block->b_fnext;
+		if (host && block->b_host != host)
+			continue;
 		if (action == NLM_ACT_MARK)
 			block->b_host->h_inuse = 1;
-		else if (action == NLM_ACT_UNLOCK) {
-			if (host == NULL || host == block->b_host)
-				nlmsvc_delete_block(block, 1);
-		}
+		else if (action == NLM_ACT_UNLOCK)
+			nlmsvc_delete_block(block, 1);
 	}
 	up(&file->f_sema);
 	return 0;
@@ -455,8 +461,8 @@
 	posix_unblock_lock(fl);
 	for (bp = &nlm_blocked; (block = *bp); bp = &block->b_next) {
 		if (nlm_compare_locks(&block->b_call.a_args.lock.fl, fl)) {
-			svc_wake_up(block->b_daemon);
 			nlmsvc_insert_block(block, 0);
+			svc_wake_up(block->b_daemon);
 			return;
 		}
 	}
@@ -516,7 +522,7 @@
 	if ((error = posix_lock_file(&file->f_file, &lock->fl, 0)) < 0) {
 		printk(KERN_WARNING "lockd: unexpected error %d in %s!\n",
 				-error, __FUNCTION__);
-		nlmsvc_insert_block(block, jiffies + 10 * HZ);
+		nlmsvc_insert_block(block, 10 * HZ);
 		up(&file->f_sema);
 		return;
 	}
@@ -528,7 +534,7 @@
 	block->b_incall  = 1;
 
 	/* Schedule next grant callback in 30 seconds */
-	nlmsvc_insert_block(block, jiffies + 30 * HZ);
+	nlmsvc_insert_block(block, 30 * HZ);
 
 	/* Call the client */
 	nlm_get_host(block->b_call.a_host);
@@ -566,13 +572,13 @@
 	 * can be done, though. */
 	if (task->tk_status < 0) {
 		/* RPC error: Re-insert for retransmission */
-		timeout = jiffies + 10 * HZ;
+		timeout = 10 * HZ;
 	} else if (block->b_done) {
 		/* Block already removed, kill it for real */
 		timeout = 0;
 	} else {
 		/* Call was successful, now wait for client callback */
-		timeout = jiffies + 60 * HZ;
+		timeout = 60 * HZ;
 	}
 	nlmsvc_insert_block(block, timeout);
 	svc_wake_up(block->b_daemon);
@@ -600,7 +606,7 @@
 	if ((block = nlmsvc_find_block(cookie)) != NULL) {
 		if (status == NLM_LCK_DENIED_GRACE_PERIOD) {
 			/* Try again in a couple of seconds */
-			nlmsvc_insert_block(block, jiffies + 10 * HZ);
+			nlmsvc_insert_block(block, 10 * HZ);
 			block = NULL;
 		} else {
 			/* Lock is now held by client, or has been rejected.
@@ -631,7 +637,11 @@
 	dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",
 			nlm_blocked,
 			nlm_blocked? nlm_blocked->b_when : 0);
-	while ((block = nlm_blocked) && block->b_when <= jiffies) {
+	while ((block = nlm_blocked)) {
+		if (block->b_when == NLM_NEVER)
+			break;
+		if (time_after(block->b_when,jiffies))
+			break;
 		dprintk("nlmsvc_retry_blocked(%p, when=%ld, done=%d)\n",
 			block, block->b_when, block->b_done);
 		if (block->b_done)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/lockd/svcproc.c linux.19p18/fs/lockd/svcproc.c
--- linux.vanilla/fs/lockd/svcproc.c	Mon Dec 11 22:13:03 2000
+++ linux.19p18/fs/lockd/svcproc.c	Mon Feb 12 14:51:59 2001
@@ -435,6 +435,8 @@
 					      void	        *resp)
 {
 	struct sockaddr_in	saddr = rqstp->rq_addr;
+	int			vers = rqstp->rq_vers;
+	int			prot = rqstp->rq_prot;
 	struct nlm_host		*host;
 
 	dprintk("lockd: SM_NOTIFY     called\n");
@@ -450,8 +452,8 @@
 	/* Obtain the host pointer for this NFS server and try to
 	 * reclaim all locks we hold on this server.
 	 */
-	saddr.sin_addr.s_addr = argp->addr;	
-	if ((host = nlm_lookup_host(NULL, &saddr, IPPROTO_UDP, 1)) != NULL) {
+	saddr.sin_addr.s_addr = htonl(argp->addr);
+	if ((host = nlmclnt_lookup_host(&saddr, prot, vers)) != NULL) {
 		nlmclnt_recovery(host, argp->state);
 		nlm_release_host(host);
 	}
@@ -461,7 +463,7 @@
 		struct svc_client	*clnt;
 		saddr.sin_addr.s_addr = argp->addr;	
 		if ((clnt = nlmsvc_ops->exp_getclient(&saddr)) != NULL 
-		 && (host = nlm_lookup_host(clnt, &saddr, 0, 0)) != NULL) {
+		 && (host = nlm_lookup_host(clnt, NULL, 0, 0)) != NULL) {
 			nlmsvc_free_host_resources(host);
 			nlm_release_host(host);
 		}
@@ -585,7 +587,8 @@
   PROC(cancel_res,	cancelres,	norep,		res,	void),
   PROC(unlock_res,	unlockres,	norep,		res,	void),
   PROC(granted_res,	grantedres,	norep,		res,	void),
-  PROC(none,		void,		void,		void,	void),
+  /* statd callback */
+  PROC(sm_notify,	reboot,		void,		reboot,	void),
   PROC(none,		void,		void,		void,	void),
   PROC(none,		void,		void,		void,	void),
   PROC(none,		void,		void,		void,	void),
@@ -594,6 +597,4 @@
   PROC(nm_lock,		lockargs,	res,		args,	res),
   PROC(free_all,	notify,		void,		args,	void),
 
-  /* statd callback */
-  PROC(sm_notify,	reboot,		void,		reboot,	void),
 };
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/lockd/svcshare.c linux.19p18/fs/lockd/svcshare.c
--- linux.vanilla/fs/lockd/svcshare.c	Mon Dec 11 22:13:03 2000
+++ linux.19p18/fs/lockd/svcshare.c	Mon Feb 12 14:51:59 2001
@@ -95,14 +95,16 @@
 
 	shpp = &file->f_shares;
 	while ((share = *shpp) !=  NULL) {
+		if (host && host != share->s_host) {
+			shpp = &share->s_next;
+			continue;
+		}
 		if (action == NLM_ACT_MARK)
 			share->s_host->h_inuse = 1;
 		else if (action == NLM_ACT_UNLOCK) {
-			if (host == NULL || host == share->s_host) {
-				*shpp = share->s_next;
-				kfree(share);
-				continue;
-			}
+			*shpp = share->s_next;
+			kfree(share);
+			continue;
 		}
 		shpp = &share->s_next;
 	}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/lockd/svcsubs.c linux.19p18/fs/lockd/svcsubs.c
--- linux.vanilla/fs/lockd/svcsubs.c	Mon Dec 11 22:13:03 2000
+++ linux.19p18/fs/lockd/svcsubs.c	Mon Feb 12 14:51:59 2001
@@ -44,6 +44,10 @@
  * Note that we open the file O_RDONLY even when creating write locks.
  * This is not quite right, but for now, we assume the client performs
  * the proper R/W checking.
+ *
+ * BEWARE:
+ * The cast to struct knfs_fh in this routine, imposes an alignment
+ * requirement on (struct nfs_fh)->data for some platforms.
  */
 u32
 nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
@@ -63,8 +67,7 @@
 	down(&nlm_file_sema);
 
 	for (file = nlm_files[hash]; file; file = file->f_next) {
-		if (file->f_handle.fh_dcookie == fh->fh_dcookie &&
-		    !memcmp(&file->f_handle, fh, sizeof(*fh)))
+		if (!memcmp(&file->f_handle, fh, sizeof(*fh)))
 			goto found;
 	}
 
@@ -147,6 +150,7 @@
 	struct inode	 *inode = nlmsvc_file_inode(file);
 	struct file_lock *fl;
 	struct nlm_host	 *lockhost;
+	int		 status = 0;
 
 again:
 	file->f_locks = 0;
@@ -157,29 +161,27 @@
 		/* update current lock count */
 		file->f_locks++;
 		lockhost = (struct nlm_host *) fl->fl_owner;
+		if (host && lockhost != host)
+			continue;
 		if (action == NLM_ACT_MARK)
 			lockhost->h_inuse = 1;
 		else if (action == NLM_ACT_CHECK)
-			return 1;
+			status = 1;
 		else if (action == NLM_ACT_UNLOCK) {
-			struct file_lock lock = *fl;
-
-			if (host && lockhost != host)
-				continue;
+			struct file_lock lock;
 
+			lock = *fl;
 			lock.fl_type  = F_UNLCK;
-			lock.fl_start = 0;
-			lock.fl_end   = NLM_OFFSET_MAX;
 			if (posix_lock_file(&file->f_file, &lock, 0) < 0) {
 				printk("lockd: unlock failure in %s:%d\n",
 						__FILE__, __LINE__);
-				return 1;
-			}
-			goto again;
+				status = 1;
+			} else
+				goto again;
 		}
 	}
 
-	return 0;
+	return status;
 }
 
 /*
@@ -208,6 +210,7 @@
 {
 	struct nlm_file	*file, **fp;
 	int		i;
+	int		res = 0;
 
 	down(&nlm_file_sema);
 	for (i = 0; i < FILE_NRHASH; i++) {
@@ -215,24 +218,21 @@
 		while ((file = *fp) != NULL) {
 			/* Traverse locks, blocks and shares of this file
 			 * and update file->f_locks count */
-			if (nlm_inspect_file(host, file, action)) {
-				up(&nlm_file_sema);
-				return 1;
-			}
+			if (nlm_inspect_file(host, file, action))
+				res = 1;
 
-			/* No more references to this file. Let go of it. */
-			if (!file->f_blocks && !file->f_locks
-			 && !file->f_shares && !file->f_count) {
-				*fp = file->f_next;
-				nlmsvc_ops->fclose(&file->f_file);
-				kfree(file);
-			} else {
+			if (file->f_blocks || file->f_locks
+			    || file->f_shares || file->f_count) {
 				fp = &file->f_next;
+				continue;
 			}
+			*fp = file->f_next;
+			nlmsvc_ops->fclose(&file->f_file);
+			kfree(file);
 		}
 	}
 	up(&nlm_file_sema);
-	return 0;
+	return res;
 }
 
 /*
@@ -298,7 +298,7 @@
 	if ((host = nlm_lookup_host(clnt, NULL, 0, 0)) != NULL) {
 		dprintk("lockd: invalidating client for %s\n", host->h_name);
 		nlmsvc_free_host_resources(host);
-		host->h_expires = 0;
+		host->h_expires = jiffies;
 		nlm_release_host(host);
 	}
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/locks.c linux.19p18/fs/locks.c
--- linux.vanilla/fs/locks.c	Mon Dec 11 22:13:03 2000
+++ linux.19p18/fs/locks.c	Mon Feb 12 14:51:59 2001
@@ -268,20 +268,22 @@
 
 	while ((waiter = blocker->fl_nextblock) != NULL) {
 		/* N.B. Is it possible for the notify function to block?? */
+		if (!wait) {
+			/* Remove waiter from the block list, because by the
+			 * time it wakes up blocker won't exist any more.
+			 */
+			locks_delete_block(blocker, waiter);
+		}
 		if (waiter->fl_notify)
 			waiter->fl_notify(waiter);
-		wake_up(&waiter->fl_wait);
+		else
+			wake_up(&waiter->fl_wait);
 		if (wait) {
 			/* Let the blocked process remove waiter from the
 			 * block list when it gets scheduled.
 			 */
 			current->policy |= SCHED_YIELD;
 			schedule();
-		} else {
-			/* Remove waiter from the block list, because by the
-			 * time it wakes up blocker won't exist any more.
-			 */
-			locks_delete_block(blocker, waiter);
 		}
 	}
 	return;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nfs/dir.c linux.19p18/fs/nfs/dir.c
--- linux.vanilla/fs/nfs/dir.c	Mon Dec 11 22:13:03 2000
+++ linux.19p18/fs/nfs/dir.c	Mon Feb 12 14:51:59 2001
@@ -45,6 +45,7 @@
 static int nfs_safe_remove(struct dentry *);
 
 static ssize_t nfs_dir_read(struct file *, char *, size_t, loff_t *);
+static loff_t nfs_dir_llseek(struct file *, loff_t, int);
 static int nfs_readdir(struct file *, void *, filldir_t);
 static struct dentry *nfs_lookup(struct inode *, struct dentry *);
 static int nfs_create(struct inode *, struct dentry *, int);
@@ -58,7 +59,7 @@
 		      struct inode *, struct dentry *);
 
 static struct file_operations nfs_dir_operations = {
-	NULL,			/* lseek - default */
+	nfs_dir_llseek,		/* llseek */
 	nfs_dir_read,		/* read - bad */
 	NULL,			/* write - bad */
 	nfs_readdir,		/* readdir */
@@ -131,7 +132,7 @@
 	struct file	*file = desc->file;
 	struct dentry	*dir = file->f_dentry;
 	struct inode	*inode = dir->d_inode;
-	struct nfs_fattr dir_attr;
+	struct rpc_cred	*cred = nfs_file_cred(file);
 	void		*buffer = (void *)page_address(page);
 	int		plus = NFS_USE_READDIRPLUS(inode);
 	int		error;
@@ -139,11 +140,9 @@
 	dfprintk(VFS, "NFS: nfs_readdir_filler() reading cookie %Lu into page %lu.\n", (long long)desc->entry->cookie, page->offset);
 
  again:
-	error = NFS_CALL(readdir, inode, (dir, &dir_attr,
-					  nfs_file_cred(file),
+	error = NFS_PROTO(inode)->readdir(inode, cred,
 					  desc->entry->cookie, buffer,
-					  NFS_SERVER(inode)->dtsize, plus));
-	nfs_refresh_inode(inode, &dir_attr);
+					  NFS_SERVER(inode)->dtsize, plus);
 	/* We requested READDIRPLUS, but the server doesn't grok it */
 	if (desc->plus && error == -ENOTSUPP) {
 		NFS_FLAGS(inode) &= ~NFS_INO_ADVISE_RDPLUS;
@@ -339,7 +338,7 @@
 	struct file	*file = desc->file;
 	struct dentry	*dir = file->f_dentry;
 	struct inode	*inode = dir->d_inode;
-	struct nfs_fattr dir_attr;
+	struct rpc_cred	*cred = nfs_file_cred(file);
 	struct page	*page = NULL;
 	unsigned long	cache_page;
 	u32		*p;
@@ -358,11 +357,8 @@
 	}
 	page = page_cache_entry(cache_page);
 	p = (u32 *)page_address(page);
-	status = NFS_CALL(readdir, inode, (dir, &dir_attr,
-					   nfs_file_cred(file),
-					   desc->target, p,
-					   NFS_SERVER(inode)->dtsize, 0));
-	nfs_refresh_inode(inode, &dir_attr);
+	status = NFS_PROTO(inode)->readdir(inode, cred, desc->target, p,
+					   NFS_SERVER(inode)->dtsize, 0);
 	if (status >= 0) {
 		p = desc->decode(p, desc->entry, 0);
 		if (IS_ERR(p))
@@ -452,6 +448,22 @@
 	return 0;
 }
 
+/*
+ * nfs_dir_llseek(): cater for the fact that NFS(v2|v3) readdir
+ *		     cookies take (32|64)-bit unsigned values.
+ */
+static loff_t nfs_dir_llseek(struct file *file, loff_t offset, int origin)
+{
+	/* We disallow SEEK_CUR and SEEK_END */
+	if (origin != 0)
+		return -EINVAL;
+	if (offset != file->f_pos) {
+		file->f_pos = offset;
+		file->f_reada = 0;
+		file->f_version = ++global_event;
+	}
+	return (offset > 0) ? offset : 0;
+}
 
 /*
  * Whenever an NFS operation succeeds, we know that the dentry
@@ -521,11 +533,10 @@
  */
 static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
 {
-	struct dentry		*dir = dentry->d_parent;
-	struct inode		*inode = dentry->d_inode,
-				*dir_i = dir->d_inode;
+	struct inode		*dir = dentry->d_parent->d_inode;
+	struct inode		*inode = dentry->d_inode;
 	struct nfs_fh		fhandle;
-	struct nfs_fattr	fattr, dir_attr;
+	struct nfs_fattr	fattr;
 	int error;
 
 	/*
@@ -541,7 +552,7 @@
 
 	if (is_bad_inode(inode)) {
 		dfprintk(VFS, "nfs_lookup_validate: %s/%s has dud inode\n",
-			dir->d_name.name, dentry->d_name.name);
+			dentry->d_parent->d_name.name, dentry->d_name.name);
 		goto out_bad;
 	}
 
@@ -549,7 +560,7 @@
 		goto out_valid;
 
 	if (IS_ROOT(dentry)) {
-		__nfs_revalidate_inode(dentry);
+		__nfs_revalidate_inode(NFS_SERVER(inode), inode);
 		goto out_valid_renew;
 	}
 
@@ -559,8 +570,7 @@
 	/*
 	 * Do a new lookup and check the dentry attributes.
 	 */
-	error = NFS_CALL(lookup, dir_i, (dir, &dir_attr,
-				  &dentry->d_name, &fhandle, &fattr));
+	error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr);
 	if (error < 0)
 		goto out_bad;
 
@@ -570,18 +580,12 @@
 	    NFS_FILEID(inode) != fattr.fileid)
 		goto out_bad;
 
-	/* Filehandle matches? */
-	if (NFS_FH(dentry)->size == 0)
-		goto out_bad;
+	/* Ok, remember that we successfully checked it.. */
+	nfs_refresh_inode(inode, &fattr);
 
-	if (NFS_FH(dentry)->size != fhandle.size ||
-	    memcmp(NFS_FH(dentry)->data, fhandle.data, fhandle.size))
+	if (nfs_inode_is_stale(inode, &fhandle, &fattr))
 		goto out_bad;
 
-	/* Ok, remeber that we successfully checked it.. */
-	nfs_refresh_inode(inode, &fattr);
-	nfs_refresh_inode(dir_i, &dir_attr);
-
  out_valid_renew:
 	nfs_renew_times(dentry);
  out_valid:
@@ -593,10 +597,9 @@
 	if (have_submounts(dentry))
 		goto out_valid;
 	d_drop(dentry);
-	if (dentry->d_parent->d_inode)
-		NFS_CACHEINV(dentry->d_parent->d_inode);
+	nfs_zap_caches(dir);
 	if (inode && S_ISDIR(inode->i_mode))
-		NFS_CACHEINV(inode);
+		nfs_zap_caches(inode);
 	return 0;
 }
 
@@ -611,33 +614,6 @@
 	}
 }
 
-__inline__ struct nfs_fh *nfs_fh_alloc(void)
-{
-	struct nfs_fh *p;
-
-	p = kmalloc(sizeof(*p), GFP_KERNEL);
-	if (!p)
-		return NULL;
-	memset(p, 0, sizeof(*p));
-	return p;
-}
-
-__inline__ void nfs_fh_free(struct nfs_fh *p)
-{
-	kfree(p);
-}
-
-/*
- * Called when the dentry is being freed to release private memory.
- */
-static void nfs_dentry_release(struct dentry *dentry)
-{
-	if (dentry->d_fsdata) {
-		nfs_fh_free(dentry->d_fsdata);
-		dentry->d_fsdata = NULL;
-	}
-}
-
 /*
  * Called when the dentry loses inode.
  * We use it to clean up silly-renamed files.
@@ -654,44 +630,33 @@
 	NULL,			/* d_hash */
 	NULL,			/* d_compare */
 	nfs_dentry_delete,	/* d_delete(struct dentry *) */
-	nfs_dentry_release,	/* d_release(struct dentry *) */
+	NULL,			/* d_release(struct dentry *) */
 	nfs_dentry_iput		/* d_iput */
 };
 
-static struct dentry *nfs_lookup(struct inode *dir_i, struct dentry * dentry)
+static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry)
 {
-	struct dentry *dir = dentry->d_parent;
 	struct inode *inode;
 	int error;
 	struct nfs_fh fhandle;
-	struct nfs_fattr fattr, dir_attr;
+	struct nfs_fattr fattr;
 
 	dfprintk(VFS, "NFS: lookup(%s/%s)\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name);
 
 	error = -ENAMETOOLONG;
-	if (dentry->d_name.len > NFS_SERVER(dir_i)->namelen)
+	if (dentry->d_name.len > NFS_SERVER(dir)->namelen)
 		goto out;
 
 	dentry->d_op = &nfs_dentry_operations;
 
-	if (!dentry->d_fsdata) {
-		dentry->d_fsdata = nfs_fh_alloc();
-		if (!dentry->d_fsdata) {
-			error = -ENOMEM;
-			goto out;
-		}
-	}
-
 #if NFS_FIXME
 	inode = nfs_dircache_lookup(dir_i, dentry);
 	if (inode)
 		goto no_entry;
 #endif
 
-	error = NFS_CALL(lookup, dir_i, (dir, &dir_attr,
-				 &dentry->d_name, &fhandle, &fattr));
-	nfs_refresh_inode(dir_i, &dir_attr);
+	error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr);
 	inode = NULL;
 	if (error == -ENOENT)
 		goto no_entry;
@@ -734,16 +699,15 @@
  * that the operation succeeded on the server, but an error in the
  * reply path made it appear to have failed.
  */
-static int nfs_create(struct inode *dir_i, struct dentry *dentry, int mode)
+static int nfs_create(struct inode *dir, struct dentry *dentry, int mode)
 {
-	struct dentry	*dir = dentry->d_parent;
 	struct iattr	 attr;
-	struct nfs_fattr fattr, dir_attr;
+	struct nfs_fattr fattr;
 	struct nfs_fh	 fhandle;
 	int		 error;
 
 	dfprintk(VFS, "NFS: create(%x/%ld, %s\n",
-		dir_i->i_dev, dir_i->i_ino, dentry->d_name.name);
+		dir->i_dev, dir->i_ino, dentry->d_name.name);
 
 #ifdef NFSD_BROKEN_UID
 	/* We set uid/gid in the request because IBM's broken nfsd
@@ -767,10 +731,9 @@
 	 * select the appropriate create strategy. Currently open_namei
 	 * does not pass the create flags.
 	 */
-	nfs_zap_caches(dir_i);
-	error = NFS_CALL(create, dir_i, (dir, &dir_attr, &dentry->d_name,
-			&attr, 0, &fhandle, &fattr));
-	nfs_refresh_inode(dir_i, &dir_attr);
+	nfs_zap_caches(dir);
+	error = NFS_PROTO(dir)->create(dir, &dentry->d_name,
+					&attr, 0, &fhandle, &fattr);
 	if (!error && fhandle.size != 0)
 		error = nfs_instantiate(dentry, &fhandle, &fattr);
 	if (error || fhandle.size == 0)
@@ -781,16 +744,15 @@
 /*
  * See comments for nfs_proc_create regarding failed operations.
  */
-static int nfs_mknod(struct inode *dir_i, struct dentry *dentry, int mode, int rdev)
+static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
 {
-	struct dentry	*dir = dentry->d_parent;
 	struct iattr	 attr;
-	struct nfs_fattr fattr, dir_attr;
+	struct nfs_fattr fattr;
 	struct nfs_fh	 fhandle;
 	int		 error;
 
 	dfprintk(VFS, "NFS: mknod(%x/%ld, %s\n",
-		dir_i->i_dev, dir_i->i_ino, dentry->d_name.name);
+		dir->i_dev, dir->i_ino, dentry->d_name.name);
 
 #ifdef NFSD_BROKEN_UID
 	attr.ia_valid = ATTR_MODE | ATTR_UID | ATTR_GID;
@@ -803,10 +765,9 @@
 #endif
 
 
-	nfs_zap_caches(dir_i);
-	error = NFS_CALL(mknod, dir_i, (dir, &dir_attr, &dentry->d_name,
-				&attr, rdev, &fhandle, &fattr));
-	nfs_refresh_inode(dir_i, &dir_attr);
+	nfs_zap_caches(dir);
+	error = NFS_PROTO(dir)->mknod(dir, &dentry->d_name,
+				&attr, rdev, &fhandle, &fattr);
 	if (!error && fhandle.size != 0)
 		error = nfs_instantiate(dentry, &fhandle, &fattr);
 	if (error || fhandle.size == 0)
@@ -817,16 +778,15 @@
 /*
  * See comments for nfs_proc_create regarding failed operations.
  */
-static int nfs_mkdir(struct inode *dir_i, struct dentry *dentry, int mode)
+static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
-	struct dentry   *dir = dentry->d_parent;
 	struct iattr	 attr;
-	struct nfs_fattr fattr, dir_attr;
+	struct nfs_fattr fattr;
 	struct nfs_fh	 fhandle;
 	int		 error;
 
 	dfprintk(VFS, "NFS: mkdir(%x/%ld, %s)\n",
-		dir_i->i_dev, dir_i->i_ino, dentry->d_name.name);
+		dir->i_dev, dir->i_ino, dentry->d_name.name);
 
 #ifdef NFSD_BROKEN_UID
 	attr.ia_valid = ATTR_MODE | ATTR_UID | ATTR_GID;
@@ -838,10 +798,8 @@
 	attr.ia_mode = mode | S_IFDIR;
 #endif
 
-	nfs_zap_caches(dir_i);
-	error = NFS_CALL(mkdir, dir_i, (dir, &dir_attr,
-				&dentry->d_name, &attr, &fhandle, &fattr));
-	nfs_refresh_inode(dir_i, &dir_attr);
+	nfs_zap_caches(dir);
+	error = NFS_PROTO(dir)->mkdir(dir, &dentry->d_name, &attr, &fhandle, &fattr);
 	if (!error && fhandle.size != 0)
 		error = nfs_instantiate(dentry, &fhandle, &fattr);
 
@@ -850,18 +808,15 @@
 	return error;
 }
 
-static int nfs_rmdir(struct inode *dir_i, struct dentry *dentry)
+static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
 {
-	struct dentry	*dir = dentry->d_parent;
-	struct nfs_fattr dir_attr;
 	int		 error;
 
 	dfprintk(VFS, "NFS: rmdir(%x/%ld, %s\n",
-		dir_i->i_dev, dir_i->i_ino, dentry->d_name.name);
+		dir->i_dev, dir->i_ino, dentry->d_name.name);
 
-	nfs_zap_caches(dir_i);
-	error = NFS_CALL(rmdir, dir_i, (dir, &dir_attr, &dentry->d_name));
-	nfs_refresh_inode(dir_i, &dir_attr);
+	nfs_zap_caches(dir);
+	error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name);
 
 	/* Free the inode */
 	if (!error)
@@ -925,12 +880,10 @@
 	return sdentry;
 }
 
-static int nfs_sillyrename(struct inode *dir_i, struct dentry *dentry)
+static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
 {
-	struct dentry	*dir = dentry->d_parent;
 	static unsigned int sillycounter = 0;
-	struct nfs_fattr dir_attr;
-	const int        i_inosize  = sizeof(dir_i->i_ino)*2;
+	const int        i_inosize  = sizeof(dir->i_ino)*2;
 	const int        countersize = sizeof(sillycounter)*2;
 	const int        slen       = strlen(".nfs") + i_inosize + countersize;
 	struct qstr      qsilly;
@@ -985,12 +938,10 @@
 			goto out;
 	} while(sdentry->d_inode != NULL); /* need negative lookup */
 
-	nfs_zap_caches(dir_i);
+	nfs_zap_caches(dir);
 	qsilly.name = silly;
 	qsilly.len  = strlen(silly);
-	error = NFS_CALL(rename, dir_i, (dir, &dir_attr, &dentry->d_name,
-				  dir, &dir_attr, &qsilly));
-	nfs_refresh_inode(dir_i, &dir_attr);
+	error = NFS_PROTO(dir)->rename(dir, &dentry->d_name, dir, &qsilly);
 	if (!error) {
 		nfs_renew_times(dentry);
 		d_move(dentry, sdentry);
@@ -1011,9 +962,7 @@
  */
 static int nfs_safe_remove(struct dentry *dentry)
 {
-	struct nfs_fattr dir_attr;
-	struct dentry	*dir = dentry->d_parent;
-	struct inode	*dir_i = dir->d_inode,   
+	struct inode	*dir = dentry->d_parent->d_inode,
 			*inode = dentry->d_inode;
 	int		 error = 0, rehash = 0;
 		
@@ -1049,11 +998,10 @@
 		goto out;
 	}
 
-	nfs_zap_caches(dir_i);
+	nfs_zap_caches(dir);
 	if (inode)
 		NFS_CACHEINV(inode);
-	error = NFS_CALL(remove, dir_i, (dir, &dir_attr, &dentry->d_name));
-	nfs_refresh_inode(dir_i, &dir_attr);
+	error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
 	if (error < 0)
 		goto out;
 
@@ -1096,20 +1044,19 @@
 }
 
 static int
-nfs_symlink(struct inode *dir_i, struct dentry *dentry, const char *symname)
+nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
 {
-	struct dentry	*dir = dentry->d_parent;
-	struct nfs_fattr dir_attr, sym_attr;
+	struct nfs_fattr sym_attr;
 	struct nfs_fh    sym_fh;
 	struct iattr     attr;
 	struct qstr      qsymname;
 	int              error, mode, maxlen;
 
 	dfprintk(VFS, "NFS: symlink(%x/%ld, %s, %s)\n",
-		dir_i->i_dev, dir_i->i_ino, dentry->d_name.name, symname);
+		dir->i_dev, dir->i_ino, dentry->d_name.name, symname);
 
 	error = -ENAMETOOLONG;
-	maxlen = (NFS_PROTO(dir_i)->version==2) ? NFS2_MAXPATHLEN : NFS3_MAXPATHLEN;
+	maxlen = (NFS_PROTO(dir)->version==2) ? NFS2_MAXPATHLEN : NFS3_MAXPATHLEN;
 	if (strlen(symname) > maxlen)
 		goto out;
 
@@ -1137,11 +1084,9 @@
 	qsymname.name = symname;
 	qsymname.len  = strlen(symname);
 
-	nfs_zap_caches(dir_i);
-	error = NFS_CALL(symlink, dir_i, (dir, &dir_attr,
-				&dentry->d_name, &qsymname, &attr,
-				&sym_fh, &sym_attr));
-	nfs_refresh_inode(dir_i, &dir_attr);
+	nfs_zap_caches(dir);
+	error = NFS_PROTO(dir)->symlink(dir, &dentry->d_name, &qsymname,
+					&attr, &sym_fh, &sym_attr);
 	if (!error && sym_fh.size != 0 && (sym_attr.valid & NFS_ATTR_FATTR)) {
 		error = nfs_instantiate(dentry, &sym_fh, &sym_attr);
 	} else {
@@ -1157,11 +1102,9 @@
 }
 
 static int 
-nfs_link(struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry)
+nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
 {
-	struct dentry	*dir = dentry->d_parent;
 	struct inode	*inode = old_dentry->d_inode;
-	struct nfs_fattr old_attr, dir_attr;
 	int		 error;
 
 	dfprintk(VFS, "NFS: link(%s/%s -> %s/%s)\n",
@@ -1174,12 +1117,9 @@
 	 * we can't use the existing dentry.
 	 */
 	d_drop(dentry);
-	nfs_zap_caches(dir_i);
+	nfs_zap_caches(dir);
 	NFS_CACHEINV(inode);
-	error = NFS_CALL(link, inode, (old_dentry, &old_attr,
-				       dir, &dir_attr, &dentry->d_name));
-	nfs_refresh_inode(inode, &old_attr);
-	nfs_refresh_inode(dir_i, &dir_attr);
+	error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name);
 	return error;
 }
 
@@ -1214,7 +1154,6 @@
 static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 		      struct inode *new_dir, struct dentry *new_dentry)
 {
-	struct nfs_fattr old_attr, new_attr;
 	struct inode *   old_inode = old_dentry->d_inode;
 	struct inode *   new_inode = new_dentry->d_inode;
 	struct dentry *  dentry = NULL, *rehash = NULL;
@@ -1296,12 +1235,8 @@
 
 	nfs_zap_caches(new_dir);
 	nfs_zap_caches(old_dir);
-	error = NFS_CALL(rename, old_dir,
-			 (old_dentry->d_parent, &old_attr, &old_dentry->d_name,
-			  new_dentry->d_parent, &new_attr, &new_dentry->d_name));
-	nfs_refresh_inode(old_dir, &old_attr);
-	nfs_refresh_inode(new_dir, &new_attr);
-
+	error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name,
+			  		   new_dir, &new_dentry->d_name);
 out:
 	/* Update the dcache if needed */
 	if (rehash)
@@ -1315,14 +1250,11 @@
 }
 
 int
-nfs_permission(struct inode *i, int msk)
+nfs_permission(struct inode *inode, int mask)
 {
-	struct nfs_fattr	fattr;
-	struct dentry		*de = NULL;
-	int			err = vfs_permission(i, msk);
-	struct list_head	*start, *tmp;
+	int			error = vfs_permission(inode, mask);
 
-	if (!NFS_PROTO(i)->access)
+	if (!NFS_PROTO(inode)->access)
 		goto out;
 	/*
 	 * Trust UNIX mode bits except:
@@ -1332,28 +1264,18 @@
 	 * 3) When ACLs may overturn a negative answer */
 	if (!capable(CAP_DAC_OVERRIDE) && !capable(CAP_DAC_READ_SEARCH)
 	    && (current->fsuid != 0) && (current->fsgid != 0)
-	    && err != -EACCES)
+	    && error != -EACCES)
 		goto out;
 
-	tmp = start = &i->i_dentry;
-	while ((tmp = tmp->next) != start) {
-		de = list_entry(tmp, struct dentry, d_alias);
-		if (de->d_inode == i)
-			break;
-	}
-	if (!de || de->d_inode != i)
-		return 0;
+	error = NFS_PROTO(inode)->access(inode, mask, 0);
 
-	err = NFS_CALL(access, i, (de, msk, &fattr, 0));
-
-	if (err == -EACCES && NFS_CLIENT(i)->cl_droppriv &&
+	if (error == -EACCES && NFS_CLIENT(inode)->cl_droppriv &&
 	    current->uid != 0 && current->gid != 0 &&
 	    (current->fsuid != current->uid || current->fsgid != current->gid))
-		err = NFS_CALL(access, i, (de, msk, &fattr, 1));
+		error = NFS_PROTO(inode)->access(inode, mask, 1);
 
-	nfs_refresh_inode(i, &fattr);
  out:
-	return err;
+	return error;
 }
 
 /*
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nfs/file.c linux.19p18/fs/nfs/file.c
--- linux.vanilla/fs/nfs/file.c	Mon Dec 11 22:13:03 2000
+++ linux.19p18/fs/nfs/file.c	Mon Feb 12 14:51:59 2001
@@ -111,13 +111,14 @@
 nfs_file_read(struct file * file, char * buf, size_t count, loff_t *ppos)
 {
 	struct dentry * dentry = file->f_dentry;
+	struct inode  * inode = dentry->d_inode;
 	ssize_t result;
 
 	dfprintk(VFS, "nfs: read(%s/%s, %lu@%lu)\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name,
 		(unsigned long) count, (unsigned long) *ppos);
 
-	result = nfs_revalidate_inode(dentry);
+	result = nfs_revalidate_inode(NFS_SERVER(inode), inode);
 	if (!result)
 		result = generic_file_read(file, buf, count, ppos);
 	return result;
@@ -127,12 +128,13 @@
 nfs_file_mmap(struct file * file, struct vm_area_struct * vma)
 {
 	struct dentry *dentry = file->f_dentry;
+	struct inode *inode = dentry->d_inode;
 	int	status;
 
 	dfprintk(VFS, "nfs: mmap(%s/%s)\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name);
 
-	status = nfs_revalidate_inode(dentry);
+	status = nfs_revalidate_inode(NFS_SERVER(inode), inode);
 	if (!status)
 		status = generic_file_mmap(file, vma);
 	return status;
@@ -182,10 +184,8 @@
 	rpages = NFS_SERVER(inode)->rpages;
 	result = nfs_pagein_inode(inode, index, rpages);
 	if (result < 0)
-		goto out_bad;
+		return result;
 	return 0;
- out_bad:
-	return result;
 }
 
 /* 
@@ -205,7 +205,7 @@
 	result = -EBUSY;
 	if (IS_SWAPFILE(inode))
 		goto out_swapfile;
-	result = nfs_revalidate_inode(dentry);
+	result = nfs_revalidate_inode(NFS_SERVER(inode), inode);
 	if (result)
 		goto out;
 
@@ -265,7 +265,9 @@
 	 * Flush all pending writes before doing anything
 	 * with locks..
 	 */
+	down(&inode->i_sem);
 	status = nfs_wb_all(inode);
+	up(&inode->i_sem);
 	if (status < 0)
 		goto out_unlock;
 
@@ -280,8 +282,10 @@
  out_unlock:
  out_ok:
 	if ((cmd == F_SETLK || cmd == F_SETLKW) && fl->fl_type != F_UNLCK) {
+		down(&inode->i_sem);
 		nfs_wb_all(inode);	/* we may have slept */
 		nfs_zap_caches(inode);
+		up(&inode->i_sem);
 	}
 	return status;
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nfs/inode.c linux.19p18/fs/nfs/inode.c
--- linux.vanilla/fs/nfs/inode.c	Mon Dec 11 22:13:03 2000
+++ linux.19p18/fs/nfs/inode.c	Mon Feb 12 14:51:59 2001
@@ -40,11 +40,10 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
-#define CONFIG_NFS_SNAPSHOT 1
 #define NFSDBG_FACILITY		NFSDBG_VFS
 #define NFS_PARANOIA 1
 
-static struct inode * __nfs_fhget(struct super_block *, struct nfs_fattr *);
+static struct inode * __nfs_fhget(struct super_block *, struct nfs_fh *, struct nfs_fattr *);
 
 static void nfs_read_inode(struct inode *);
 static void nfs_put_inode(struct inode *);
@@ -53,8 +52,6 @@
 static void nfs_put_super(struct super_block *);
 static int  nfs_statfs(struct super_block *, struct statfs *, int);
 static void nfs_umount_begin(struct super_block *);
-static struct nfs_file *nfs_file_alloc(void);
-static void nfs_file_free(struct nfs_file *p);
 
 static struct super_operations nfs_sops = { 
 	nfs_read_inode,		/* read inode */
@@ -256,7 +253,7 @@
 		return NULL;
 	}
 
-	inode = __nfs_fhget(sb, &fattr);
+	inode = __nfs_fhget(sb, rootfh, &fattr);
 	return inode;
 }
 
@@ -273,9 +270,7 @@
 	struct nfs_server	*server;
 	struct rpc_xprt		*xprt = 0;
 	struct rpc_clnt		*clnt = 0;
-	struct nfs_fh		*root_fh = NULL,
-				*root = &data->root,
-				fh;
+	struct nfs_fh		fh;
 	struct inode		*root_inode = NULL;
 	unsigned int		authflavor;
 	struct sockaddr_in	srvaddr;
@@ -290,7 +285,6 @@
 		goto failure;
 	}
 
-	memset(&fh, 0, sizeof(fh));
 	if (data->version != NFS_MOUNT_VERSION) {
 		printk(KERN_WARNING "nfs warning: mount version %s than kernel\n",
 			data->version < NFS_MOUNT_VERSION ? "older" : "newer");
@@ -298,12 +292,21 @@
 			data->namlen = 0;
 		if (data->version < 3)
 			data->bsize  = 0;
-		if (data->version < 4) {
+		if (data->version < 4)
 			data->flags &= ~NFS_MOUNT_VER3;
-			root = &fh;
-			root->size = NFS2_FHSIZE;
-			memcpy(root->data, data->old_root.data, NFS2_FHSIZE);
+	}
+
+	memset(&fh, 0, sizeof(fh));
+	if (data->version < 4) {
+		fh.size = NFS2_FHSIZE;
+		memcpy(fh.data, data->old_root.data, NFS2_FHSIZE);
+	} else {
+		fh.size = (data->flags & NFS_MOUNT_VER3) ? data->root.size : NFS2_FHSIZE;
+		if (fh.size > sizeof(fh.data)) {
+			printk(KERN_WARNING "NFS: mount program passes invalid filehandle!\n");
+			goto failure;
 		}
+		memcpy(fh.data, data->root.data, fh.size);
 	}
 
 	/* We now require that the mount process passes the remote address */
@@ -351,19 +354,15 @@
 	if (data->flags & NFS_MOUNT_VER3) {
 #ifdef CONFIG_NFS_V3
 		server->rpc_ops = &nfs_v3_clientops;
-		NFS_SB_FHSIZE(sb) = sizeof(unsigned short) + NFS3_FHSIZE;
+		NFS_SB_FHSIZE(sb) = NFS3_FHSIZE;
 		version = 3;
-		if (data->version < 4) {
-			printk(KERN_NOTICE "NFS: NFSv3 not supported by mount program.\n");
-			goto failure_unlock;
-		}
 #else
 		printk(KERN_NOTICE "NFS: NFSv3 not supported.\n");
 		goto failure_unlock;
 #endif
 	} else {
 		server->rpc_ops = &nfs_v2_clientops;
-		NFS_SB_FHSIZE(sb) = sizeof(unsigned short) + NFS2_FHSIZE;
+		NFS_SB_FHSIZE(sb) = NFS2_FHSIZE;
 		version = 2;
 	}
 
@@ -419,17 +418,12 @@
 	 * Keep the super block locked while we try to get 
 	 * the root fh attributes.
 	 */
-	root_fh = nfs_fh_alloc();
-	if (!root_fh)
-		goto out_no_fh;
-	memcpy((u8*)root_fh, (u8*)root, sizeof(*root_fh));
-
 	/* Did getting the root inode fail? */
-	if ((root->size > NFS_SB_FHSIZE(sb)
-	     || ! (root_inode = nfs_get_root(sb, root)))
+	if ((fh.size > NFS_SB_FHSIZE(sb)
+	     || ! (root_inode = nfs_get_root(sb, &fh)))
 	    && (data->flags & NFS_MOUNT_VER3)) {
 		data->flags &= ~NFS_MOUNT_VER3;
-		nfs_fh_free(root_fh);
+		fh.size = NFS2_FHSIZE;
 		rpciod_down();
 		rpc_shutdown_client(server->client);
 		goto nfsv3_try_again;
@@ -441,11 +435,9 @@
 		goto failure_put_root;
 
 	sb->s_root->d_op = &nfs_dentry_operations;
-	sb->s_root->d_fsdata = root_fh;
-	sb->u.nfs_sb.s_root = root_fh;
 
 	/* Get some general file system info */
-	if (server->rpc_ops->statfs(server, root, &fsinfo) >= 0) {
+	if (server->rpc_ops->statfs(server, &fh, &fsinfo) >= 0) {
 		if (server->namelen == 0)
 			server->namelen = fsinfo.namelen;
 	} else {
@@ -518,9 +510,6 @@
  failure_put_root:
 	if (root_inode)
 		iput(root_inode);
-	if (root_fh)
-		nfs_fh_free(root_fh);
- out_no_fh:
 	rpciod_down();
 
  failure_unlock:
@@ -552,7 +541,7 @@
 	struct nfs_fsinfo	res;
 	struct statfs		tmp;
 
-	error = server->rpc_ops->statfs(server, NFS_FH(sb->s_root), &res);
+	error = server->rpc_ops->statfs(server, NFS_FH(sb->s_root->d_inode), &res);
 	if (error) {
 		printk(KERN_NOTICE "nfs_statfs: statfs error = %d\n", -error);
 		memset(&res, 0, sizeof(res));
@@ -590,46 +579,6 @@
 #endif
 
 /*
- * Free all unused dentries in an inode's alias list.
- *
- * Subtle note: we have to be very careful not to cause
- * any IO operations with the stale dentries, as this
- * could cause file corruption. But since the dentry
- * count is 0 and all pending IO for a dentry has been
- * flushed when the count went to 0, we're safe here.
- * Also returns the number of unhashed dentries
- */
-static int
-nfs_free_dentries(struct inode *inode)
-{
-	struct list_head *tmp, *head = &inode->i_dentry;
-	int unhashed;
-
-restart:
-	tmp = head->next;
-	unhashed = 0;
-	while (tmp != head) {
-		struct dentry *dentry = list_entry(tmp, struct dentry, d_alias);
-		dget(dentry);
-		if (!list_empty(&dentry->d_subdirs))
-			shrink_dcache_parent(dentry);
-		dprintk("nfs_free_dentries: found %s/%s, d_count=%d, hashed=%d\n",
-			dentry->d_parent->d_name.name, dentry->d_name.name,
-			dentry->d_count, !list_empty(&dentry->d_hash));
-		if (dentry->d_count == 1) {
-			d_drop(dentry);
-			dput(dentry);
-			goto restart;
-		}
-		if (list_empty(&dentry->d_hash))
-			unhashed++;
-		tmp = tmp->next;
-		dput(dentry);
-	}
-	return unhashed;
-}
-
-/*
  * Zap the caches.
  */
 void nfs_zap_caches(struct inode *inode)
@@ -657,7 +606,7 @@
  * Fill in inode information from the fattr.
  */
 static void
-nfs_fill_inode(struct inode *inode, struct nfs_fattr *fattr)
+nfs_fill_inode(struct inode *inode, struct nfs_fh *fh, struct nfs_fattr *fattr)
 {
 	/*
 	 * Check whether the mode has been set, as we only want to
@@ -697,25 +646,15 @@
 		NFS_CACHE_ISIZE(inode) = fattr->size;
 		NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
 		NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
+		memcpy(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh));
 	}
 	nfs_refresh_inode(inode, fattr);
 }
 
-static struct inode *
-nfs_make_new_inode(struct super_block *sb, struct nfs_fattr *fattr)
-{
-	struct inode *inode = get_empty_inode();
-
-	if (!inode)
-		return NULL;	
-	inode->i_sb = sb;
-	inode->i_dev = sb->s_dev;
-	inode->i_flags = 0;
-	inode->i_ino = nfs_fattr_to_ino_t(fattr);
-	nfs_read_inode(inode);
-	nfs_fill_inode(inode, fattr);
-	return inode;
-}
+struct nfs_find_desc {
+	struct nfs_fh		*fh;
+	struct nfs_fattr	*fattr;
+};
 
 /*
  * In NFSv3 we can have 64bit inode numbers. In order to support
@@ -726,50 +665,39 @@
 static int
 nfs_find_actor(struct inode *inode, unsigned long ino, void *opaque)
 {
-	struct nfs_fattr *fattr = (struct nfs_fattr *)opaque;
+	struct nfs_find_desc	*desc = (struct nfs_find_desc *)opaque;
+	struct nfs_fh		*fh = desc->fh;
+	struct nfs_fattr	*fattr = desc->fattr;
+
 	if (NFS_FSID(inode) != fattr->fsid)
 		return 0;
 	if (NFS_FILEID(inode) != fattr->fileid)
 		return 0;
-	if (inode->i_mode &&
-	    (fattr->mode & S_IFMT) != (inode->i_mode & S_IFMT))
-		return 0;
-	if (is_bad_inode(inode))
-		return 0;
-	if (NFS_FLAGS(inode) & NFS_INO_STALE)
+	if (memcmp(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh)) != 0)
 		return 0;
 	return 1;
 }
 
-static int
-nfs_inode_is_stale(struct inode *inode, struct nfs_fattr *fattr)
+int
+nfs_inode_is_stale(struct inode *inode, struct nfs_fh *fh, struct nfs_fattr *fattr)
 {
-	int unhashed;
-	int is_stale = 0;
 
-	if (inode->i_mode &&
-	    (fattr->mode & S_IFMT) != (inode->i_mode & S_IFMT))
-		is_stale = 1;
+	/* Empty inodes are not stale */
+	if (!inode->i_mode)
+		return 0;
 
-	if (is_bad_inode(inode))
-		is_stale = 1;
+	if ((fattr->mode & S_IFMT) != (inode->i_mode & S_IFMT))
+		return 1;
 
-	/*
-	 * If the inode seems stale, free up cached dentries.
-	 */
-	unhashed = nfs_free_dentries(inode);
+	if (is_bad_inode(inode))
+		return 1;
 
-	/* Assume we're holding an i_count
-	 *
-	 * NB: sockets sometimes have volatile file handles
-	 *     don't invalidate their inodes even if all dentries are
-	 *     unhashed.
-	 */
-	if (unhashed && inode->i_count == unhashed + 1
-	    && !S_ISSOCK(inode->i_mode) && !S_ISFIFO(inode->i_mode))
-		is_stale = 1;
+	/* Has the filehandle changed? If so is the old one stale? */
+	if (memcmp(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh)) != 0 &&
+	    __nfs_revalidate_inode(NFS_SERVER(inode),inode) == -ESTALE)
+		return 1;
 
-	return is_stale;
+	return 0;
 }
 
 /*
@@ -778,8 +706,6 @@
  * the vfs read_inode function because there is no way to pass the
  * file handle or current attributes into the read_inode function.
  *
- * We provide a special check for NetApp .snapshot directories to avoid
- * inode aliasing problems. All snapshot inodes are anonymous (unhashed).
  */
 struct inode *
 nfs_fhget(struct dentry *dentry, struct nfs_fh *fhandle,
@@ -791,40 +717,16 @@
 		dentry->d_parent->d_name.name, dentry->d_name.name,
 		(long long) fattr->fileid);
 
-	/* Install the file handle in the dentry */
-	memcpy(NFS_FH(dentry), (u8*)fhandle, sizeof(*fhandle));
-
-#ifdef CONFIG_NFS_SNAPSHOT
-	/*
-	 * Check for NetApp snapshot dentries, and get an 
-	 * unhashed inode to avoid aliasing problems.
-	 */
-	if ((dentry->d_parent->d_inode->u.nfs_i.flags & NFS_IS_SNAPSHOT) ||
-	    (dentry->d_name.len == 9 &&
-	     memcmp(dentry->d_name.name, ".snapshot", 9) == 0)) {
-		struct inode *inode = nfs_make_new_inode(sb, fattr);
-		if (!inode)
-			goto out;
-		inode->u.nfs_i.flags |= NFS_IS_SNAPSHOT;
-		dprintk("NFS: nfs_fhget(snapshot ino=%ld)\n", inode->i_ino);
-	out:
-		return inode;
-	}
-#endif
-	return __nfs_fhget(sb, fattr);
+	return __nfs_fhget(sb, fhandle, fattr);
 }
 
 /*
  * Look up the inode by super block and fattr->fileid.
- *
- * Note carefully the special handling of busy inodes (i_count > 1).
- * With the kernel 2.1.xx dcache all inodes except hard links must
- * have i_count == 1 after iget(). Otherwise, it indicates that the
- * server has reused a fileid (i_ino) and we have a stale inode.
  */
 static struct inode *
-__nfs_fhget(struct super_block *sb, struct nfs_fattr *fattr)
+__nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
 {
+	struct nfs_find_desc desc = { fh, fattr };
 	struct inode	*inode = NULL;
 	unsigned long	ino;
 
@@ -833,34 +735,12 @@
 
 	ino = nfs_fattr_to_ino_t(fattr);
 
-	while((inode = iget4(sb, ino, nfs_find_actor, fattr)) != NULL) {
-
-		/*
-		 * Check for busy inodes, and attempt to get rid of any
-		 * unused local references. If successful, we release the
-		 * inode and try again.
-		 *
-		 * Note that the busy test uses the values in the fattr,
-		 * as the inode may have become a different object.
-		 * (We can probably handle modes changes here, too.)
-		 */
-		if (!nfs_inode_is_stale(inode,fattr))
-			break;
-
-		dprintk("__nfs_fhget: inode %ld still busy, i_count=%d\n",
-		       inode->i_ino, inode->i_count);
-		/* Mark the inode as being stale */
-		NFS_FLAGS(inode) |= NFS_INO_STALE;
-		nfs_zap_caches(inode);
-		iput(inode);
-	}
-
-	if (!inode)
+	if (!(inode = iget4(sb, ino, nfs_find_actor, &desc)))
 		goto out_no_inode;
 
-	nfs_fill_inode(inode, fattr);
-	dprintk("NFS: __nfs_fhget(%x/%ld ct=%d)\n",
-		inode->i_dev, inode->i_ino, inode->i_count);
+	nfs_fill_inode(inode, fh, fattr);
+	dprintk("NFS: __nfs_fhget(%x/%Ld ct=%d)\n",
+		inode->i_dev, (long long)NFS_FILEID(inode), inode->i_count);
 
 out:
 	return inode;
@@ -896,7 +776,7 @@
 		goto out;
 
 	/* Now perform the setattr call */
-	error = NFS_CALL(setattr, inode, (dentry, &fattr, attr));
+	error = NFS_PROTO(inode)->setattr(inode, &fattr, attr);
 	if (error || !(fattr.valid & NFS_ATTR_FATTR)) {
 		nfs_zap_caches(inode);
 		goto out;
@@ -954,52 +834,27 @@
 int
 nfs_revalidate(struct dentry *dentry)
 {
-	return nfs_revalidate_inode(dentry);
-}
-
-static __inline__ struct nfs_file *nfs_file_alloc(void)
-{
-	struct nfs_file	*p;
-	p = kmalloc(sizeof(*p), GFP_KERNEL);
-	if (p) {
-		memset(p, 0, sizeof(*p));
-		p->magic = NFS_FILE_MAGIC;
-	}
-	return p;
-}
-
-static __inline__ void nfs_file_free(struct nfs_file *p)
-{
-	if (p->magic == NFS_FILE_MAGIC) {
-		p->magic = 0;
-		kfree(p);
-	} else
-		printk(KERN_ERR "NFS: extra file info corrupted!\n");
+	struct inode *inode = dentry->d_inode;
+	return nfs_revalidate_inode(NFS_SERVER(inode), inode);
 }
 
 int nfs_open(struct inode *inode, struct file *filp)
 {
 	struct rpc_auth	*auth = NFS_CLIENT(inode)->cl_auth;
-	struct nfs_file	*data;
+	struct rpc_cred	*cred = rpcauth_lookupcred(auth, 0);
 
-	data = nfs_file_alloc();
-	if (!data)
-		return -ENOMEM;
-	data->cred = rpcauth_lookupcred(auth, 0);
-	filp->private_data = data;
+	filp->private_data = cred;
 	return 0;
 }
 
 int nfs_release(struct inode *inode, struct file *filp)
 {
-	struct nfs_file	*data = NFS_FILE(filp);
 	struct rpc_auth	*auth = NFS_CLIENT(inode)->cl_auth;
 	struct rpc_cred	*cred;
 
 	cred = nfs_file_cred(filp);
 	if (cred)
 		rpcauth_releasecred(auth, cred);
-	nfs_file_free(data);
 	return 0;
 }
 
@@ -1008,17 +863,15 @@
  * the cached attributes have to be refreshed.
  */
 int
-__nfs_revalidate_inode(struct dentry *dentry)
+__nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
 {
-	struct inode	*inode = dentry->d_inode;
 	struct nfs_fattr fattr;
 	int		 status = 0;
 
-	dfprintk(PAGECACHE, "NFS: revalidating %s/%s, ino=%ld\n",
-		dentry->d_parent->d_name.name, dentry->d_name.name,
-		inode->i_ino);
+	dfprintk(PAGECACHE, "NFS: revalidating (%x/%Ld)\n",
+		inode->i_dev, (long long)NFS_FILEID(inode));
 
-	if (!inode || is_bad_inode(inode))
+	if (!inode || is_bad_inode(inode) || NFS_STALE(inode))
 		return -ESTALE;
 
 	while (NFS_REVALIDATING(inode)) {
@@ -1026,58 +879,30 @@
 		if (status < 0)
 			return status;
 		if (time_before(jiffies,NFS_READTIME(inode)+NFS_ATTRTIMEO(inode)))
-			return 0;
+			return NFS_STALE(inode) ? -ESTALE : 0;
 	}
 	NFS_FLAGS(inode) |= NFS_INO_REVALIDATING;
 
-	status = NFS_CALL(getattr, inode, (dentry, &fattr));
+	status = NFS_PROTO(inode)->getattr(inode, &fattr);
 	if (status) {
-		int error;
-		u32 *fh;
-		struct dentry *dir = dentry->d_parent;
-		struct nfs_fh fhandle;
-		struct nfs_fattr dir_attr;
-
-		dfprintk(PAGECACHE, "nfs_revalidate_inode: %s/%s getattr failed, ino=%ld, error=%d\n",
-		       dentry->d_parent->d_name.name, dentry->d_name.name,
-		       inode->i_ino, status);
-		nfs_zap_caches(inode);
-
-		if (status != -ESTALE)
-			goto out;
-
-		/*
-		 * A "stale filehandle" error ... show the current fh
-		 * and find out what the filehandle should be.
-		 */
-		fh = (u32 *) NFS_FH(dentry);
-		dfprintk(PAGECACHE, "NFS: bad fh %08x%08x%08x%08x%08x%08x%08x%08x\n",
-			fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]);
-		error = NFS_CALL(lookup, dir->d_inode, (dir, &dir_attr, 
-					&dentry->d_name, &fhandle, &fattr));
-		nfs_refresh_inode(dir->d_inode, &dir_attr);
-		if (error) {
-			dfprintk(PAGECACHE, "NFS: lookup failed, error=%d\n", error);
-			goto out;
+		dfprintk(PAGECACHE, "nfs_revalidate_inode: (%x/%Ld) getattr failed, error=%d\n",
+			 inode->i_dev, (long long)NFS_FILEID(inode), status);
+		if (status == -ESTALE) {
+			NFS_FLAGS(inode) |= NFS_INO_STALE;
+			remove_inode_hash(inode);
 		}
-		fh = (u32 *) &fhandle;
-		dfprintk(PAGECACHE, "            %08x%08x%08x%08x%08x%08x%08x%08x\n",
-			fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]);
-		if (!IS_ROOT(dentry) && !have_submounts(dentry))
-			d_drop(dentry);
 		goto out;
 	}
 
 	status = nfs_refresh_inode(inode, &fattr);
 	if (status) {
-		dfprintk(PAGECACHE, "nfs_revalidate_inode: %s/%s refresh failed, ino=%ld, error=%d\n",
-			 dentry->d_parent->d_name.name, dentry->d_name.name,
-			 inode->i_ino, status);
+		dfprintk(PAGECACHE, "nfs_revalidate_inode: (%x/%Ld) refresh failed, error=%d\n",
+			 inode->i_dev, (long long)NFS_FILEID(inode), status);
 		goto out;
 	}
+	dfprintk(PAGECACHE, "NFS: (%x/%Ld) revalidation complete\n",
+		 inode->i_dev, (long long)NFS_FILEID(inode));
 
-	dfprintk(PAGECACHE, "NFS: %s/%s revalidation complete\n",
-		dentry->d_parent->d_name.name, dentry->d_name.name);
 out:
 	NFS_FLAGS(inode) &= ~NFS_INO_REVALIDATING;
 	wake_up(&inode->i_wait);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nfs/mount_clnt.c linux.19p18/fs/nfs/mount_clnt.c
--- linux.vanilla/fs/nfs/mount_clnt.c	Mon Dec 11 22:13:03 2000
+++ linux.19p18/fs/nfs/mount_clnt.c	Mon Feb 12 14:51:59 2001
@@ -33,23 +33,23 @@
  */
 
 static int			nfs_gen_mount(struct sockaddr_in *, char *,
-					      struct nfs_fh *, int);
+					      struct nfs3_fh *, int);
 static struct rpc_clnt *	mnt_create(char *, struct sockaddr_in *, int);
 extern struct rpc_program	mnt_program;
 
 struct mnt_fhstatus {
 	unsigned int		status;
-	struct nfs_fh *		fh;
+	struct nfs3_fh *	fh;
 };
 
 int
-nfs_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh)
+nfs_mount(struct sockaddr_in *addr, char *path, struct nfs3_fh *fh)
 {
 	return nfs_gen_mount(addr, path, fh, NFS_MNT_VERSION);
 }
 
 int
-nfs3_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh)
+nfs3_mount(struct sockaddr_in *addr, char *path, struct nfs3_fh *fh)
 {
 	return nfs_gen_mount(addr, path, fh, NFS_MNT3_VERSION);
 }
@@ -58,7 +58,7 @@
  * Obtain an NFS file handle for the given host and path
  */
 static int
-nfs_gen_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh, int version)
+nfs_gen_mount(struct sockaddr_in *addr, char *path, struct nfs3_fh *fh, int version)
 {
 	struct rpc_clnt		*mnt_clnt;
 	struct mnt_fhstatus	result = { 0, fh };
@@ -122,7 +122,7 @@
 static int
 xdr_decode_fhstatus(struct rpc_rqst *req, u32 *p, struct mnt_fhstatus *res)
 {
-	struct nfs_fh *fh = res->fh;
+	struct nfs3_fh	*fh = res->fh;
 
 	memset((void *)fh, 0, sizeof(*fh));
 	if ((res->status = ntohl(*p++)) == 0) {
@@ -135,7 +135,7 @@
 static int
 xdr_decode_fhstatus3(struct rpc_rqst *req, u32 *p, struct mnt_fhstatus *res)
 {
-	struct nfs_fh *fh = res->fh;
+	struct nfs3_fh	*fh = res->fh;
 
 	memset((void *)fh, 0, sizeof(*fh));
 	if ((res->status = ntohl(*p++)) == 0) {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nfs/nfs3proc.c linux.19p18/fs/nfs/nfs3proc.c
--- linux.vanilla/fs/nfs/nfs3proc.c	Mon Dec 11 22:13:03 2000
+++ linux.19p18/fs/nfs/nfs3proc.c	Mon Feb 12 14:51:59 2001
@@ -46,65 +46,67 @@
  * One function for each procedure in the NFS protocol.
  */
 static int
-nfs3_proc_getattr(struct dentry *dentry, struct nfs_fattr *fattr)
+nfs3_proc_getattr(struct inode *inode, struct nfs_fattr *fattr)
 {
 	int	status;
 
 	dprintk("NFS call  getattr\n");
 	fattr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_GETATTR,
-			  NFS_FH(dentry), fattr, 0);
+	status = rpc_call(NFS_CLIENT(inode), NFS3PROC_GETATTR,
+			  NFS_FH(inode), fattr, 0);
 	dprintk("NFS reply getattr\n");
 	return status;
 }
 
 static int
-nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
+nfs3_proc_setattr(struct inode *inode, struct nfs_fattr *fattr,
 			struct iattr *sattr)
 {
-	struct nfs3_sattrargs	arg = { NFS_FH(dentry), sattr, 0, 0 };
+	struct nfs3_sattrargs	arg = { NFS_FH(inode), sattr, 0, 0 };
 	int	status;
 
 	dprintk("NFS call  setattr\n");
 	fattr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_SETATTR, &arg, fattr, 0);
+	status = rpc_call(NFS_CLIENT(inode), NFS3PROC_SETATTR, &arg, fattr, 0);
 	dprintk("NFS reply setattr\n");
 	return status;
 }
 
 static int
-nfs3_proc_lookup(struct dentry *dir, struct nfs_fattr *dir_attr,
-			struct qstr *name,
+nfs3_proc_lookup(struct inode *dir, struct qstr *name,
 			struct nfs_fh *fhandle, struct nfs_fattr *fattr)
 {
+	struct nfs_fattr	dir_attr;
 	struct nfs3_diropargs	arg = { NFS_FH(dir), name->name, name->len };
-	struct nfs3_diropres	res = { dir_attr, fhandle, fattr };
+	struct nfs3_diropres	res = { &dir_attr, fhandle, fattr };
 	int			status;
 
 	dprintk("NFS call  lookup %s\n", name->name);
-	dir_attr->valid = 0;
+	dir_attr.valid = 0;
 	fattr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_LOOKUP, &arg, &res, 0);
+	status = rpc_call(NFS_CLIENT(dir), NFS3PROC_LOOKUP, &arg, &res, 0);
 	if (status >= 0 && !(fattr->valid & NFS_ATTR_FATTR))
-		status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_GETATTR,
+		status = rpc_call(NFS_CLIENT(dir), NFS3PROC_GETATTR,
 			 fhandle, fattr, 0);
 	dprintk("NFS reply lookup: %d\n", status);
+	nfs_refresh_inode(dir, &dir_attr);
 	return status;
 }
 
 static int
-nfs3_proc_access(struct dentry *dentry, int mode, struct nfs_fattr *fattr, int ruid)
+nfs3_proc_access(struct inode *inode, int mode, int ruid)
 {
-	struct nfs3_accessargs	arg = { NFS_FH(dentry), 0 };
-	struct nfs3_accessres	res = { fattr, 0 };
+	struct nfs_fattr	fattr;
+	struct nfs3_accessargs	arg = { NFS_FH(inode), 0 };
+	struct nfs3_accessres	res = { &fattr, 0 };
 	int	status, flags;
 
 	dprintk("NFS call  access\n");
-	fattr->valid = 0;
+	fattr.valid = 0;
 
 	if (mode & MAY_READ)
 		arg.access |= NFS3_ACCESS_READ;
-	if (S_ISDIR(dentry->d_inode->i_mode)) {
+	if (S_ISDIR(inode->i_mode)) {
 		if (mode & MAY_WRITE)
 			arg.access |= NFS3_ACCESS_MODIFY | NFS3_ACCESS_EXTEND | NFS3_ACCESS_DELETE;
 		if (mode & MAY_EXEC)
@@ -116,7 +118,7 @@
 			arg.access |= NFS3_ACCESS_EXECUTE;
 	}
 	flags = (ruid) ? RPC_CALL_REALUID : 0;
-	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_ACCESS, &arg, &res, flags);
+	status = rpc_call(NFS_CLIENT(inode), NFS3PROC_ACCESS, &arg, &res, flags);
 	dprintk("NFS reply access\n");
 
 	if (status == 0 && (arg.access & res.access) != arg.access)
@@ -125,28 +127,28 @@
 }
 
 static int
-nfs3_proc_readlink(struct dentry *dentry, struct nfs_fattr *fattr,
-			void *buffer, unsigned int buflen)
+nfs3_proc_readlink(struct inode *inode, void *buffer, unsigned int buflen)
 {
-	struct nfs3_readlinkargs args = { NFS_FH(dentry), buffer, buflen };
-	struct nfs3_readlinkres	res = { fattr, buffer, buflen };
+	struct nfs_fattr	fattr;
+	struct nfs3_readlinkargs args = { NFS_FH(inode), buffer, buflen };
+	struct nfs3_readlinkres	res = { &fattr, buffer, buflen };
 	int			status;
 
 	dprintk("NFS call  readlink\n");
-	fattr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_READLINK,
+	fattr.valid = 0;
+	status = rpc_call(NFS_CLIENT(inode), NFS3PROC_READLINK,
 					&args, &res, 0);
 	dprintk("NFS reply readlink: %d\n", status);
 	return status;
 }
 
 static int
-nfs3_proc_read(struct dentry *dentry, struct nfs_fattr *fattr,
-	       struct rpc_cred *cred, int flags,
+nfs3_proc_read(struct inode *inode, struct rpc_cred *cred,
+	       struct nfs_fattr *fattr, int flags,
 	       unsigned long offset, unsigned int count,
 	       void *buffer, int *eofp)
 {
-	struct nfs_readargs	arg = { NFS_FH(dentry), offset, count, 1,
+	struct nfs_readargs	arg = { NFS_FH(inode), offset, count, 1,
 					{{buffer, count}, {0,0}, {0,0}, {0,0},
 					 {0,0}, {0,0}, {0,0}, {0,0}} };
 	struct nfs_readres	res = { fattr, count, 0 };
@@ -155,19 +157,19 @@
 
 	dprintk("NFS call  read %d @ %ld\n", count, offset);
 	fattr->valid = 0;
-	status = rpc_call_sync(NFS_CLIENT(dentry->d_inode), &msg, flags);
+	status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags);
 	dprintk("NFS reply read: %d\n", status);
 	*eofp = res.eof;
 	return status;
 }
 
 static int
-nfs3_proc_write(struct dentry *dentry, struct nfs_fattr *fattr,
-		struct rpc_cred *cred, int flags,
+nfs3_proc_write(struct inode *inode, struct rpc_cred *cred,
+		struct nfs_fattr *fattr, int flags,
 		unsigned long offset, unsigned int count,
 		void *buffer, struct nfs_writeverf *verf)
 {
-	struct nfs_writeargs	arg = { NFS_FH(dentry), offset, count,
+	struct nfs_writeargs	arg = { NFS_FH(inode), offset, count,
 					NFS_FILE_SYNC, 1,
 					{{buffer, count}, {0,0}, {0,0}, {0,0},
 					 {0,0}, {0,0}, {0,0}, {0,0}} };
@@ -181,7 +183,7 @@
 		rpcflags |= NFS_RPC_SWAPFLAGS;
 	arg.stable = (flags & NFS_RW_SYNC) ? NFS_FILE_SYNC : NFS_UNSTABLE;
 
-	status = rpc_call_sync(NFS_CLIENT(dentry->d_inode), &msg, rpcflags);
+	status = rpc_call_sync(NFS_CLIENT(inode), &msg, rpcflags);
 
 	dprintk("NFS reply read: %d\n", status);
 	return status < 0? status : res.count;
@@ -192,17 +194,17 @@
  * For now, we don't implement O_EXCL.
  */
 static int
-nfs3_proc_create(struct dentry *dir, struct nfs_fattr *dir_attr,
-			struct qstr *name, struct iattr *sattr, int flags,
-			struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+nfs3_proc_create(struct inode *dir, struct qstr *name, struct iattr *sattr,
+		 int flags, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
 {
+	struct nfs_fattr	dir_attr;
 	struct nfs3_createargs	arg = { NFS_FH(dir), name->name, name->len,
 					sattr, 0, { 0, 0 } };
-	struct nfs3_diropres	res = { dir_attr, fhandle, fattr };
+	struct nfs3_diropres	res = { &dir_attr, fhandle, fattr };
 	int			status;
 
 	dprintk("NFS call  create %s\n", name->name);
-	dir_attr->valid = 0;
+	dir_attr.valid = 0;
 	fattr->valid = 0;
 
 	arg.createmode = NFS3_CREATE_UNCHECKED;
@@ -213,7 +215,8 @@
 	}
 
 again:
-	status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_CREATE, &arg, &res, 0);
+	status = rpc_call(NFS_CLIENT(dir), NFS3PROC_CREATE, &arg, &res, 0);
+	nfs_refresh_inode(dir, &dir_attr);
 
 	/* If the server doesn't support the exclusive creation semantics,
 	 * try again with simple 'guarded' mode. */
@@ -246,7 +249,7 @@
 		 * not sure this buys us anything (and I'd have
 		 * to revamp the NFSv3 XDR code) */
 		fattr->valid = 0;
-		status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_SETATTR,
+		status = rpc_call(NFS_CLIENT(dir), NFS3PROC_SETATTR,
 						&arg, fattr, 0);
 		dprintk("NFS reply setattr (post-create): %d\n", status);
 	}
@@ -255,16 +258,17 @@
 }
 
 static int
-nfs3_proc_remove(struct dentry *dir, struct nfs_fattr *dir_attr,
-				struct qstr *name)
+nfs3_proc_remove(struct inode *dir, struct qstr *name)
 {
+	struct nfs_fattr	dir_attr;
 	struct nfs3_diropargs	arg = { NFS_FH(dir), name->name, name->len };
-	struct rpc_message	msg = {NFS3PROC_REMOVE, &arg, dir_attr, NULL };
+	struct rpc_message	msg = {NFS3PROC_REMOVE, &arg, &dir_attr, NULL };
 	int			status;
 
 	dprintk("NFS call  remove %s\n", name->name);
-	dir_attr->valid = 0;
-	status = rpc_call_sync(NFS_CLIENT(dir->d_inode), &msg, 0);
+	dir_attr.valid = 0;
+	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+	nfs_refresh_inode(dir, &dir_attr);
 	dprintk("NFS reply remove: %d\n", status);
 	return status;
 }
@@ -281,7 +285,7 @@
 		return -ENOMEM;
 	memset(arg, 0, size);
 	res = (struct nfs_fattr*)(arg + 1);
-	arg->fh = NFS_FH(dir);
+	arg->fh = NFS_FH(dir->d_inode);
 	arg->name = name->name;
 	arg->len = name->len;
 	msg->rpc_proc = NFS3PROC_REMOVE;
@@ -303,91 +307,96 @@
 
 
 static int
-nfs3_proc_rename(struct dentry *old_dir, struct nfs_fattr *old_attr,
-			struct qstr *old_name,
-			struct dentry *new_dir, struct nfs_fattr *new_attr,
-			struct qstr *new_name)
+nfs3_proc_rename(struct inode *old_dir, struct qstr *old_name,
+			struct inode *new_dir, struct qstr *new_name)
 {
+	struct nfs_fattr	old_dir_attr, new_dir_attr;
 	struct nfs3_renameargs	arg = { NFS_FH(old_dir),
 					old_name->name, old_name->len,
 					NFS_FH(new_dir),
 					new_name->name, new_name->len };
-	struct nfs3_renameres	res = { old_attr, new_attr };
+	struct nfs3_renameres	res = { &old_dir_attr, &new_dir_attr };
 	int			status;
 
 	dprintk("NFS call  rename %s -> %s\n", old_name->name, new_name->name);
-	old_attr->valid = 0;
-	new_attr->valid = 0;
-	status = rpc_call(NFS_CLIENT(old_dir->d_inode), NFS3PROC_RENAME, &arg, &res, 0);
+	old_dir_attr.valid = 0;
+	new_dir_attr.valid = 0;
+	status = rpc_call(NFS_CLIENT(old_dir), NFS3PROC_RENAME, &arg, &res, 0);
+	nfs_refresh_inode(old_dir, &old_dir_attr);
+	nfs_refresh_inode(new_dir, &new_dir_attr);
 	dprintk("NFS reply rename: %d\n", status);
 	return status;
 }
 
 static int
-nfs3_proc_link(struct dentry *dentry, struct nfs_fattr *fattr,
-			struct dentry *dir, struct nfs_fattr *dir_attr,
-			struct qstr *name)
+nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
 {
-	struct nfs3_linkargs	arg = { NFS_FH(dentry), NFS_FH(dir),
+	struct nfs_fattr	dir_attr, fattr;
+	struct nfs3_linkargs	arg = { NFS_FH(inode), NFS_FH(dir),
 					name->name, name->len };
-	struct nfs3_linkres	res = { dir_attr, fattr };
+	struct nfs3_linkres	res = { &dir_attr, &fattr };
 	int			status;
 
 	dprintk("NFS call  link %s\n", name->name);
-	dir_attr->valid = 0;
-	fattr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_LINK, &arg, &res, 0);
+	dir_attr.valid = 0;
+	fattr.valid = 0;
+	status = rpc_call(NFS_CLIENT(inode), NFS3PROC_LINK, &arg, &res, 0);
+	nfs_refresh_inode(dir, &dir_attr);
+	nfs_refresh_inode(inode, &fattr);
 	dprintk("NFS reply link: %d\n", status);
 	return status;
 }
 
 static int
-nfs3_proc_symlink(struct dentry *dir, struct nfs_fattr *dir_attr,
-			struct qstr *name, struct qstr *path,
-			struct iattr *sattr,
-			struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+nfs3_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path,
+			struct iattr *sattr, struct nfs_fh *fhandle,
+			struct nfs_fattr *fattr)
 {
+	struct nfs_fattr	dir_attr;
 	struct nfs3_symlinkargs	arg = { NFS_FH(dir), name->name, name->len,
 					path->name, path->len, sattr };
-	struct nfs3_diropres	res = { dir_attr, fhandle, fattr };
+	struct nfs3_diropres	res = { &dir_attr, fhandle, fattr };
 	int			status;
 
 	dprintk("NFS call  symlink %s -> %s\n", name->name, path->name);
-	dir_attr->valid = 0;
+	dir_attr.valid = 0;
 	fattr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_SYMLINK, &arg, &res, 0);
+	status = rpc_call(NFS_CLIENT(dir), NFS3PROC_SYMLINK, &arg, &res, 0);
+	nfs_refresh_inode(dir, &dir_attr);
 	dprintk("NFS reply symlink: %d\n", status);
 	return status;
 }
 
 static int
-nfs3_proc_mkdir(struct dentry *dir, struct nfs_fattr *dir_attr,
-			struct qstr *name, struct iattr *sattr,
+nfs3_proc_mkdir(struct inode *dir, struct qstr *name, struct iattr *sattr,
 			struct nfs_fh *fhandle, struct nfs_fattr *fattr)
 {
+	struct nfs_fattr	dir_attr;
 	struct nfs3_createargs	arg = { NFS_FH(dir), name->name, name->len,
 					sattr, 0, { 0, 0 } };
-	struct nfs3_diropres	res = { dir_attr, fhandle, fattr };
+	struct nfs3_diropres	res = { &dir_attr, fhandle, fattr };
 	int			status;
 
 	dprintk("NFS call  mkdir %s\n", name->name);
-	dir_attr->valid = 0;
+	dir_attr.valid = 0;
 	fattr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_MKDIR, &arg, &res, 0);
+	status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKDIR, &arg, &res, 0);
+	nfs_refresh_inode(dir, &dir_attr);
 	dprintk("NFS reply mkdir: %d\n", status);
 	return status;
 }
 
 static int
-nfs3_proc_rmdir(struct dentry *dir, struct nfs_fattr *dir_attr,
-				struct qstr *name)
+nfs3_proc_rmdir(struct inode *dir, struct qstr *name)
 {
+	struct nfs_fattr	dir_attr;
 	struct nfs3_diropargs	arg = { NFS_FH(dir), name->name, name->len };
 	int			status;
 
 	dprintk("NFS call  rmdir %s\n", name->name);
-	dir_attr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_RMDIR, &arg, dir_attr, 0);
+	dir_attr.valid = 0;
+	status = rpc_call(NFS_CLIENT(dir), NFS3PROC_RMDIR, &arg, &dir_attr, 0);
+	nfs_refresh_inode(dir, &dir_attr);
 	dprintk("NFS reply rmdir: %d\n", status);
 	return status;
 }
@@ -402,14 +411,14 @@
  * readdirplus.
  */
 static int
-nfs3_proc_readdir(struct dentry *dir, struct nfs_fattr *dir_attr,
-		  struct rpc_cred *cred,
+nfs3_proc_readdir(struct inode *dir, struct rpc_cred *cred,
 		  u64 cookie, void *entry, unsigned int size, int plus)
 {
+	struct nfs_fattr	dir_attr;
 	struct nfs3_readdirargs	arg = { NFS_FH(dir), cookie, {0, 0}, 0, 0, 0 };
-	struct nfs3_readdirres	res = { dir_attr, 0, 0, 0, 0 };
+	struct nfs3_readdirres	res = { &dir_attr, 0, 0, 0, 0 };
 	struct rpc_message	msg = { NFS3PROC_READDIR, &arg, &res, cred };
-	u32			*verf = NFS_COOKIEVERF(dir->d_inode);
+	u32			*verf = NFS_COOKIEVERF(dir);
 	int			status;
 
 	arg.buffer  = entry;
@@ -428,20 +437,21 @@
 	dprintk("NFS call  readdir%s %d\n",
 			plus? "plus" : "", (unsigned int) cookie);
 
-	dir_attr->valid = 0;
-	status = rpc_call_sync(NFS_CLIENT(dir->d_inode), &msg, 0);
+	dir_attr.valid = 0;
+	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
+	nfs_refresh_inode(dir, &dir_attr);
 	dprintk("NFS reply readdir: %d\n", status);
 	return status;
 }
 
 static int
-nfs3_proc_mknod(struct dentry *dir, struct nfs_fattr *dir_attr,
-			struct qstr *name, struct iattr *sattr,
+nfs3_proc_mknod(struct inode *dir, struct qstr *name, struct iattr *sattr,
 			dev_t rdev, struct nfs_fh *fh, struct nfs_fattr *fattr)
 {
+	struct nfs_fattr	dir_attr;
 	struct nfs3_mknodargs	arg = { NFS_FH(dir), name->name, name->len, 0,
 					sattr, rdev };
-	struct nfs3_diropres	res = { dir_attr, fh, fattr };
+	struct nfs3_diropres	res = { &dir_attr, fh, fattr };
 	int			status;
 
 	switch (sattr->ia_mode & S_IFMT) {
@@ -453,9 +463,10 @@
 	}
 
 	dprintk("NFS call  mknod %s %x\n", name->name, rdev);
-	dir_attr->valid = 0;
+	dir_attr.valid = 0;
 	fattr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_MKNOD, &arg, &res, 0);
+	status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKNOD, &arg, &res, 0);
+	nfs_refresh_inode(dir, &dir_attr);
 	dprintk("NFS reply mknod: %d\n", status);
 	return status;
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nfs/proc.c linux.19p18/fs/nfs/proc.c
--- linux.vanilla/fs/nfs/proc.c	Mon Dec 11 22:13:03 2000
+++ linux.19p18/fs/nfs/proc.c	Mon Feb 12 14:51:59 2001
@@ -77,34 +77,34 @@
  * One function for each procedure in the NFS protocol.
  */
 static int
-nfs_proc_getattr(struct dentry *dentry, fattr *fattr)
+nfs_proc_getattr(struct inode *inode, fattr *fattr)
 {
 	int	status;
 
 	dprintk("NFS call  getattr\n");
 	fattr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_GETATTR,
-				NFS_FH(dentry), fattr, 0);
+	status = rpc_call(NFS_CLIENT(inode), NFSPROC_GETATTR,
+				NFS_FH(inode), fattr, 0);
 	dprintk("NFS reply getattr\n");
 	return status;
 }
 
 static int
-nfs_proc_setattr(struct dentry *dentry, fattr *fattr,
+nfs_proc_setattr(struct inode *inode, fattr *fattr,
 				struct iattr *sattr)
 {
-	struct nfs_sattrargs	arg = { NFS_FH(dentry), sattr };
+	struct nfs_sattrargs	arg = { NFS_FH(inode), sattr };
 	int	status;
 
 	dprintk("NFS call  setattr\n");
 	fattr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_SETATTR, &arg, fattr, 0);
+	status = rpc_call(NFS_CLIENT(inode), NFSPROC_SETATTR, &arg, fattr, 0);
 	dprintk("NFS reply setattr\n");
 	return status;
 }
 
 static int
-nfs_proc_lookup(struct dentry *dir, fattr *dir_attr, qstr *name,
+nfs_proc_lookup(struct inode *dir, qstr *name,
 		struct nfs_fh *fhandle, fattr *fattr)
 {
 	struct nfs_diropargs	arg = { NFS_FH(dir), name->name, name->len };
@@ -112,36 +112,32 @@
 	int			status;
 
 	dprintk("NFS call  lookup %s\n", name->name);
-	dir_attr->valid = 0;
 	fattr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_LOOKUP, &arg, &res, 0);
+	status = rpc_call(NFS_CLIENT(dir), NFSPROC_LOOKUP, &arg, &res, 0);
 	dprintk("NFS reply lookup: %d\n", status);
 	return status;
 }
 
 static int
-nfs_proc_readlink(struct dentry *dentry, fattr *fattr,
-			void *buffer, unsigned int bufsiz)
+nfs_proc_readlink(struct inode *inode, void *buffer, unsigned int bufsiz)
 {
-	struct nfs_readlinkargs	args = { NFS_FH(dentry), buffer, bufsiz };
+	struct nfs_readlinkargs	args = { NFS_FH(inode), buffer, bufsiz };
 	struct nfs_readlinkres	res = { buffer, bufsiz };
 	int			status;
 
 	dprintk("NFS call  readlink\n");
-	fattr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_READLINK,
+	status = rpc_call(NFS_CLIENT(inode), NFSPROC_READLINK,
 					&args, &res, 0);
 	dprintk("NFS reply readlink: %d\n", status);
 	return status;
 }
 
 static int
-nfs_proc_read(struct dentry *dentry, fattr *fattr,
-	      struct rpc_cred *cred, int flags,
-	      unsigned long offset, unsigned int count,
+nfs_proc_read(struct inode *inode, struct rpc_cred *cred, fattr *fattr,
+	      int flags, unsigned long offset, unsigned int count,
 	      void *buffer, int *eofp)
 {
-	struct nfs_readargs	arg = { NFS_FH(dentry), offset, count, 1,
+	struct nfs_readargs	arg = { NFS_FH(inode), offset, count, 1,
 				       {{ buffer, count }, {0,0}, {0,0}, {0,0},
 					{0,0}, {0,0}, {0,0}, {0,0}} };
 	struct nfs_readres	res = { fattr, count, 0};
@@ -150,7 +146,7 @@
 
 	dprintk("NFS call  read %d @ %ld\n", count, offset);
 	fattr->valid = 0;
-	status = rpc_call_sync(NFS_CLIENT(dentry->d_inode), &msg, flags);
+	status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags);
 
 	dprintk("NFS reply read: %d\n", status);
 	*eofp = res.eof;
@@ -158,12 +154,11 @@
 }
 
 static int
-nfs_proc_write(struct dentry *dentry, fattr *fattr,
-	       struct rpc_cred *cred, int how,
-	       unsigned long offset, unsigned int count,
+nfs_proc_write(struct inode *inode, struct rpc_cred *cred, fattr *fattr,
+	       int how, unsigned long offset, unsigned int count,
 	       void *buffer, struct nfs_writeverf *verf)
 {
-	struct nfs_writeargs	arg = {NFS_FH(dentry), offset, count,
+	struct nfs_writeargs	arg = {NFS_FH(inode), offset, count,
 					NFS_FILE_SYNC, 1,
 					{{buffer, count}, {0,0}, {0,0}, {0,0},
 					 {0,0}, {0,0}, {0,0}, {0,0}}};
@@ -175,7 +170,7 @@
 	fattr->valid = 0;
 	if (how & NFS_RW_SWAP)
 		flags |= NFS_RPC_SWAPFLAGS;
-	status = rpc_call_sync(NFS_CLIENT(dentry->d_inode), &msg, flags);
+	status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags);
 
 	dprintk("NFS reply write: %d\n", status);
 	verf->committed = NFS_FILE_SYNC;      /* NFSv2 always syncs data */
@@ -183,8 +178,7 @@
 }
 
 static int
-nfs_proc_create(struct dentry *dir, fattr *dir_attr,
-		qstr *name, struct iattr *sattr, int flags,
+nfs_proc_create(struct inode *dir, qstr *name, struct iattr *sattr, int flags,
 		struct nfs_fh *fhandle, fattr *fattr)
 {
 	struct nfs_createargs	arg = { NFS_FH(dir), name->name,
@@ -192,10 +186,9 @@
 	struct nfs_diropok	res = { fhandle, fattr };
 	int			status;
 
-	dir_attr->valid = 0;
 	fattr->valid = 0;
 	dprintk("NFS call  create %s\n", name->name);
-	status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_CREATE, &arg, &res, 0);
+	status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0);
 	dprintk("NFS reply create: %d\n", status);
 	return status;
 }
@@ -204,8 +197,7 @@
  * In NFSv2, mknod is grafted onto the create call.
  */
 static int
-nfs_proc_mknod(struct dentry *dir, fattr *dir_attr,
-			qstr *name, struct iattr *sattr, dev_t rdev,
+nfs_proc_mknod(struct inode *dir, qstr *name, struct iattr *sattr, dev_t rdev,
 			struct nfs_fh *fhandle, fattr *fattr)
 {
 	struct nfs_createargs	arg = { NFS_FH(dir), name->name,
@@ -224,30 +216,27 @@
 		sattr->ia_size   = rdev;	/* get out your barf bag */
 	}
 
-	dir_attr->valid = 0;
 	fattr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_CREATE, &arg, &res, 0);
+	status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0);
 
 	if (status == -EINVAL && S_ISFIFO(mode)) {
 		sattr->ia_mode = mode;
-		dir_attr->valid = 0;
 		fattr->valid = 0;
-		status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_CREATE, &arg, &res, 0);
+		status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0);
 	}
 	dprintk("NFS reply mknod: %d\n", status);
 	return status;
 }
   
 static int
-nfs_proc_remove(struct dentry *dir, fattr *dir_attr, qstr *name)
+nfs_proc_remove(struct inode *dir, qstr *name)
 {
 	struct nfs_diropargs	arg = { NFS_FH(dir), name->name, name->len };
 	struct rpc_message	msg = { NFSPROC_REMOVE, &arg, NULL, NULL };
 	int			status;
 
-	dir_attr->valid = 0;
 	dprintk("NFS call  remove %s\n", name->name);
-	status = rpc_call_sync(NFS_CLIENT(dir->d_inode), &msg, 0);
+	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
 
 	dprintk("NFS reply remove: %d\n", status);
 	return status;
@@ -262,7 +251,7 @@
 	if (!arg)
 		return -ENOMEM;
 	memset(arg, 0, sizeof(*arg));
-	arg->fh = NFS_FH(dir);
+	arg->fh = NFS_FH(dir->d_inode);
 	arg->name = name->name;
 	arg->len = name->len;
 	msg->rpc_proc = NFSPROC_REMOVE;
@@ -280,8 +269,8 @@
 }
 
 static int
-nfs_proc_rename(struct dentry *old_dir, fattr *old_attr, qstr *old_name,
-		struct dentry *new_dir, fattr *new_attr, qstr *new_name)
+nfs_proc_rename(struct inode *old_dir, qstr *old_name,
+		struct inode *new_dir, qstr *new_name)
 {
 	struct nfs_renameargs	arg = { NFS_FH(old_dir), old_name->name,
 					old_name->len,
@@ -290,32 +279,26 @@
 	int			status;
 
 	dprintk("NFS call  rename %s -> %s\n", old_name->name, new_name->name);
-	old_attr->valid = 0;
-	new_attr->valid = 0;
-	status = rpc_call(NFS_CLIENT(old_dir->d_inode), NFSPROC_RENAME, &arg, NULL, 0);
+	status = rpc_call(NFS_CLIENT(old_dir), NFSPROC_RENAME, &arg, NULL, 0);
 	dprintk("NFS reply rename: %d\n", status);
 	return status;
 }
 
 static int
-nfs_proc_link(struct dentry *dentry, fattr *attr,
-	      struct dentry *dir, fattr *dir_attr, qstr *name)
+nfs_proc_link(struct inode *inode, struct inode *dir, qstr *name)
 {
-	struct nfs_linkargs	arg = { NFS_FH(dentry), NFS_FH(dir),
+	struct nfs_linkargs	arg = { NFS_FH(inode), NFS_FH(dir),
 					name->name, name->len };
 	int			status;
 
 	dprintk("NFS call  link %s\n", name->name);
-	dir_attr->valid = 0;
-	attr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_LINK, &arg, NULL, 0);
+	status = rpc_call(NFS_CLIENT(inode), NFSPROC_LINK, &arg, NULL, 0);
 	dprintk("NFS reply link: %d\n", status);
 	return status;
 }
 
 static int
-nfs_proc_symlink(struct dentry *dir, fattr *dir_attr, qstr *name,
-		 qstr *path, struct iattr *sattr,
+nfs_proc_symlink(struct inode *dir, qstr *name, qstr *path, struct iattr *sattr,
 		 struct nfs_fh *sym_fh, fattr *sym_attr)
 {
 	struct nfs_symlinkargs	arg = { NFS_FH(dir), name->name, name->len,
@@ -323,16 +306,14 @@
 	int			status;
 
 	dprintk("NFS call  symlink %s -> %s\n", name->name, path->name);
-	dir_attr->valid = 0;
 	sym_attr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_SYMLINK, &arg, NULL, 0);
+	status = rpc_call(NFS_CLIENT(dir), NFSPROC_SYMLINK, &arg, NULL, 0);
 	dprintk("NFS reply symlink: %d\n", status);
 	return status;
 }
 
 static int
-nfs_proc_mkdir(struct dentry *dir, fattr *dir_attr, qstr *name,
-	       struct iattr *sattr,
+nfs_proc_mkdir(struct inode *dir, qstr *name, struct iattr *sattr,
 	       struct nfs_fh *fhandle, fattr *fattr)
 {
 	struct nfs_createargs	arg = { NFS_FH(dir), name->name, name->len,
@@ -341,22 +322,20 @@
 	int			status;
 
 	dprintk("NFS call  mkdir %s\n", name->name);
-	dir_attr->valid = 0;
 	fattr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_MKDIR, &arg, &res, 0);
+	status = rpc_call(NFS_CLIENT(dir), NFSPROC_MKDIR, &arg, &res, 0);
 	dprintk("NFS reply mkdir: %d\n", status);
 	return status;
 }
 
 static int
-nfs_proc_rmdir(struct dentry *dir, fattr *dir_attr, qstr *name)
+nfs_proc_rmdir(struct inode *dir, qstr *name)
 {
 	struct nfs_diropargs	arg = { NFS_FH(dir), name->name, name->len };
 	int			status;
 
 	dprintk("NFS call  rmdir %s\n", name->name);
-	dir_attr->valid = 0;
-	status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_RMDIR, &arg, NULL, 0);
+	status = rpc_call(NFS_CLIENT(dir), NFSPROC_RMDIR, &arg, NULL, 0);
 	dprintk("NFS reply rmdir: %d\n", status);
 	return status;
 }
@@ -369,8 +348,7 @@
  * from nfs_readdir by calling the decode_entry function directly.
  */
 static int
-nfs_proc_readdir(struct dentry *dir, fattr *dir_attr,
-		 struct rpc_cred *cred,
+nfs_proc_readdir(struct inode *dir, struct rpc_cred *cred,
 		 __u64 cookie, void *entry, unsigned int size, int plus)
 {
 	struct nfs_readdirargs	arg;
@@ -378,7 +356,6 @@
 	struct rpc_message	msg = { NFSPROC_READDIR, &arg, &res, cred };
 	int			status;
 
-	dir_attr->valid = 0;
 	arg.fh = NFS_FH(dir);
 	arg.cookie = cookie;
 	arg.buffer = entry;
@@ -386,9 +363,8 @@
 	res.buffer = entry;
 	res.bufsiz = size;
 
-	dir_attr->valid = 0;
 	dprintk("NFS call  readdir %d\n", (unsigned int)cookie);
-	status = rpc_call_sync(NFS_CLIENT(dir->d_inode), &msg, 0);
+	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
 
 	dprintk("NFS reply readdir: %d\n", status);
 	return status;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nfs/read.c linux.19p18/fs/nfs/read.c
--- linux.vanilla/fs/nfs/read.c	Mon Dec 11 22:13:03 2000
+++ linux.19p18/fs/nfs/read.c	Mon Feb 12 14:51:59 2001
@@ -42,7 +42,7 @@
 
 struct nfs_read_data {
 	struct rpc_task		task;
-	struct dentry		*dentry;
+	struct inode		*inode;
 	struct rpc_cred		*cred;
 	struct nfs_readargs	args;	/* XDR argument struct */
 	struct nfs_readres	res;	/* ... and result struct */
@@ -87,11 +87,9 @@
  * Read a page synchronously.
  */
 static int
-nfs_readpage_sync(struct file *file, struct page *page)
+nfs_readpage_sync(struct file *file, struct inode *inode, struct page *page)
 {
-	struct dentry	*dentry = file->f_dentry;
-	struct inode	*inode = dentry->d_inode;
-	struct rpc_cred	*cred = nfs_file_cred(file);
+	struct rpc_cred	*cred = NULL;
 	struct nfs_fattr fattr;
 	unsigned long	offset = nfs_page_offset(page);
 	char		*buffer = (char *) page_address(page);
@@ -104,19 +102,23 @@
 		flags |= NFS_RPC_SWAPFLAGS;
 
 	dprintk("NFS: nfs_readpage_sync(%p)\n", page);
+
+	if (file)
+		cred = nfs_file_cred(file);
+
 	clear_bit(PG_error, &page->flags);
 
 	do {
 		if ((chunk = rsize) > count)
 			chunk = count;
 
-		dprintk("NFS: nfs_proc_read(%s, (%s/%s), %ld, %d, %p)\n",
+		dprintk("NFS: nfs_proc_read(%s, (%x/%Ld), %ld, %d, %p)\n",
 			NFS_SERVER(inode)->hostname,
-			dentry->d_parent->d_name.name, dentry->d_name.name,
+			inode->i_dev, (long long)NFS_FILEID(inode),
 			offset, chunk, buffer);
 
-		result = NFS_CALL(read, inode, (dentry, &fattr, cred, flags,
-						offset, chunk, buffer, &eof));
+		result = NFS_PROTO(inode)->read(inode, cred, &fattr, flags,
+						offset, chunk, buffer, &eof);
 		nfs_refresh_inode(inode, &fattr);
 
 		/*
@@ -180,7 +182,7 @@
 static inline void
 nfs_mark_request_read(struct nfs_page *req)
 {
-	struct inode *inode = req->wb_dentry->d_inode;
+	struct inode *inode = req->wb_inode;
 
 	if (list_empty(&req->wb_list)) {
 		nfs_list_add_request(req, &inode->u.nfs_i.read);
@@ -190,9 +192,8 @@
 }
 
 static int
-nfs_readpage_async(struct file *file, struct page *page)
+nfs_readpage_async(struct file *file, struct inode *inode, struct page *page)
 {
-	struct inode	*inode = file->f_dentry->d_inode;
 	struct nfs_page	*req, *new = NULL;
 	int		result;
 
@@ -222,7 +223,7 @@
 		}
 
 		result = -ENOMEM;
-		new = nfs_create_request(file, page, 0, PAGE_CACHE_SIZE);
+		new = nfs_create_request(file, inode, page, 0, PAGE_CACHE_SIZE);
 		if (!new)
 			break;
 	}
@@ -258,9 +259,9 @@
 		data->args.nriov++;
 	}
 	req = nfs_list_entry(data->pages.next);
-	data->dentry	  = req->wb_dentry;
+	data->inode	  = req->wb_inode;
 	data->cred	  = req->wb_cred;
-	data->args.fh     = NFS_FH(req->wb_dentry);
+	data->args.fh     = NFS_FH(req->wb_inode);
 	data->args.offset = nfs_page_offset(req->wb_page) + req->wb_offset;
 	data->args.count  = count;
 	data->res.fattr   = &data->fattr;
@@ -286,9 +287,8 @@
 }
 
 static int
-nfs_pagein_one(struct list_head *head, struct dentry *dentry)
+nfs_pagein_one(struct list_head *head, struct inode *inode)
 {
-	struct inode		*inode = dentry->d_inode;
 	struct rpc_task		*task;
 	struct rpc_clnt		*clnt = NFS_CLIENT(inode);
 	struct nfs_read_data	*data;
@@ -322,9 +322,9 @@
 	msg.rpc_cred = data->cred;
 
 	/* Start the async call */
-	dprintk("NFS: %4d initiated read call (req %s/%s count %d nriov %d.\n",
+	dprintk("NFS: %4d initiated read call (req %x/%Ld count %d nriov %d.\n",
 		task->tk_pid,
-		dentry->d_parent->d_name.name, dentry->d_name.name,
+		inode->i_dev, (long long)NFS_FILEID(inode),
 		data->args.count, data->args.nriov);
 
 	rpc_clnt_sigmask(clnt, &oldset);
@@ -349,7 +349,7 @@
 	while (!list_empty(head)) {
 		pages += nfs_coalesce_requests(head, &one_request, rpages);
 		req = nfs_list_entry(one_request.next);
-		error = nfs_pagein_one(&one_request, req->wb_dentry);
+		error = nfs_pagein_one(&one_request, req->wb_inode);
 		if (error < 0)
 			break;
 	}
@@ -419,8 +419,7 @@
 nfs_readpage_result(struct rpc_task *task)
 {
 	struct nfs_read_data	*data = (struct nfs_read_data *) task->tk_calldata;
-	struct dentry		*dentry = data->dentry;
-	struct inode		*inode = dentry->d_inode;
+	struct inode		*inode = data->inode;
 	int			count = data->res.count;
 
 	dprintk("NFS: %4d nfs_readpage_result, (status %d)\n",
@@ -440,9 +439,9 @@
 			set_bit(PG_error, &page->flags);
 		nfs_unlock_page(page);
 
-		dprintk("NFS: read (%s/%s %d@%ld)\n",
-                        req->wb_dentry->d_parent->d_name.name,
-                        req->wb_dentry->d_name.name,
+		dprintk("NFS: read (%x/%Ld %d@%ld)\n",
+			req->wb_inode->i_dev,
+			(long long)NFS_FILEID(req->wb_inode),
                         req->wb_bytes,
                         (nfs_page_offset(page) + req->wb_offset));
 		nfs_unlock_request(req);
@@ -465,16 +464,19 @@
 int
 nfs_readpage(struct file *file, struct page *page)
 {
-	struct dentry *dentry = file->f_dentry;
-	struct inode *inode = dentry->d_inode;
-	int		error = 0,
-			rsize = NFS_SERVER(inode)->rsize;
+	struct inode *inode;
+	int		error = 0;
 
 	while (!nfs_lock_page(page))
 		wait_on_page(page);
 
-	dprintk("NFS: nfs_readpage (%p %d@%ld)\n",
-		page, rsize, page->offset);
+	if (!file)
+		inode = page->inode;
+	else
+		inode = file->f_dentry->d_inode;
+
+	dprintk("NFS: nfs_readpage (%p %ld@%lu)\n",
+		page, PAGE_CACHE_SIZE, page->offset);
 
 	/*
 	 * Try to flush any pending writes to the file
@@ -484,13 +486,13 @@
 		goto out_unlock;
 
 	error = -1;
-	if (!IS_SWAPFILE(inode) && !PageError(page) && rsize >= PAGE_CACHE_SIZE)
-		error = nfs_readpage_async(file, page);
+	if (!PageError(page) && NFS_SERVER(inode)->rsize >= PAGE_CACHE_SIZE)
+		error = nfs_readpage_async(file, inode, page);
 
 	if (error >= 0)
 		goto out;
 
-	error = nfs_readpage_sync(file, page);
+	error = nfs_readpage_sync(file, inode, page);
 	if (error < 0 && IS_SWAPFILE(inode))
 		printk(KERN_ERR "Aiee.. nfs swap-in of page failed!\n");
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nfs/symlink.c linux.19p18/fs/nfs/symlink.c
--- linux.vanilla/fs/nfs/symlink.c	Mon Dec 11 22:13:03 2000
+++ linux.19p18/fs/nfs/symlink.c	Mon Feb 12 14:51:59 2001
@@ -57,19 +57,16 @@
 /* Symlink caching in the page cache is even more simplistic
  * and straight-forward than readdir caching.
  */
-static int nfs_symlink_filler(struct dentry *dentry, struct page *page)
+static int nfs_symlink_filler(struct inode *inode, struct page *page)
 {
-	struct inode *inode = dentry->d_inode;
-	struct nfs_fattr fattr;
 	void * buffer = (void *)page_address(page);
 	unsigned int error;
 
 	/* We place the length at the beginning of the page,
 	 * in client byte order, followed by the string.
 	 */
-	error = NFS_CALL(readlink, inode, (dentry, &fattr, buffer,
-					   PAGE_CACHE_SIZE-sizeof(u32)-4));
-	nfs_refresh_inode(inode, &fattr);
+	error = NFS_PROTO(inode)->readlink(inode, buffer,
+					   PAGE_CACHE_SIZE-sizeof(u32)-4);
 	if (error < 0)
 		goto error;
 	flush_dcache_page(page_address(page)); /* Is this correct? */
@@ -90,7 +87,7 @@
 
 	/* Caller revalidated the directory inode already. */
 	page = read_cache_page(inode, 0,
-				(filler_t *)nfs_symlink_filler, dentry);
+				(filler_t *)nfs_symlink_filler, inode);
 	if (IS_ERR(page))
 		goto read_failed;
 
@@ -115,7 +112,7 @@
 
 	/* Caller revalidated the directory inode already. */
 	page = read_cache_page(inode, 0,
-				(filler_t *)nfs_symlink_filler, dentry);
+				(filler_t *)nfs_symlink_filler, inode);
 	if (IS_ERR(page))
 		goto read_failed;
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nfs/write.c linux.19p18/fs/nfs/write.c
--- linux.vanilla/fs/nfs/write.c	Mon Dec 11 22:13:03 2000
+++ linux.19p18/fs/nfs/write.c	Mon Feb 12 14:51:59 2001
@@ -66,7 +66,7 @@
  */
 struct nfs_write_data {
 	struct rpc_task		task;
-	struct dentry		*dentry;
+	struct inode		*inode;
 	struct rpc_cred		*cred;
 	struct nfs_writeargs	args;		/* argument struct */
 	struct nfs_writeres	res;		/* result struct */
@@ -143,20 +143,21 @@
  * Offset is the data offset within the page.
  */
 static int
-nfs_writepage_sync(struct file *file, struct page *page,
+nfs_writepage_sync(struct file *file, struct inode *inode, struct page *page,
 		   unsigned long offset, unsigned int count)
 {
-	struct dentry	*dentry = file->f_dentry;
-	struct inode	*inode = dentry->d_inode;
-	struct rpc_cred	*cred = nfs_file_cred(file);
+	struct rpc_cred	*cred = NULL;
 	unsigned int	wsize = NFS_SERVER(inode)->wsize;
 	int		result, refresh = 0, written = 0, flags;
 	u8		*buffer;
 	struct nfs_fattr fattr;
 	struct nfs_writeverf verifier;
 
-	dprintk("NFS:      nfs_writepage_sync(%s/%s %d@%ld)\n",
-		dentry->d_parent->d_name.name, dentry->d_name.name,
+	if (file)
+		cred = nfs_file_cred(file);
+
+	dprintk("NFS:      nfs_writepage_sync(%x/%Ld %d@%ld)\n",
+		inode->i_dev, (long long)NFS_FILEID(inode),
 		count, nfs_page_offset(page) + offset);
 
 	buffer = (u8 *) page_address(page) + offset;
@@ -168,7 +169,7 @@
 		if (count < wsize && !IS_SWAPFILE(inode))
 			wsize = count;
 
-		result = NFS_PROTO(inode)->write(dentry, &fattr, cred, flags,
+		result = NFS_PROTO(inode)->write(inode, cred, &fattr, flags,
 						 offset, wsize, buffer,
 						 &verifier);
 		nfs_write_attributes(inode, &fattr);
@@ -205,14 +206,18 @@
 int
 nfs_writepage(struct file * file, struct page *page)
 {
-	struct inode *inode = file->f_dentry->d_inode;
+	struct inode *inode;
 	unsigned offset = PAGE_CACHE_SIZE;
 
+	if (!file)
+		inode = page->inode;
+	else
+		inode = file->f_dentry->d_inode;
 	if (page->offset >= inode->i_size)
 		return -EIO;
 	if (page->offset + offset > inode->i_size)
 		offset = inode->i_size & (PAGE_CACHE_SIZE-1);
-	return nfs_writepage_sync(file, page, 0, offset);
+	return nfs_writepage_sync(file, inode, page, 0, offset);
 }
 
 /*
@@ -252,6 +257,8 @@
 		return;
 	if (!NFS_WBACK_BUSY(req))
 		printk(KERN_ERR "NFS: unlocked request attempted hashed!\n");
+	if (list_empty(&inode->u.nfs_i.writeback))
+		inode->i_count++;
 	inode->u.nfs_i.npages++;
 	list_add(&req->wb_hash, &inode->u.nfs_i.writeback);
 	req->wb_count++;
@@ -269,12 +276,14 @@
 
 	if (!NFS_WBACK_BUSY(req))
 		printk(KERN_ERR "NFS: unlocked request attempted unhashed!\n");
-	inode = req->wb_dentry->d_inode;
+	inode = req->wb_inode;
 	list_del(&req->wb_hash);
 	INIT_LIST_HEAD(&req->wb_hash);
 	inode->u.nfs_i.npages--;
 	if ((inode->u.nfs_i.npages == 0) != list_empty(&inode->u.nfs_i.writeback))
 		printk(KERN_ERR "NFS: desynchronized value of nfs_i.npages.\n");
+	if (list_empty(&inode->u.nfs_i.writeback))
+		iput(inode);
 	if (!nfs_have_writebacks(inode) && !nfs_have_read(inode))
 		inode_remove_flushd(inode);
 	nfs_release_request(req);
@@ -354,7 +363,7 @@
 static inline void
 nfs_mark_request_dirty(struct nfs_page *req)
 {
-	struct inode *inode = req->wb_dentry->d_inode;
+	struct inode *inode = req->wb_inode;
 
 	if (list_empty(&req->wb_list)) {
 		nfs_list_add_request(req, &inode->u.nfs_i.dirty);
@@ -369,7 +378,7 @@
 static inline int
 nfs_dirty_request(struct nfs_page *req)
 {
-	struct inode *inode = req->wb_dentry->d_inode;
+	struct inode *inode = req->wb_inode;
 	return !list_empty(&req->wb_list) && req->wb_list_head == &inode->u.nfs_i.dirty;
 }
 
@@ -380,7 +389,7 @@
 static inline void
 nfs_mark_request_commit(struct nfs_page *req)
 {
-	struct inode *inode = req->wb_dentry->d_inode;
+	struct inode *inode = req->wb_inode;
 
 	if (list_empty(&req->wb_list)) {
 		nfs_list_add_request(req, &inode->u.nfs_i.commit);
@@ -396,11 +405,10 @@
  * two different requests for the same page, and avoids possible deadlock
  * when we reach the hard limit on the number of dirty pages.
  */
-struct nfs_page *nfs_create_request(struct file *file, struct page *page,
+struct nfs_page *nfs_create_request(struct file *file, struct inode *inode,
+				    struct page *page,
 				    unsigned int offset, unsigned int count)
 {
-	struct dentry		*dentry = file->f_dentry;
-	struct inode		*inode = dentry->d_inode;
 	struct nfs_reqlist	*cache = NFS_REQUESTLIST(inode);
 	struct nfs_page		*req = NULL;
 	long			timeout;
@@ -452,9 +460,12 @@
 	req->wb_offset  = offset;
 	req->wb_bytes   = count;
 	req->wb_file    = file;
-	file->f_count++;
-	req->wb_dentry	= dentry;
-	req->wb_cred	= nfs_file_cred(file);
+	if (file) {
+		file->f_count++;
+		req->wb_cred	= nfs_file_cred(file);
+	} else
+		req->wb_cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
+	req->wb_inode	= inode;
 	req->wb_count   = 1;
 
 	/* register request's existence */
@@ -471,7 +482,7 @@
 void
 nfs_release_request(struct nfs_page *req)
 {
-	struct inode		*inode = req->wb_dentry->d_inode;
+	struct inode		*inode = req->wb_inode;
 	struct nfs_reqlist	*cache = NFS_REQUESTLIST(inode);
 	struct page		*page = req->wb_page;
 
@@ -489,7 +500,10 @@
 	if (NFS_WBACK_BUSY(req))
 		printk(KERN_ERR "NFS: Request released while still locked!\n");
 
-	fput(req->wb_file);
+	if (req->wb_file)
+		fput(req->wb_file);
+	else
+		rpcauth_releasecred(NFS_CLIENT(inode)->cl_auth, req->wb_cred);
 	page_cache_release(page);
 	nfs_page_free(req);
 	/* wake up anyone waiting to allocate a request */
@@ -506,7 +520,7 @@
 static int
 nfs_wait_on_request(struct nfs_page *req)
 {
-	struct inode	*inode = req->wb_dentry->d_inode;
+	struct inode	*inode = req->wb_inode;
         struct rpc_clnt	*clnt = NFS_CLIENT(inode);
         int retval;
 
@@ -716,10 +730,9 @@
  * Note: Should always be called with the Page Lock held!
  */
 static struct nfs_page *
-nfs_update_request(struct file* file, struct page *page,
+nfs_update_request(struct file* file, struct inode *inode, struct page *page,
 		   unsigned int offset, unsigned int bytes)
 {
-	struct inode		*inode = file->f_dentry->d_inode;
 	struct nfs_page		*req, *new = NULL;
 	unsigned long		rqend, end;
 
@@ -754,7 +767,7 @@
 		 */
 		if (inode->u.nfs_i.npages >= MAX_REQUEST_SOFT)
 			nfs_wb_file(inode, file);
-		new = nfs_create_request(file, page, offset, bytes);
+		new = nfs_create_request(file, inode, page, offset, bytes);
 		if (!new)
 			return ERR_PTR(-ENOMEM);
 		/* If the region is locked, adjust the timeout */
@@ -891,7 +904,7 @@
 	 * page synchronously.
 	 */
 	if (NFS_SERVER(inode)->wsize < PAGE_CACHE_SIZE)
-		return nfs_writepage_sync(file, page, offset, count);
+		return nfs_writepage_sync(file, inode, page, offset, count);
 
         /*
          * Try to find an NFS request corresponding to this page
@@ -900,7 +913,7 @@
 	 * it out now.
          */
 	do {
-		req = nfs_update_request(file, page, offset, count);
+		req = nfs_update_request(file, inode, page, offset, count);
 		if (IS_ERR(req))
 			status = PTR_ERR(req);
 		if (status != -EBUSY)
@@ -967,9 +980,9 @@
 		data->args.nriov++;
 	}
 	req = nfs_list_entry(data->pages.next);
-	data->dentry = req->wb_dentry;
+	data->inode = req->wb_inode;
 	data->cred = req->wb_cred;
-	data->args.fh     = NFS_FH(req->wb_dentry);
+	data->args.fh     = NFS_FH(req->wb_inode);
 	data->args.offset = nfs_page_offset(req->wb_page) + req->wb_offset;
 	data->args.count  = count;
 	data->res.fattr   = &data->fattr;
@@ -987,9 +1000,8 @@
  * that has been written but not committed.
  */
 static int
-nfs_flush_one(struct list_head *head, struct dentry *dentry, int how)
+nfs_flush_one(struct list_head *head, struct inode *inode, int how)
 {
-	struct inode            *inode = dentry->d_inode;
 	struct rpc_clnt 	*clnt = NFS_CLIENT(inode);
 	struct nfs_write_data	*data;
 	struct rpc_task		*task;
@@ -1033,10 +1045,10 @@
 	msg.rpc_resp = &data->res;
 	msg.rpc_cred = data->cred;
 
-	dprintk("NFS: %4d initiated write call (req %s/%s count %d nriov %d)\n",
+	dprintk("NFS: %4d initiated write call (req %x/%Ld count %d nriov %d)\n",
 		task->tk_pid, 
-		dentry->d_parent->d_name.name,
-		dentry->d_name.name,
+		inode->i_dev,
+		(long long)NFS_FILEID(inode),
 		data->args.count, data->args.nriov);
 
 	rpc_clnt_sigmask(clnt, &oldset);
@@ -1066,7 +1078,7 @@
 	while (!list_empty(head)) {
 		pages += nfs_coalesce_requests(head, &one_request, wpages);
 		req = nfs_list_entry(one_request.next);
-		error = nfs_flush_one(&one_request, req->wb_dentry, how);
+		error = nfs_flush_one(&one_request, req->wb_inode, how);
 		if (error < 0)
 			break;
 	}
@@ -1092,8 +1104,7 @@
 	struct nfs_write_data	*data = (struct nfs_write_data *) task->tk_calldata;
 	struct nfs_writeargs	*argp = &data->args;
 	struct nfs_writeres	*resp = &data->res;
-	struct dentry		*dentry = data->dentry;
-	struct inode		*inode = dentry->d_inode;
+	struct inode		*inode = data->inode;
 	struct nfs_page		*req;
 	struct page		*page;
 
@@ -1138,9 +1149,9 @@
 		nfs_list_remove_request(req);
 		page = req->wb_page;
 
-		dprintk("NFS: write (%s/%s %d@%Ld)",
-			req->wb_dentry->d_parent->d_name.name,
-			req->wb_dentry->d_name.name,
+		dprintk("NFS: write (%x/%Ld %d@%Ld)",
+			req->wb_inode->i_dev,
+			(long long)NFS_FILEID(req->wb_inode),
 			req->wb_bytes,
 			(long long)(nfs_page_offset(page) + req->wb_offset));
 
@@ -1181,7 +1192,6 @@
 nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data)
 {
 	struct nfs_page		*req;
-	struct dentry		*dentry;
 	struct inode		*inode;
 	unsigned long		start, end, len;
 
@@ -1191,10 +1201,7 @@
 	end = 0;
 	start = ~0;
 	req = nfs_list_entry(head->next);
-	dentry = req->wb_dentry;
-	data->dentry = dentry;
-	data->cred = req->wb_cred;
-	inode = dentry->d_inode;
+	inode = req->wb_inode;
 	while (!list_empty(head)) {
 		struct nfs_page	*req;
 		unsigned long	rqstart, rqend;
@@ -1208,7 +1215,9 @@
 		if (rqend > end)
 			end = rqend;
 	}
-	data->args.fh     = NFS_FH(dentry);
+	data->inode = inode;
+	data->cred = req->wb_cred;
+	data->args.fh     = NFS_FH(inode);
 	data->args.offset = start;
 	len = end - start;
 	if (end >= inode->i_size || len > (~((u32)0) >> 1))
@@ -1243,7 +1252,7 @@
 	/* Set up the argument struct */
 	nfs_commit_rpcsetup(head, data);
 	req = nfs_list_entry(data->pages.next);
-	clnt = NFS_CLIENT(req->wb_dentry->d_inode);
+	clnt = NFS_CLIENT(req->wb_inode);
 
 	rpc_init_task(task, clnt, nfs_commit_done, flags);
 	task->tk_calldata = data;
@@ -1279,8 +1288,7 @@
 	struct nfs_write_data	*data = (struct nfs_write_data *)task->tk_calldata;
 	struct nfs_writeres	*resp = &data->res;
 	struct nfs_page		*req;
-	struct dentry		*dentry = data->dentry;
-	struct inode		*inode = dentry->d_inode;
+	struct inode		*inode = data->inode;
 
         dprintk("NFS: %4d nfs_commit_done (status %d)\n",
                                 task->tk_pid, task->tk_status);
@@ -1290,9 +1298,9 @@
 		req = nfs_list_entry(data->pages.next);
 		nfs_list_remove_request(req);
 
-		dprintk("NFS: commit (%s/%s %d@%ld)",
-			req->wb_dentry->d_parent->d_name.name,
-			req->wb_dentry->d_name.name,
+		dprintk("NFS: commit (%x/%Ld %d@%ld)",
+			req->wb_inode->i_dev,
+			(long long)NFS_FILEID(req->wb_inode),
 			req->wb_bytes,
 			nfs_page_offset(req->wb_page) + req->wb_offset);
 		if (task->tk_status < 0) {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nfsd/auth.c linux.19p18/fs/nfsd/auth.c
--- linux.vanilla/fs/nfsd/auth.c	Fri Apr 21 12:46:44 2000
+++ linux.19p18/fs/nfsd/auth.c	Wed Feb  7 09:38:38 2001
@@ -10,6 +10,7 @@
 #include <linux/sunrpc/svcauth.h>
 #include <linux/nfsd/nfsd.h>
 
+#define	CAP_NFSD_MASK (CAP_FS_MASK|CAP_TO_MASK(CAP_SYS_RESOURCE))
 void
 nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
 {
@@ -50,10 +51,10 @@
 	current->ngroups = i;
 
 	if ((cred->cr_uid)) {
-		cap_t(current->cap_effective) &= ~CAP_FS_MASK;
+		cap_t(current->cap_effective) &= ~CAP_NFSD_MASK;
 	} else {
-		cap_t(current->cap_effective) |= (CAP_FS_MASK &
-		                                  current->cap_permitted);
+		cap_t(current->cap_effective) |= (CAP_NFSD_MASK &
+						  current->cap_permitted);
 	}
 
 	rqstp->rq_userset = 1;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nfsd/export.c linux.19p18/fs/nfsd/export.c
--- linux.vanilla/fs/nfsd/export.c	Mon Dec 11 22:13:03 2000
+++ linux.19p18/fs/nfsd/export.c	Wed Feb  7 09:38:52 2001
@@ -9,8 +9,6 @@
  * creates a client control block and adds it to the hash
  * table. Then, you call NFSCTL_EXPORT for each fs.
  *
- * You cannot currently read the export information from the
- * kernel. It would be nice to have a /proc file though.
  *
  * Copyright (C) 1995, 1996 Olaf Kirch, <okir@monad.swb.de>
  */
@@ -447,7 +445,7 @@
 	if (path) {
 		if (!(dentry = lookup_dentry(path, NULL, 0))) {
 			printk("nfsd: exp_rootfh path not found %s", path);
-			return -EPERM;
+			return err;
 		}
 		dev = dentry->d_inode->i_dev;
 		ino = dentry->d_inode->i_ino;
@@ -611,7 +609,7 @@
 	{ NFSEXP_SUNSECURE, { "sunsecure", ""}},
 	{ NFSEXP_CROSSMNT, {"nohide", ""}},
 	{ NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}},
-	{ NFSEXP_NOAUTHNLM, {"no_auth_nlm", ""}},
+	{ NFSEXP_NOAUTHNLM, {"insecure_locks", ""}},
 	{ 0, {"", ""}}
 };
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nfsd/nfs3proc.c linux.19p18/fs/nfsd/nfs3proc.c
--- linux.vanilla/fs/nfsd/nfs3proc.c	Mon Dec 11 22:13:03 2000
+++ linux.19p18/fs/nfsd/nfs3proc.c	Wed Feb  7 09:38:53 2001
@@ -29,7 +29,7 @@
 
 #define NFSDDBG_FACILITY		NFSDDBG_PROC
 
-#define RETURN(st)	{ resp->status = (st); return (st); }
+#define RETURN_STATUS(st)	{ resp->status = (st); return (st); }
 
 static int	nfs3_ftypes[] = {
 	0,			/* NF3NON */
@@ -76,7 +76,7 @@
 
 	fh_copy(&resp->fh, &argp->fh);
 	nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP);
-	RETURN(nfserr);
+	RETURN_STATUS(nfserr);
 }
 
 /*
@@ -94,7 +94,7 @@
 
 	fh_copy(&resp->fh, &argp->fh);
 	nfserr = nfsd_setattr(rqstp, &resp->fh, &argp->attrs);
-	RETURN(nfserr);
+	RETURN_STATUS(nfserr);
 }
 
 /*
@@ -116,7 +116,7 @@
 				    argp->name,
 				    argp->len,
 				    &resp->fh);
-	RETURN(nfserr);
+	RETURN_STATUS(nfserr);
 }
 
 /*
@@ -136,7 +136,7 @@
 	fh_copy(&resp->fh, &argp->fh);
 	resp->access = argp->access;
 	nfserr = nfsd_access(rqstp, &resp->fh, &resp->access);
-	RETURN(nfserr);
+	RETURN_STATUS(nfserr);
 }
 
 /*
@@ -161,7 +161,7 @@
 	fh_copy(&resp->fh, &argp->fh);
 	resp->len = NFS3_MAXPATHLEN;
 	nfserr = nfsd_readlink(rqstp, &resp->fh, (char *) path, &resp->len);
-	RETURN(nfserr);
+	RETURN_STATUS(nfserr);
 }
 
 /*
@@ -202,7 +202,7 @@
 		resp->eof = (argp->offset + resp->count) >= inode->i_size;
 	}
 
-	RETURN(nfserr);
+	RETURN_STATUS(nfserr);
 }
 
 /*
@@ -222,14 +222,14 @@
 				argp->stable? " stable" : "");
 
 	fh_copy(&resp->fh, &argp->fh);
+	resp->committed = argp->stable;
 	nfserr = nfsd_write(rqstp, &resp->fh,
 				   argp->offset,
 				   argp->data,
 				   argp->len,
-				   argp->stable);
-	resp->committed = argp->stable;
+				   &resp->committed);
 	resp->count = argp->count;
-	RETURN(nfserr);
+	RETURN_STATUS(nfserr);
 }
 
 /*
@@ -257,7 +257,7 @@
 	/* Get the directory inode */
 	nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, MAY_CREATE);
 	if (nfserr)
-		RETURN(nfserr);
+		RETURN_STATUS(nfserr);
 
 	/* Unfudge the mode bits */
 	attr->ia_mode &= ~S_IFMT;
@@ -273,7 +273,7 @@
 				attr, newfhp,
 				argp->createmode, argp->verf);
 
-	RETURN(nfserr);
+	RETURN_STATUS(nfserr);
 }
 
 /*
@@ -296,7 +296,7 @@
 	nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
 				    &argp->attrs, S_IFDIR, 0, &resp->fh);
 
-	RETURN(nfserr);
+	RETURN_STATUS(nfserr);
 }
 
 static int
@@ -315,7 +315,7 @@
 	nfserr = nfsd_symlink(rqstp, &resp->dirfh, argp->fname, argp->flen,
 						   argp->tname, argp->tlen,
 						   &resp->fh, &argp->attrs);
-	RETURN(nfserr);
+	RETURN_STATUS(nfserr);
 }
 
 /*
@@ -337,22 +337,22 @@
 	fh_init(&resp->fh);
 
 	if (argp->ftype == 0 || argp->ftype >= NF3BAD)
-		return nfserr_inval;
+		RETURN_STATUS(nfserr_inval);
 	if (argp->ftype == NF3CHR || argp->ftype == NF3BLK) {
 		if ((argp->ftype == NF3CHR && argp->major >= MAX_CHRDEV)
 		    || (argp->ftype == NF3BLK && argp->major >= MAX_BLKDEV)
 		    || argp->minor > 0xFF)
-			return nfserr_inval;
+			RETURN_STATUS(nfserr_inval);
 		rdev = ((argp->major) << 8) | (argp->minor);
 	} else
 		if (argp->ftype != NF3SOCK && argp->ftype != NF3FIFO)
-			return nfserr_inval;
+			RETURN_STATUS(nfserr_inval);
 
 	type = nfs3_ftypes[argp->ftype];
 	nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
 				    &argp->attrs, type, rdev, &resp->fh);
 
-	RETURN(nfserr);
+	RETURN_STATUS(nfserr);
 }
 
 /*
@@ -372,7 +372,7 @@
 	/* Unlink. -S_IFDIR means file must not be a directory */
 	fh_copy(&resp->fh, &argp->fh);
 	nfserr = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR, argp->name, argp->len);
-	RETURN(nfserr);
+	RETURN_STATUS(nfserr);
 }
 
 /*
@@ -391,7 +391,7 @@
 
 	fh_copy(&resp->fh, &argp->fh);
 	nfserr = nfsd_unlink(rqstp, &resp->fh, S_IFDIR, argp->name, argp->len);
-	RETURN(nfserr);
+	RETURN_STATUS(nfserr);
 }
 
 static int
@@ -412,7 +412,7 @@
 	fh_copy(&resp->tfh, &argp->tfh);
 	nfserr = nfsd_rename(rqstp, &resp->ffh, argp->fname, argp->flen,
 				    &resp->tfh, argp->tname, argp->tlen);
-	RETURN(nfserr);
+	RETURN_STATUS(nfserr);
 }
 
 static int
@@ -432,7 +432,7 @@
 	fh_copy(&resp->tfh, &argp->tfh);
 	nfserr = nfsd_link(rqstp, &resp->tfh, argp->tname, argp->tlen,
 				  &resp->fh);
-	RETURN(nfserr);
+	RETURN_STATUS(nfserr);
 }
 
 /*
@@ -468,7 +468,7 @@
 	memcpy(resp->verf, argp->verf, 8);
 	resp->count = count;
 
-	RETURN(nfserr);
+	RETURN_STATUS(nfserr);
 }
 
 /*
@@ -504,7 +504,7 @@
 	memcpy(resp->verf, argp->verf, 8);
 	resp->count = count;
 
-	RETURN(nfserr);
+	RETURN_STATUS(nfserr);
 }
 
 /*
@@ -522,7 +522,7 @@
 
 	nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats);
 	fh_put(&argp->fh);
-	RETURN(nfserr);
+	RETURN_STATUS(nfserr);
 }
 
 /*
@@ -563,7 +563,7 @@
 	}
 
 	fh_put(&argp->fh);
-	RETURN(nfserr);
+	RETURN_STATUS(nfserr);
 }
 
 /*
@@ -606,7 +606,7 @@
 	}
 
 	fh_put(&argp->fh);
-	RETURN(nfserr);
+	RETURN_STATUS(nfserr);
 }
 
 
@@ -626,12 +626,12 @@
 				(unsigned long) argp->offset);
 
 	if (argp->offset > NFS_OFFSET_MAX)
-		return nfserr_inval;
+		RETURN_STATUS(nfserr_inval);
 
 	fh_copy(&resp->fh, &argp->fh);
 	nfserr = nfsd_commit(rqstp, &resp->fh, argp->offset, argp->count);
 
-	RETURN(nfserr);
+	RETURN_STATUS(nfserr);
 }
 
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nfsd/nfs3xdr.c linux.19p18/fs/nfsd/nfs3xdr.c
--- linux.vanilla/fs/nfsd/nfs3xdr.c	Mon Dec 11 22:13:03 2000
+++ linux.19p18/fs/nfsd/nfs3xdr.c	Wed Feb  7 09:38:54 2001
@@ -36,17 +36,6 @@
 	NF3SOCK, NF3BAD,  NF3LNK, NF3BAD,
 };
 
-/*
- * XDR functions for basic NFS types
- */
-static inline u32 *
-dec64(u32 *p, u64 *valp)
-{
-	*valp  = ((u64) ntohl(*p++)) << 32;
-	*valp |= ntohl(*p++);
-	return p;
-}
-
 static inline u32 *
 encode_time3(u32 *p, time_t secs)
 {
@@ -140,7 +129,7 @@
 		u64	newsize;
 
 		iap->ia_valid |= ATTR_SIZE;
-		p = dec64(p, &newsize);
+		p = xdr_decode_hyper(p, &newsize);
 		if (newsize <= NFS_OFFSET_MAX)
 			iap->ia_size = (u32) newsize;
 		else
@@ -177,24 +166,24 @@
 	*p++ = htonl((u32) nfsd_ruid(rqstp, inode->i_uid));
 	*p++ = htonl((u32) nfsd_rgid(rqstp, inode->i_gid));
 	if (S_ISLNK(inode->i_mode) && inode->i_size > NFS3_MAXPATHLEN) {
-		p = enc64(p, (u64) NFS3_MAXPATHLEN);
+		p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
 	} else {
-		p = enc64(p, (u64) inode->i_size);
+		p = xdr_encode_hyper(p, (u64) inode->i_size);
 	}
 	/*
 	 *  For the 'used' member, we take i_blocks if set; assuming 512-byte
 	 *  units.  Some FSs don't set this, so all we can do then is
 	 *  use the size.
 	 */
-	if (inode->i_blocks) {
-		p = enc64(p,  ((u64)inode->i_blocks)<<9 );
-	} else {
-		p = enc64(p, (u64) inode->i_size);
-	}
+	if (inode->i_blocks)
+		p = xdr_encode_hyper(p,  ((u64)inode->i_blocks)<<9 );
+	else
+		p = xdr_encode_hyper(p, (u64) inode->i_size);
+
 	*p++ = htonl((u32) MAJOR(inode->i_rdev));
 	*p++ = htonl((u32) MINOR(inode->i_rdev));
-	p = enc64(p, (u64) inode->i_dev);
-	p = enc64(p, (u64) inode->i_ino);
+	p = xdr_encode_hyper(p, (u64) inode->i_dev);
+	p = xdr_encode_hyper(p, (u64) inode->i_ino);
 	p = encode_time3(p, inode->i_atime);
 	p = encode_time3(p, inode->i_mtime);
 	p = encode_time3(p, inode->i_ctime);
@@ -216,19 +205,19 @@
 	*p++ = htonl((u32) nfsd_ruid(rqstp, fhp->fh_post_uid));
 	*p++ = htonl((u32) nfsd_rgid(rqstp, fhp->fh_post_gid));
 	if (S_ISLNK(fhp->fh_post_mode) && fhp->fh_post_size > NFS3_MAXPATHLEN) {
-		p = enc64(p, (u64) NFS3_MAXPATHLEN);
+		p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
 	} else {
-		p = enc64(p, (u64) fhp->fh_post_size);
+		p = xdr_encode_hyper(p, (u64) fhp->fh_post_size);
 	}
 	if (fhp->fh_post_blocks) {
-		p = enc64(p, ((u64)fhp->fh_post_blocks)<<9);
+		p = xdr_encode_hyper(p, ((u64)fhp->fh_post_blocks)<<9);
 	} else {
-		p = enc64(p, (u64) fhp->fh_post_size);
+		p = xdr_encode_hyper(p, (u64) fhp->fh_post_size);
 	}
 	*p++ = htonl((u32) MAJOR(fhp->fh_post_rdev));
 	*p++ = htonl((u32) MINOR(fhp->fh_post_rdev));
-	p = enc64(p, (u64) inode->i_dev);
-	p = enc64(p, (u64) inode->i_ino);
+	p = xdr_encode_hyper(p, (u64) inode->i_dev);
+	p = xdr_encode_hyper(p, (u64) inode->i_ino);
 	p = encode_time3(p, fhp->fh_post_atime);
 	p = encode_time3(p, fhp->fh_post_mtime);
 	p = encode_time3(p, fhp->fh_post_ctime);
@@ -263,7 +252,7 @@
 	if (dentry && dentry->d_inode && fhp->fh_post_saved) {
 		if (fhp->fh_pre_saved) {
 			*p++ = xdr_one;
-			p = enc64(p, (u64) fhp->fh_pre_size);
+			p = xdr_encode_hyper(p, (u64) fhp->fh_pre_size);
 			p = encode_time3(p, fhp->fh_pre_mtime);
 			p = encode_time3(p, fhp->fh_pre_ctime);
 		} else {
@@ -350,7 +339,7 @@
 					struct nfsd3_readargs *args)
 {
 	if (!(p = decode_fh(p, &args->fh))
-	 || !(p = dec64(p, &args->offset)))
+	 || !(p = xdr_decode_hyper(p, &args->offset)))
 		return 0;
 
 	args->count = ntohl(*p++);
@@ -362,7 +351,7 @@
 					struct nfsd3_writeargs *args)
 {
 	if (!(p = decode_fh(p, &args->fh))
-	 || !(p = dec64(p, &args->offset)))
+	 || !(p = xdr_decode_hyper(p, &args->offset)))
 		return 0;
 
 	args->count = ntohl(*p++);
@@ -478,7 +467,7 @@
 {
 	if (!(p = decode_fh(p, &args->fh)))
 		return 0;
-	p = dec64(p, &args->cookie);
+	p = xdr_decode_hyper(p, &args->cookie);
 	args->verf   = p; p += 2;
 	args->dircount = ~0;
 	args->count  = ntohl(*p++);
@@ -492,7 +481,7 @@
 {
 	if (!(p = decode_fh(p, &args->fh)))
 		return 0;
-	p = dec64(p, &args->cookie);
+	p = xdr_decode_hyper(p, &args->cookie);
 	args->verf     = p; p += 2;
 	args->dircount = ntohl(*p++);
 	args->count    = ntohl(*p++);
@@ -506,7 +495,7 @@
 {
 	if (!(p = decode_fh(p, &args->fh)))
 		return 0;
-	p = dec64(p, &args->offset);
+	p = xdr_decode_hyper(p, &args->offset);
 	args->count = ntohl(*p++);
 
 	return xdr_argsize_check(rqstp, p);
@@ -682,7 +671,7 @@
 	int		buflen, slen, elen;
 
 	if (cd->offset)
-		enc64(cd->offset, (u64) offset);
+		xdr_encode_hyper(cd->offset, (u64) offset);
 
 	/* nfsd_readdir calls us with name == 0 when it wants us to
 	 * set the last offset entry. */
@@ -705,20 +694,12 @@
 		cd->eob = 1;
 		return -EINVAL;
 	}
-	*p++ = xdr_one;				   /* mark entry present */
-	p    = enc64(p, ino);			   /* file id */
-#ifdef XDR_ENCODE_STRING_TAKES_LENGTH
-	p    = xdr_encode_string(p, name, namlen); /* name length & name */
-#else
-	/* just like nfsproc.c */
-	*p++ = htonl((u32) namlen);
-	p[slen - 1] = 0;		/* don't leak kernel data */
-	memcpy(p, name, namlen);
-	p += slen;
-#endif
+	*p++ = xdr_one;				  /* mark entry present */
+	p    = xdr_encode_hyper(p, ino);	  /* file id */
+	p    = xdr_encode_string(p, name, namlen);/* name length & name */
 
 	cd->offset = p;			/* remember pointer */
-	p = enc64(p, NFS_OFFSET_MAX);	/* offset of next entry */
+	p = xdr_encode_hyper(p, NFS_OFFSET_MAX);	/* offset of next entry */
 
 	/* throw in readdirplus baggage */
 	if (plus) {
@@ -769,12 +750,12 @@
 	*p++ = xdr_zero;	/* no post_op_attr */
 
 	if (resp->status == 0) {
-		p = enc64(p, bs * s->f_blocks);	/* total bytes */
-		p = enc64(p, bs * s->f_bfree);	/* free bytes */
-		p = enc64(p, bs * s->f_bavail);	/* user available bytes */
-		p = enc64(p, s->f_files);	/* total inodes */
-		p = enc64(p, s->f_ffree);	/* free inodes */
-		p = enc64(p, s->f_ffree);	/* user available inodes */
+		p = xdr_encode_hyper(p, bs * s->f_blocks);	/* total bytes */
+		p = xdr_encode_hyper(p, bs * s->f_bfree);	/* free bytes */
+		p = xdr_encode_hyper(p, bs * s->f_bavail);	/* user available bytes */
+		p = xdr_encode_hyper(p, s->f_files);	/* total inodes */
+		p = xdr_encode_hyper(p, s->f_ffree);	/* free inodes */
+		p = xdr_encode_hyper(p, s->f_ffree);	/* user available inodes */
 		*p++ = htonl(resp->invarsec);	/* mean unchanged time */
 	}
 	return xdr_ressize_check(rqstp, p);
@@ -795,7 +776,7 @@
 		*p++ = htonl(resp->f_wtpref);
 		*p++ = htonl(resp->f_wtmult);
 		*p++ = htonl(resp->f_dtpref);
-		p = enc64(p, resp->f_maxfilesize);
+		p = xdr_encode_hyper(p, resp->f_maxfilesize);
 		*p++ = xdr_one;
 		*p++ = xdr_zero;
 		*p++ = htonl(resp->f_properties);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nfsd/nfscache.c linux.19p18/fs/nfsd/nfscache.c
--- linux.vanilla/fs/nfsd/nfscache.c	Mon Dec 11 22:13:03 2000
+++ linux.19p18/fs/nfsd/nfscache.c	Thu Feb 15 16:18:02 2001
@@ -161,7 +161,7 @@
 		    xid == rp->c_xid && proc == rp->c_proc &&
 		    proto == rp->c_prot && vers == rp->c_vers &&
 		    time_before(jiffies, rp->c_timestamp + 120*HZ) &&
-		    memcmp((char*)&rqstp->rq_addr, (char*)&rp->c_addr, rqstp->rq_addrlen)==0) {
+		    memcmp((char*)&rqstp->rq_addr, (char*)&rp->c_addr, sizeof(rp->c_addr))==0) {
 			nfsdstats.rchits++;
 			goto found_entry;
 		}
@@ -217,13 +217,12 @@
 found_entry:
 	/* We found a matching entry which is either in progress or done. */
 	age = jiffies - rp->c_timestamp;
+	rp->c_timestamp = jiffies;
+	lru_put_front(rp);
 
 	/* Request being processed or excessive rexmits */
 	if (rp->c_state == RC_INPROG || age < RC_DELAY)
 		return RC_DROPIT;
-
-	rp->c_timestamp = jiffies;
-	lru_put_front(rp);
 
 	/* From the hall of fame of impractical attacks:
 	 * Is this a user who tries to snoop on the cache? */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nfsd/nfsctl.c linux.19p18/fs/nfsd/nfsctl.c
--- linux.vanilla/fs/nfsd/nfsctl.c	Mon Dec 11 22:13:03 2000
+++ linux.19p18/fs/nfsd/nfsctl.c	Wed Feb  7 09:38:51 2001
@@ -131,7 +131,6 @@
 static void
 nfsd_init(void)
 {
-	nfsd_xdr_init();	/* XDR */
 	nfsd_stat_init();	/* Statistics */
 	nfsd_cache_init();	/* RPC reply cache */
 	nfsd_export_init();	/* Exports table */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nfsd/nfsfh.c linux.19p18/fs/nfsd/nfsfh.c
--- linux.vanilla/fs/nfsd/nfsfh.c	Mon Dec 11 22:13:03 2000
+++ linux.19p18/fs/nfsd/nfsfh.c	Mon Feb 12 14:51:59 2001
@@ -183,7 +183,6 @@
 	if (!(target->d_flags & DCACHE_NFSD_DISCONNECTED))
 		printk("nfsd: d_splice with non-DISCONNECTED target: %s/%s\n", parent->d_name.name, name->name);
 #endif
-	name->hash = full_name_hash(name->name, name->len);
 	tdentry = d_alloc(parent, name);
 	if (tdentry == NULL)
 		return -ENOMEM;
@@ -275,7 +274,6 @@
 	struct qstr qs;
 	char namebuf[256];
 	struct list_head *lp;
-	struct dentry *tmp;
 	/* child is an IS_ROOT (anonymous) dentry, but it is hypothesised that
 	 * it should be a child of parent.
 	 * We see if we can find a name and, if we can - splice it in.
@@ -295,8 +293,8 @@
 	 * parent by a lookup.  In this case return that dentry. 
 	 * caller must notice and act accordingly
 	 */
-	for (lp = child->d_inode->i_dentry.next; lp != &child->d_inode->i_dentry ; lp=lp->next) {
-		tmp = list_entry(lp,struct dentry, d_alias);
+	list_for_each(lp, &child->d_inode->i_dentry) {
+		struct dentry *tmp = list_entry(lp,struct dentry, d_alias);
 		if (tmp->d_parent == parent) {
 			child = dget(tmp);
 			goto out;
@@ -308,12 +306,12 @@
 	err = get_ino_name(parent, &qs, child->d_inode->i_ino);
 	if (err)
 		goto out;
-	tmp = d_lookup(parent, &qs);
-	if (tmp) {
+
+	/* find_inode_number calculates the name hash as a side effect */
+	if (find_inode_number(parent, &qs) != 0) {
 		/* Now that IS odd.  I wonder what it means... */
 		err = -EEXIST;
 		printk("nfsd-fh: found a name that I didn't expect: %s/%s\n", parent->d_name.name, qs.name);
-		dput(tmp);
 		goto out;
 	}
 	err = d_splice(child, parent, &qs);
@@ -339,7 +337,7 @@
 	struct dentry *dentry, *result = NULL;
 	struct dentry *tmp;
 	int  found =0;
-	int err;
+	int err = -ESTALE;
 	/* the sb->s_nfsd_free_path_sem semaphore is needed to make sure that only one unconnected (free)
 	 * dcache path ever exists, as otherwise two partial paths might get
 	 * joined together, which would be very confusing.
@@ -353,23 +351,21 @@
 	 * Attempt to find the inode.
 	 */
  retry:
+	down(&sb->s_nfsd_free_path_sem);
 	result = nfsd_iget(sb, fh->fh_ino, fh->fh_generation);
-	err = PTR_ERR(result);
-	if (IS_ERR(result))
-		goto err_out;
-	err = -ESTALE;
-	if (!result) {
-		dprintk("find_fh_dentry: No inode found.\n");
-		goto err_out;
-	}
-	if (! (result->d_flags & DCACHE_NFSD_DISCONNECTED))
-		return result;
-
-	/* result is now an anonymous dentry, which may be adequate as it 
-	 * stands, or else will get spliced into the dcache tree */
-
-	if (!S_ISDIR(result->d_inode->i_mode) && ! needpath) {
-		nfsdstats.fh_anon++;
+	if (!result || IS_ERR(result)
+	    || !(result->d_flags & DCACHE_NFSD_DISCONNECTED)
+	    || (!S_ISDIR(result->d_inode->i_mode) && !needpath)) {
+		up(&sb->s_nfsd_free_path_sem);
+		if (!result) {
+			dprintk("find_fh_dentry: No inode found.\n");
+			goto err_out;
+		}
+		err = PTR_ERR(result);
+		if (IS_ERR(result))
+			goto err_out;
+		if ( (result->d_flags & DCACHE_NFSD_DISCONNECTED))
+			nfsdstats.fh_anon++;
 		return result;
 	}
 
@@ -377,14 +373,6 @@
 	 * location in the tree.
 	 */
 	dprintk("nfs_fh: need to look harder for %d/%d\n",sb->s_dev,fh->fh_ino);
-	down(&sb->s_nfsd_free_path_sem);
-
-	/* claiming the semaphore might have allow things to get fixed up */
-	if (! (result->d_flags & DCACHE_NFSD_DISCONNECTED)) {
-		up(&sb->s_nfsd_free_path_sem);
-		return result;
-	}
-
 
 	found = 0;
 	if (!S_ISDIR(result->d_inode->i_mode)) {
@@ -466,6 +454,7 @@
 		if (tmp != dentry) {
 			/* we lost a race,  try again
 			 */
+			dput(pdentry);
 			dput(tmp);
 			dput(dentry);
 			dput(result);	/* this will discard the whole free path, so we can up the semaphore */
@@ -563,7 +552,7 @@
 					!(exp->ex_flags & NFSEXP_NOSUBTREECHECK));
 
 		if (IS_ERR(dentry)) {
-			error = nfserrno(-PTR_ERR(dentry));
+			error = nfserrno(PTR_ERR(dentry));
 			goto out;
 		}
 #ifdef NFSD_PARANOIA
@@ -690,7 +679,7 @@
 	fhp->fh_handle.fh_dev    = kdev_t_to_u32(parent->d_inode->i_dev);
 	fhp->fh_handle.fh_xdev   = kdev_t_to_u32(exp->ex_dev);
 	fhp->fh_handle.fh_xino   = ino_t_to_u32(exp->ex_ino);
-	fhp->fh_handle.fh_dcookie = (struct dentry *)0xfeebbaca;
+	fhp->fh_handle.fh_dcookie = 0xfeebbaca;
 	if (inode) {
 		fhp->fh_handle.fh_ino = ino_t_to_u32(inode->i_ino);
 		fhp->fh_handle.fh_generation = inode->i_generation;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nfsd/nfsproc.c linux.19p18/fs/nfsd/nfsproc.c
--- linux.vanilla/fs/nfsd/nfsproc.c	Mon Dec 11 22:13:03 2000
+++ linux.19p18/fs/nfsd/nfsproc.c	Wed Feb  7 09:38:53 2001
@@ -30,10 +30,6 @@
 
 #define NFSDDBG_FACILITY		NFSDDBG_PROC
 
-/* Check for dir entries '.' and '..' */
-#define isdotent(n, l)	(l < 3 && n[0] == '.' && (l == 1 || n[1] == '.'))
-
-#define RETURN(st)	return st
 
 static void
 svcbuf_reserve(struct svc_buf *buf, u32 **ptr, int *len, int nr)
@@ -45,7 +41,7 @@
 static int
 nfsd_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
 {
-	RETURN(nfs_ok);
+	return nfs_ok;
 }
 
 /*
@@ -60,7 +56,7 @@
 		SVCFH_DEV(&argp->fh), SVCFH_INO(&argp->fh));
 
 	fh_copy(&resp->fh, &argp->fh);
-	RETURN(fh_verify(rqstp, &resp->fh, 0, MAY_NOP));
+	return fh_verify(rqstp, &resp->fh, 0, MAY_NOP);
 }
 
 /*
@@ -76,7 +72,7 @@
 		argp->attrs.ia_valid, (long) argp->attrs.ia_size);
 
 	fh_copy(&resp->fh, &argp->fh);
-	RETURN(nfsd_setattr(rqstp, &resp->fh, &argp->attrs));
+	return nfsd_setattr(rqstp, &resp->fh, &argp->attrs);
 }
 
 /*
@@ -98,7 +94,7 @@
 				 &resp->fh);
 
 	fh_put(&argp->fh);
-	RETURN(nfserr);
+	return nfserr;
 }
 
 /*
@@ -121,7 +117,7 @@
 	nfserr = nfsd_readlink(rqstp, &argp->fh, (char *) path, &resp->len);
 
 	fh_put(&argp->fh);
-	RETURN(nfserr);
+	return nfserr;
 }
 
 /*
@@ -159,7 +155,7 @@
 				  (char *) buffer,
 				  &resp->count);
 
-	RETURN(nfserr);
+	return nfserr;
 }
 
 /*
@@ -171,6 +167,7 @@
 					struct nfsd_attrstat  *resp)
 {
 	int	nfserr;
+	int	stable = 1;
 
 	dprintk("nfsd: WRITE    %d/%d %d bytes at %d\n",
 		SVCFH_DEV(&argp->fh), SVCFH_INO(&argp->fh),
@@ -180,8 +177,8 @@
 				   argp->offset,
 				   argp->data,
 				   argp->len,
-				   0);
-	RETURN(nfserr);
+				   &stable);
+	return nfserr;
 }
 
 /*
@@ -257,8 +254,19 @@
 	if (attr->ia_valid & ATTR_MODE) { 
 		type = attr->ia_mode & S_IFMT;
 		mode = attr->ia_mode & ~S_IFMT;
-		if (!type)	/* HP weirdness */
-			type = S_IFREG;
+		if (!type) {
+			/* no type, so if target exists, assume same as that,
+			 * else assume a file */
+			if (inode) {
+				type = inode->i_mode & S_IFMT;
+				if (type == S_IFCHR || type == S_IFBLK) {
+					/* reserve rdev for later checking */
+					attr->ia_size = inode->i_rdev;
+					attr->ia_valid |= ATTR_SIZE;
+				}
+			} else
+				type = S_IFREG;
+		}
 	} else if (inode) {
 		type = inode->i_mode & S_IFMT;
 		mode = inode->i_mode & ~S_IFMT;
@@ -331,7 +339,7 @@
 
 done:
 	fh_put(dirfhp);
-	RETURN(nfserr);
+	return nfserr;
 }
 
 static int
@@ -345,7 +353,7 @@
 	/* Unlink. -SIFDIR means file must not be a directory */
 	nfserr = nfsd_unlink(rqstp, &argp->fh, -S_IFDIR, argp->name, argp->len);
 	fh_put(&argp->fh);
-	RETURN(nfserr);
+	return nfserr;
 }
 
 static int
@@ -362,7 +370,7 @@
 				    &argp->tfh, argp->tname, argp->tlen);
 	fh_put(&argp->ffh);
 	fh_put(&argp->tfh);
-	RETURN(nfserr);
+	return nfserr;
 }
 
 static int
@@ -380,7 +388,7 @@
 				  &argp->ffh);
 	fh_put(&argp->ffh);
 	fh_put(&argp->tfh);
-	RETURN(nfserr);
+	return nfserr;
 }
 
 static int
@@ -404,7 +412,7 @@
 
 	fh_put(&argp->ffh);
 	fh_put(&newfh);
-	RETURN(nfserr);
+	return nfserr;
 }
 
 /*
@@ -428,7 +436,7 @@
 	nfserr = nfsd_create(rqstp, &argp->fh, argp->name, argp->len,
 				    &argp->attrs, S_IFDIR, 0, &resp->fh);
 	fh_put(&argp->fh);
-	RETURN(nfserr);
+	return nfserr;
 }
 
 /*
@@ -444,7 +452,7 @@
 
 	nfserr = nfsd_unlink(rqstp, &argp->fh, S_IFDIR, argp->name, argp->len);
 	fh_put(&argp->fh);
-	RETURN(nfserr);
+	return nfserr;
 }
 
 /*
@@ -480,7 +488,7 @@
 	resp->count = count;
 
 	fh_put(&argp->fh);
-	RETURN(nfserr);
+	return nfserr;
 }
 
 /*
@@ -496,7 +504,7 @@
 
 	nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats);
 	fh_put(&argp->fh);
-	RETURN(nfserr);
+	return nfserr;
 }
 
 /*
@@ -549,36 +557,36 @@
 		int	nfserr;
 		int	syserr;
 	} nfs_errtbl[] = {
-		{ NFS_OK, 0 },
-		{ NFSERR_PERM, EPERM },
-		{ NFSERR_NOENT, ENOENT },
-		{ NFSERR_IO, EIO },
-		{ NFSERR_NXIO, ENXIO },
-		{ NFSERR_ACCES, EACCES },
-		{ NFSERR_EXIST, EEXIST },
-		{ NFSERR_XDEV, EXDEV },
-		{ NFSERR_MLINK, EMLINK },
-		{ NFSERR_NODEV, ENODEV },
-		{ NFSERR_NOTDIR, ENOTDIR },
-		{ NFSERR_ISDIR, EISDIR },
-		{ NFSERR_INVAL, EINVAL },
-		{ NFSERR_FBIG, EFBIG },
-		{ NFSERR_NOSPC, ENOSPC },
-		{ NFSERR_ROFS, EROFS },
-		{ NFSERR_MLINK, EMLINK },
-		{ NFSERR_NAMETOOLONG, ENAMETOOLONG },
-		{ NFSERR_NOTEMPTY, ENOTEMPTY },
+		{ nfs_ok, 0 },
+		{ nfserr_perm, -EPERM },
+		{ nfserr_noent, -ENOENT },
+		{ nfserr_io, -EIO },
+		{ nfserr_nxio, -ENXIO },
+		{ nfserr_acces, -EACCES },
+		{ nfserr_exist, -EEXIST },
+		{ nfserr_xdev, -EXDEV },
+		{ nfserr_mlink, -EMLINK },
+		{ nfserr_nodev, -ENODEV },
+		{ nfserr_notdir, -ENOTDIR },
+		{ nfserr_isdir, -EISDIR },
+		{ nfserr_inval, -EINVAL },
+		{ nfserr_fbig, -EFBIG },
+		{ nfserr_nospc, -ENOSPC },
+		{ nfserr_rofs, -EROFS },
+		{ nfserr_mlink, -EMLINK },
+		{ nfserr_nametoolong, -ENAMETOOLONG },
+		{ nfserr_notempty, -ENOTEMPTY },
 #ifdef EDQUOT
-		{ NFSERR_DQUOT, EDQUOT },
+		{ nfserr_dquot, -EDQUOT },
 #endif
-		{ NFSERR_STALE, ESTALE },
-		{ -1, EIO }
+		{ nfserr_stale, -ESTALE },
+		{ -1, -EIO }
 	};
 	int	i;
 
 	for (i = 0; nfs_errtbl[i].nfserr != -1; i++) {
 		if (nfs_errtbl[i].syserr == errno)
-			return htonl(nfs_errtbl[i].nfserr);
+			return nfs_errtbl[i].nfserr;
 	}
 	printk (KERN_INFO "nfsd: non-standard errno: %d\n", errno);
 	return nfserr_io;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nfsd/nfsxdr.c linux.19p18/fs/nfsd/nfsxdr.c
--- linux.vanilla/fs/nfsd/nfsxdr.c	Mon Dec 11 22:13:03 2000
+++ linux.19p18/fs/nfsd/nfsxdr.c	Wed Feb  7 09:38:52 2001
@@ -17,15 +17,6 @@
 
 #define NFSDDBG_FACILITY		NFSDDBG_XDR
 
-u32	nfs_ok, nfserr_perm, nfserr_noent, nfserr_io, nfserr_nxio,
-	nfserr_acces, nfserr_exist, nfserr_xdev, nfserr_nodev,
-	nfserr_notdir, nfserr_isdir, nfserr_inval, nfserr_fbig,
-	nfserr_nospc, nfserr_rofs, nfserr_mlink,
-	nfserr_nametoolong, nfserr_notempty, nfserr_dquot, nfserr_stale,
-	nfserr_remote, nfserr_badhandle, nfserr_notsync,
-	nfserr_badcookie, nfserr_notsupp, nfserr_toosmall,
-	nfserr_serverfault, nfserr_badtype, nfserr_jukebox;
-
 
 #ifdef NFSD_OPTIMIZE_SPACE
 # define inline
@@ -35,57 +26,12 @@
  * Mapping of S_IF* types to NFS file types
  */
 static u32	nfs_ftypes[] = {
-	NFNON,  NFFIFO, NFCHR, NFBAD,
+	NFNON,  NFCHR,  NFCHR, NFBAD,
 	NFDIR,  NFBAD,  NFBLK, NFBAD,
 	NFREG,  NFBAD,  NFLNK, NFBAD,
 	NFSOCK, NFBAD,  NFLNK, NFBAD,
 };
 
-/*
- * Initialization of NFS status variables
- */
-void
-nfsd_xdr_init(void)
-{
-	static int	inited = 0;
-
-	if (inited)
-		return;
-
-	nfs_ok		= htonl(NFS_OK);
-	nfserr_perm	= htonl(NFSERR_PERM);
-	nfserr_noent	= htonl(NFSERR_NOENT);
-	nfserr_io	= htonl(NFSERR_IO);
-	nfserr_inval	= htonl(NFSERR_INVAL);
-	nfserr_nxio	= htonl(NFSERR_NXIO);
-	nfserr_acces	= htonl(NFSERR_ACCES);
-	nfserr_exist	= htonl(NFSERR_EXIST);
-	nfserr_xdev	= htonl(NFSERR_XDEV);
-	nfserr_nodev	= htonl(NFSERR_NODEV);
-	nfserr_notdir	= htonl(NFSERR_NOTDIR);
-	nfserr_isdir	= htonl(NFSERR_ISDIR);
-	nfserr_inval	= htonl(NFSERR_INVAL);
-	nfserr_fbig	= htonl(NFSERR_FBIG);
-	nfserr_nospc	= htonl(NFSERR_NOSPC);
-	nfserr_rofs	= htonl(NFSERR_ROFS);
-	nfserr_mlink	= htonl(NFSERR_MLINK);
-	nfserr_nametoolong = htonl(NFSERR_NAMETOOLONG);
-	nfserr_notempty	= htonl(NFSERR_NOTEMPTY);
-	nfserr_dquot	= htonl(NFSERR_DQUOT);
-	nfserr_stale	= htonl(NFSERR_STALE);
-	nfserr_remote	= htonl(NFSERR_REMOTE);
-	nfserr_badhandle = htonl(NFSERR_BADHANDLE);
-	nfserr_notsync	= htonl(NFSERR_NOT_SYNC);
-	nfserr_badcookie = htonl(NFSERR_BAD_COOKIE);
-	nfserr_notsupp	= htonl(NFSERR_NOTSUPP);
-	nfserr_toosmall	= htonl(NFSERR_TOOSMALL);
-	nfserr_serverfault = htonl(NFSERR_SERVERFAULT);
-	nfserr_badtype	= htonl(NFSERR_BADTYPE);
-	nfserr_jukebox	= htonl(NFSERR_JUKEBOX);
-
-
-	inited = 1;
-}
 
 /*
  * XDR functions for basic NFS types
@@ -189,20 +135,25 @@
 static inline u32 *
 encode_fattr(struct svc_rqst *rqstp, u32 *p, struct inode *inode)
 {
+	int type = (inode->i_mode & S_IFMT);
 	if (!inode)
 		return 0;
-	*p++ = htonl(nfs_ftypes[(inode->i_mode & S_IFMT) >> 12]);
+	*p++ = htonl(nfs_ftypes[type >> 12]);
 	*p++ = htonl((u32) inode->i_mode);
 	*p++ = htonl((u32) inode->i_nlink);
 	*p++ = htonl((u32) nfsd_ruid(rqstp, inode->i_uid));
 	*p++ = htonl((u32) nfsd_rgid(rqstp, inode->i_gid));
-	if (S_ISLNK(inode->i_mode) && inode->i_size > NFS_MAXPATHLEN) {
+
+	if (S_ISLNK(type) && inode->i_size > NFS_MAXPATHLEN) {
 		*p++ = htonl(NFS_MAXPATHLEN);
 	} else {
 		*p++ = htonl((u32) inode->i_size);
 	}
 	*p++ = htonl((u32) inode->i_blksize);
-	*p++ = htonl((u32) inode->i_rdev);
+	if (S_ISCHR(type) || S_ISBLK(type))
+		*p++ = htonl((u32) inode->i_rdev);
+	else
+		*p++ = htonl(0xffffffff);
 	*p++ = htonl((u32) inode->i_blocks);
 	*p++ = htonl((u32) inode->i_dev);
 	*p++ = htonl((u32) inode->i_ino);
@@ -465,11 +416,9 @@
 		cd->eob = 1;
 		return -EINVAL;
 	}
-	*p++ = xdr_one;			/* mark entry present */
-	*p++ = htonl((u32) ino);	/* file id */
-	*p++ = htonl((u32) namlen);	/* name length & name */
-	memcpy(p, name, namlen);
-	p += slen;
+	*p++ = xdr_one;				/* mark entry present */
+	*p++ = htonl((u32) ino);		/* file id */
+	p    = xdr_encode_string(p, name, namlen);/* name length & name */
 	cd->offset = p;			/* remember pointer */
 	*p++ = ~(u32) 0;		/* offset of next entry */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nfsd/vfs.c linux.19p18/fs/nfsd/vfs.c
--- linux.vanilla/fs/nfsd/vfs.c	Mon Dec 11 22:13:03 2000
+++ linux.19p18/fs/nfsd/vfs.c	Wed Feb  7 09:39:03 2001
@@ -59,9 +59,6 @@
  */
 extern long nfsd_time_diff_margin;
 
-/* Check for dir entries '.' and '..' */
-#define isdotent(n, l)	(l < 3 && n[0] == '.' && (l == 1 || n[1] == '.'))
-
 /*
  * This is a cache of readahead params that help us choose the proper
  * readahead strategy. Initially, we set all readahead parameters to 0
@@ -157,15 +154,12 @@
 	dparent = fhp->fh_dentry;
 	exp  = fhp->fh_export;
 
-#if 0
-	err = nfsd_permission(exp, dparent, MAY_EXEC);
-	if (err)
-		goto out;
-#endif
 	err = nfserr_acces;
 
 	/* Lookup the name, but don't follow links */
-	if (strcmp(name, "..")==0) {
+	if (strcmp(name, ".")==0) {
+		dchild = dget(dparent);
+	} else if (strcmp(name, "..")==0) {
 		/* checking mountpoint crossing is very different when stepping up */
 		if (dparent == exp->ex_dentry) {
 			if (!EX_CROSSMNT(exp))
@@ -230,7 +224,7 @@
 	return err;
 
 out_nfserr:
-	err = nfserrno(-PTR_ERR(dchild));
+	err = nfserrno(PTR_ERR(dchild));
 	goto out;
 }
 
@@ -283,11 +277,11 @@
 	    if (delta<0) delta = -delta;
 	    if (delta < MAX_TOUCH_TIME_ERROR) {
 		/* turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME
-		 * this will cause notify_change to setthese times to "now"
+		 * this will cause notify_change to set these times to "now"
 		 */
 		iap->ia_valid &= ~BOTH_TIME_SET;
 		err = inode_change_ok(inode, iap);
-		}
+	    }
 	}
 
 	if (err)
@@ -295,8 +289,6 @@
 
 	/* The size case is special. It changes the file as well as the attributes.  */
 	if (iap->ia_valid & ATTR_SIZE) {
-if (!S_ISREG(inode->i_mode))
-printk("nfsd_setattr: size change??\n");
 		if (iap->ia_size < inode->i_size) {
 			err = nfsd_permission(fhp->fh_export, dentry, MAY_TRUNC);
 			if (err)
@@ -380,7 +372,7 @@
 	return err;
 
 out_nfserr:
-	err = nfserrno(-err);
+	err = nfserrno(err);
 	goto out;
 }
 
@@ -412,8 +404,16 @@
 };
 
 static struct accessmap	nfs3_anyaccess[] = {
-    /* XXX: should we try to cover read/write here for clients that
-     * rely on us to do their access checking for special files? */
+	/* Some clients - Solaris 2.6 at least, make an access call
+	 * to the server to check for access for things like /dev/null
+	 * (which really, the server doesn't care about).  So
+	 * We provide simple access checking for them, looking
+	 * mainly at mode bits
+	 */
+    {	NFS3_ACCESS_READ,	MAY_READ			},
+    {	NFS3_ACCESS_EXECUTE,	MAY_EXEC			},
+    {	NFS3_ACCESS_MODIFY,	MAY_WRITE			},
+    {	NFS3_ACCESS_EXTEND,	MAY_WRITE			},
 
     {	0,			0				}
 };
@@ -425,7 +425,7 @@
 	struct svc_export	*export;
 	struct dentry		*dentry;
 	u32			query, result = 0;
-	int			error;
+	unsigned int		error;
 
 	error = fh_verify(rqstp, fhp, 0, MAY_NOP);
 	if (error)
@@ -434,41 +434,45 @@
 	export = fhp->fh_export;
 	dentry = fhp->fh_dentry;
 
-	if (S_ISREG(dentry->d_inode->i_mode)) {
+	if (S_ISREG(dentry->d_inode->i_mode))
 		map = nfs3_regaccess;
-	} else if (S_ISDIR(dentry->d_inode->i_mode)) {
+	else if (S_ISDIR(dentry->d_inode->i_mode))
 		map = nfs3_diraccess;
-	} else {
+	else
 		map = nfs3_anyaccess;
-	}
+
 
 	query = *access;
-	while (map->access) {
+	for  (; map->access; map++) {
 		if (map->access & query) {
 			error = nfsd_permission(export, dentry, (map->how | NO_OWNER_OVERRIDE));
-			if (error == 0)
+			switch(error) {
+			case 0:
 				result |= map->access;
-			else if ((error == nfserr_perm) || (error == nfserr_acces)) {
+				break;
+			case nfserr_perm:
+			case nfserr_acces:
+			case nfserr_rofs:
 				/*
 				 *  This access type is denyed; but the 
 				 *  access query itself succeeds.
 				 */
 				error = 0;
-			} else {
+				break;
+			default:
 				/*
 				 *  Some fatal error.  Fail the query.
 				 */
 				goto out;
 			}
 		}
-		map++;
 	}
 	*access = result;
 
 out:
 	return error;
 }
-#endif
+#endif /* CONFIG_NFSD_V3 */
 
 
 
@@ -532,7 +536,7 @@
 	}
 out_nfserr:
 	if (err)
-		err = nfserrno(-err);
+		err = nfserrno(err);
 out:
 	return err;
 }
@@ -553,9 +557,8 @@
 			dentry->d_parent->d_name.name, dentry->d_name.name);
 	if (filp->f_op && filp->f_op->release)
 		filp->f_op->release(inode, filp);
-	if (filp->f_mode & FMODE_WRITE) {
+	if (filp->f_mode & FMODE_WRITE) 
 		put_write_access(inode);
-	}
 }
 
 /*
@@ -638,7 +641,7 @@
 		goto out_close;
 
 	/* Get readahead parameters */
-	ra = nfsd_get_raparms(fhp->fh_handle.fh_dev, fhp->fh_handle.fh_ino);
+	ra = nfsd_get_raparms(fhp->fh_export->ex_dev, fhp->fh_dentry->d_inode->i_ino);
 	if (ra) {
 		file.f_reada = ra->p_reada;
 		file.f_ramax = ra->p_ramax;
@@ -669,7 +672,7 @@
 		*count = err;
 		err = 0;
 	} else 
-		err = nfserrno(-err);
+		err = nfserrno(err);
 out_close:
 	nfsd_close(&file);
 out:
@@ -683,7 +686,7 @@
  */
 int
 nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
-				char *buf, unsigned long cnt, int stable)
+				char *buf, unsigned long cnt, int *stablep)
 {
 	struct svc_export	*exp;
 	struct file		file;
@@ -691,6 +694,7 @@
 	struct inode		*inode;
 	mm_segment_t		oldfs;
 	int			err = 0;
+	int			stable = *stablep;
 #ifdef CONFIG_QUOTA
 	uid_t			saved_euid;
 #endif
@@ -716,17 +720,16 @@
 	 * When gathered writes have been configured for this volume,
 	 * flushing the data to disk is handled separately below.
 	 */
-#ifdef CONFIG_NFSD_V3
-	if (rqstp->rq_vers == 2)
-		stable = EX_ISSYNC(exp);
-	else if (file.f_op->fsync == 0)
-	       stable = 1;
+
+	if (file.f_op->fsync == 0) {/* COMMIT3 cannot work */
+	       stable = 2;
+	       *stablep = 2; /* FILE_SYNC */
+	}
+
+	if (!EX_ISSYNC(exp))
+		stable = 0;
 	if (stable && !EX_WGATHER(exp))
 		file.f_flags |= O_SYNC;
-#else
-	if ((stable || (stable = EX_ISSYNC(exp))) && !EX_WGATHER(exp))
-		file.f_flags |= O_SYNC;
-#endif /* CONFIG_NFSD_V3 */
 
 	fh_lock(fhp);			/* lock inode */
 	file.f_pos = offset;		/* set write offset */
@@ -787,7 +790,7 @@
 			dprintk("nfsd: write resume %d\n", current->pid);
 		}
 
-		if (inode->i_state & I_DIRTY) {
+		if (EX_WGATHER(exp) && (inode->i_state & I_DIRTY)) {
 			dprintk("nfsd: write sync %d\n", current->pid);
 			nfsd_sync(&file);
 		}
@@ -802,7 +805,7 @@
 	if (err >= 0)
 		err = 0;
 	else 
-		err = nfserrno(-err);
+		err = nfserrno(err);
 out_close:
 	nfsd_close(&file);
 out:
@@ -812,8 +815,8 @@
 
 #ifdef CONFIG_NFSD_V3
 /*
- * Commit all pendig writes to stable storage.
- * Strictly speaking, we could sync just indicated the file region here,
+ * Commit all pending writes to stable storage.
+ * Strictly speaking, we could sync just the indicated file region here,
  * but there's currently no way we can ask the VFS to do so.
  *
  * We lock the file to make sure we return full WCC data to the client.
@@ -827,14 +830,15 @@
 
 	if ((err = nfsd_open(rqstp, fhp, S_IFREG, MAY_WRITE, &file)) != 0)
 		return err;
-
-	fh_lock(fhp);
-	if (file.f_op && file.f_op->fsync) {
-		file.f_op->fsync(&file, file.f_dentry);
-	} else {
-		err = nfserr_notsupp;
+	if (EX_ISSYNC(fhp->fh_export)) {
+		fh_lock(fhp);
+		if (file.f_op && file.f_op->fsync) {
+			file.f_op->fsync(&file, file.f_dentry);
+		} else {
+			err = nfserr_notsupp;
+		}
+		fh_unlock(fhp);
 	}
-	fh_unlock(fhp);
 
 	nfsd_close(&file);
 	return err;
@@ -862,6 +866,9 @@
 	err = nfserr_perm;
 	if (!flen)
 		goto out;
+	err = nfserr_exist;
+	if (isdotent(fname, flen))
+		goto out;
 
 	err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE);
 	if (err)
@@ -873,10 +880,6 @@
 	err = nfserr_notdir;
 	if(!dirp->i_op || !dirp->i_op->lookup)
 		goto out;
-
-	err = nfserr_exist;
-	if (isdotent(fname, flen))
-		goto out;
 	/*
 	 * Check whether the response file handle has been verified yet.
 	 * If it has, the parent directory should already be locked.
@@ -901,7 +904,7 @@
 				dentry->d_name.name);
 			err = -EIO;
 			goto out;
-	}
+		}
 	}
 	/*
 	 * Make sure the child dentry is still negative ...
@@ -959,10 +962,6 @@
 		write_inode_now(dchild->d_inode);
 	}
 
-	/*
-	 * Update the file handle to get the new inode info.
-	 */
-	fh_update(resfhp);
 
 	/* Set file attributes. Mode has already been set and
 	 * setting uid/gid works only for root. Irix appears to
@@ -972,11 +971,15 @@
 	err = 0;
 	if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0)
 		err = nfsd_setattr(rqstp, resfhp, iap);
+	/*
+	 * Update the file handle to get the new inode info.
+	 */
+	fh_update(resfhp);
 out:
 	return err;
 
 out_nfserr:
-	err = nfserrno(-err);
+	err = nfserrno(err);
 	goto out;
 }
 
@@ -992,10 +995,15 @@
 	struct dentry	*dentry, *dchild;
 	struct inode	*dirp;
 	int		err;
+	__u32		v_mtime=0, v_atime=0;
+	int		v_mode=0;
 
 	err = nfserr_perm;
 	if (!flen)
 		goto out;
+	err = nfserr_exist;
+	if (isdotent(fname, flen))
+		goto out;
 	if (!(iap->ia_valid & ATTR_MODE))
 		iap->ia_mode = 0;
 	err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE);
@@ -1014,9 +1022,6 @@
 	if(!dirp->i_op->create)
 		goto out;
 
-	err = nfserr_exist;
-	if (isdotent(fname, flen))
-		goto out;
 	/*
 	 * Compose the response file handle.
 	 */
@@ -1033,6 +1038,19 @@
 	if (err)
 	    goto out;
 
+	if (createmode == NFS3_CREATE_EXCLUSIVE) {
+		/* while the verifier would fit in mtime+atime,
+		 * solaris7 gets confused (bugid 4218508) if these have
+		 * the high bit set, so we use the mode as well
+		 */
+		v_mtime = verifier[0]&0x7fffffff;
+		v_atime = verifier[1]&0x7fffffff;
+		v_mode  = S_IFREG
+			| ((verifier[0]&0x80000000) >> (32-7)) /* u+x */
+			| ((verifier[1]&0x80000000) >> (32-9)) /* u+r */
+			;
+	}
+	
 	if (dchild->d_inode) {
 		err = 0;
 
@@ -1050,10 +1068,10 @@
 			}
 			break;
 		case NFS3_CREATE_EXCLUSIVE:
-			if (   dchild->d_inode->i_mtime == verifier[0]
-			    && dchild->d_inode->i_atime == verifier[1]
-			    && dchild->d_inode->i_mode == S_IFREG
-			    && dchild->d_inode->i_size == 0 )
+			if (   dchild->d_inode->i_mtime == v_mtime
+			    && dchild->d_inode->i_atime == v_atime
+			    && dchild->d_inode->i_mode  == v_mode
+			    && dchild->d_inode->i_size  == 0 )
 				break;
 			 /* fallthru */
 		case NFS3_CREATE_GUARDED:
@@ -1078,19 +1096,23 @@
 	err = 0;
 
 	if (createmode == NFS3_CREATE_EXCLUSIVE) {
-		/* Cram the verifier into atime/mtime */
-		iap->ia_valid = ATTR_MTIME|ATTR_ATIME|ATTR_MTIME_SET|ATTR_ATIME_SET;
-		iap->ia_mtime = verifier[0];
-		iap->ia_atime = verifier[1];
+		/* Cram the verifier into atime/mtime/mode */
+		iap->ia_valid = ATTR_MTIME|ATTR_ATIME
+			| ATTR_MTIME_SET|ATTR_ATIME_SET
+			| ATTR_MODE;
+		iap->ia_mtime = v_mtime;
+		iap->ia_atime = v_atime;
+		iap->ia_mode  = v_mode;
 	}
 
-	/* Set file attributes. Mode has already been set and
-	 * setting uid/gid works only for root. Irix appears to
-	 * send along the gid when it tries to implement setgid
-	 * directories via NFS. Clear out all that cruft.
+	/* Set file attributes.
+	 * Mode has already been set but we might need to reset it
+	 * for CREATE_EXCLUSIVE
+	 * Irix appears to send along the gid when it tries to
+	 * implement setgid directories via NFS. Clear out all that cruft.
 	 */
  set_attr:
-	if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0)
+	if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID)) != 0)
  		err = nfsd_setattr(rqstp, resfhp, iap);
 
  out:
@@ -1098,68 +1120,12 @@
  	return err;
  
  out_nfserr:
-	err = nfserrno(-err);
+	err = nfserrno(err);
 	goto out;
 }
 #endif /* CONFIG_NFSD_V3 */
 
 /*
- * Truncate a file.
- * The calling routines must make sure to update the ctime
- * field and call notify_change.
- *
- * XXX Nobody calls this thing? -DaveM
- * N.B. After this call fhp needs an fh_put
- */
-int
-nfsd_truncate(struct svc_rqst *rqstp, struct svc_fh *fhp, unsigned long size)
-{
-	struct dentry	*dentry;
-	struct inode	*inode;
-	struct iattr	newattrs;
-	int		err;
-	kernel_cap_t	saved_cap = 0;
-
-	err = fh_verify(rqstp, fhp, S_IFREG, MAY_WRITE | MAY_TRUNC);
-	if (err)
-		goto out;
-
-	dentry = fhp->fh_dentry;
-	inode = dentry->d_inode;
-
-	err = get_write_access(inode);
-	if (err)
-		goto out_nfserr;
-
-	/* Things look sane, lock and do it. */
-	fh_lock(fhp);
-	DQUOT_INIT(inode);
-	newattrs.ia_size = size;
-	newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
-	if (current->fsuid != 0) {
-		saved_cap = current->cap_effective;
-		cap_clear(current->cap_effective);
-	}
-	err = notify_change(dentry, &newattrs);
-	if (!err) {
-		vmtruncate(inode, size);
-		if (inode->i_op && inode->i_op->truncate)
-			inode->i_op->truncate(inode);
-	}
-	if (current->fsuid != 0)
-		current->cap_effective = saved_cap;
-	put_write_access(inode);
-	if (EX_ISSYNC(fhp->fh_export))
-		nfsd_sync_dir(dentry);
-	fh_unlock(fhp);
-out_nfserr:
-	if (err)
-		err = nfserrno(-err);
-out:
-	return err;
-}
-
-/*
  * Read a symlink. On entry, *lenp must contain the maximum path length that
  * fits into the buffer. On return, it contains the true length.
  * N.B. After this call fhp needs an fh_put
@@ -1172,7 +1138,7 @@
 	mm_segment_t	oldfs;
 	int		err;
 
-	err = fh_verify(rqstp, fhp, S_IFLNK, MAY_READ);
+	err = fh_verify(rqstp, fhp, S_IFLNK, MAY_NOP);
 	if (err)
 		goto out;
 
@@ -1200,7 +1166,7 @@
 	return err;
 
 out_nfserr:
-	err = nfserrno(-err);
+	err = nfserrno(err);
 	goto out;
 }
 
@@ -1223,15 +1189,15 @@
 	if (!flen || !plen)
 		goto out;
 
+	err = nfserr_exist;
+	if (isdotent(fname, flen))
+		goto out;
+
 	err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE);
 	if (err)
 		goto out;
 	dentry = fhp->fh_dentry;
 
-	err = nfserr_exist;
-	if (isdotent(fname, flen))
-		goto out;
-
 	err = nfserr_perm;
 	dirp = dentry->d_inode;
 	if (!dirp->i_op	|| !dirp->i_op->symlink)
@@ -1268,7 +1234,7 @@
 			       }
 			}
 		} else
-			err = nfserrno(-err);
+			err = nfserrno(err);
 	}
 	fh_unlock(fhp);
 
@@ -1280,7 +1246,7 @@
 	return err;
 
 out_nfserr:
-	err = nfserrno(-err);
+	err = nfserrno(err);
 	goto out;
 }
 
@@ -1299,6 +1265,11 @@
 	err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_CREATE);
 	if (err)
 		goto out;
+
+	err = nfserr_exist;
+	if (isdotent(fname, flen))
+		goto out;
+
 	err = fh_verify(rqstp, tfhp, -S_IFDIR, MAY_NOP);
 	if (err)
 		goto out;
@@ -1307,10 +1278,6 @@
 	if (!flen)
 		goto out;
 
-	err = nfserr_exist;
-	if (isdotent(fname, flen))
-		goto out;
-
 	ddir = ffhp->fh_dentry;
 	dirp = ddir->d_inode;
 
@@ -1350,7 +1317,7 @@
 			write_inode_now(dest);
 		}
 	} else
-		err = nfserrno(-err);
+		err = nfserrno(err);
 
 out_unlock:
 	fh_unlock(ffhp);
@@ -1360,7 +1327,7 @@
 	return err;
 
 out_nfserr:
-	err = nfserrno(-err);
+	err = nfserrno(err);
 	goto out;
 }
 
@@ -1478,7 +1445,7 @@
 	return err;
 
 out_nfserr:
-	err = nfserrno(-err);
+	err = nfserrno(err);
 	goto out;
 }
 
@@ -1494,13 +1461,14 @@
 	struct inode	*dirp;
 	int		err;
 
-	err = fh_verify(rqstp, fhp, S_IFDIR, MAY_REMOVE);
-	if (err)
-		goto out;
 	err = nfserr_acces;
 	if (!flen || isdotent(fname, flen))
 		goto out;
 
+	err = fh_verify(rqstp, fhp, S_IFDIR, MAY_REMOVE);
+	if (err)
+		goto out;
+
 	dentry = fhp->fh_dentry;
 	dirp = dentry->d_inode;
 
@@ -1520,8 +1488,10 @@
 		/* It's UNLINK */
 
 		err = fh_lock_parent(fhp, rdentry);
-		if (err)
+		if (err) {
+			dput(rdentry);
 			goto out;
+		}
 
 		err = vfs_unlink(dirp, rdentry);
 
@@ -1568,7 +1538,7 @@
 	return err;
 
 out_nfserr:
-	err = nfserrno(-err);
+	err = nfserrno(err);
 	goto out;
 }
 
@@ -1610,6 +1580,7 @@
 	 * may choose to do less.
 	 */
 	inode = file.f_dentry->d_inode;
+	down(&inode->i_sem);
 	while (1) {
 		oldlen = cd.buflen;
 
@@ -1618,9 +1589,7 @@
 			file.f_inode->i_dev, file.f_inode->i_ino,
 			(int) file.f_pos, (int) oldlen, (int) cd.buflen);
 		 */
-		down(&inode->i_sem);
 		err = file.f_op->readdir(&file, &cd, (filldir_t) func);
-		up(&inode->i_sem);
 		if (err < 0)
 			goto out_nfserr;
 		if (oldlen == cd.buflen)
@@ -1628,16 +1597,15 @@
 		if (cd.eob)
 			break;
 	}
+	up(&inode->i_sem);
 
 	/* If we didn't fill the buffer completely, we're at EOF */
 	eof = !cd.eob;
 
 	if (cd.offset) {
-#ifdef CONFIG_NFSD_V3
 		if (rqstp->rq_vers == 3)
-			(void)enc64(cd.offset, file.f_pos);
+			(void)xdr_encode_hyper(cd.offset, file.f_pos);
 		else
-#endif /* CONFIG_NFSD_V3 */
 			*cd.offset = htonl(file.f_pos);
 	}
 
@@ -1656,7 +1624,8 @@
 	return err;
 
 out_nfserr:
-	err = nfserrno(-err);
+	up(&inode->i_sem);
+	err = nfserrno(err);
 	goto out_close;
 }
 
@@ -1737,12 +1706,17 @@
 		inode->i_uid, inode->i_gid, current->fsuid, current->fsgid);
 #endif
 
-	if (acc & (MAY_WRITE | MAY_SATTR | MAY_TRUNC)) {
-		if (EX_RDONLY(exp) || IS_RDONLY(inode))
-			return nfserr_rofs;
-		if (/* (acc & MAY_WRITE) && */ IS_IMMUTABLE(inode))
-			return nfserr_perm;
-	}
+	/* only care about readonly exports for files and
+	 * directories. links don't have meaningful write access,
+	 * and all else is local to the client
+	 */
+	if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)) 
+		if (acc & (MAY_WRITE | MAY_SATTR | MAY_TRUNC)) {
+			if (EX_RDONLY(exp) || IS_RDONLY(inode))
+				return nfserr_rofs;
+			if (/* (acc & MAY_WRITE) && */ IS_IMMUTABLE(inode))
+				return nfserr_perm;
+		}
 	if ((acc & MAY_TRUNC) && IS_APPEND(inode))
 		return nfserr_perm;
 
@@ -1786,7 +1760,7 @@
 	if (current->fsuid != 0)
 		current->cap_effective = saved_cap;
 
-	return err? nfserrno(-err) : 0;
+	return err? nfserrno(err) : 0;
 }
 
 void
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nls/Config.in linux.19p18/fs/nls/Config.in
--- linux.vanilla/fs/nls/Config.in	Mon Dec 11 22:13:03 2000
+++ linux.19p18/fs/nls/Config.in	Wed Jan  3 01:04:07 2001
@@ -47,5 +47,6 @@
   tristate 'NLS ISO 8859-14 (Latin 8; Celtic)'      CONFIG_NLS_ISO8859_14
   tristate 'NLS ISO 8859-15 (Latin 9; Western European Languages with Euro)' CONFIG_NLS_ISO8859_15
   tristate 'NLS KOI8-R (Russian)'                   CONFIG_NLS_KOI8_R
+  tristate 'NLS KOI8-RU (Belorussia, Ukraine)'      CONFIG_NLS_KOI8_RU
   endmenu
 fi
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nls/Makefile linux.19p18/fs/nls/Makefile
--- linux.vanilla/fs/nls/Makefile	Sun Jun 11 21:44:19 2000
+++ linux.19p18/fs/nls/Makefile	Wed Jan  3 01:05:38 2001
@@ -342,6 +342,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_NLS_KOI8_RU),y)
+NLS += nls_koi8-ru.o
+else
+  ifeq ($(CONFIG_NLS_KOI8_RU),m)
+  M_OBJS += nls_koi8-ru.o
+  endif
+endif
+
 O_TARGET = nls.o
 OX_OBJS  = $(NLS)
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nls/nls_base.c linux.19p18/fs/nls/nls_base.c
--- linux.vanilla/fs/nls/nls_base.c	Mon Dec 11 22:13:03 2000
+++ linux.19p18/fs/nls/nls_base.c	Wed Jan  3 01:04:48 2001
@@ -529,6 +529,9 @@
 #ifdef CONFIG_NLS_KOI8_R
 	init_nls_koi8_r();
 #endif
+#ifdef CONFIG_NLS_KOI8_RU
+	init_nls_koi8_ru();
+#endif
 	return 0;
 }
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/nls/nls_koi8-ru.c linux.19p18/fs/nls/nls_koi8-ru.c
--- linux.vanilla/fs/nls/nls_koi8-ru.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/fs/nls/nls_koi8-ru.c	Wed Jan  3 01:04:24 2001
@@ -0,0 +1,401 @@
+/*
+ * linux/fs/nls_koi8-r.c
+ *
+ * Charset koi8-r translation tables.
+ * Generated automatically from the Unicode and charset
+ * tables from the Unicode Organization (www.unicode.org).
+ * The Unicode to charset table has only exact mappings.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/nls.h>
+#include <linux/init.h>
+
+static struct nls_unicode charset2uni[256] = {
+	/* 0x00*/
+	{0x00, 0x00}, {0x01, 0x00}, {0x02, 0x00}, {0x03, 0x00},
+	{0x04, 0x00}, {0x05, 0x00}, {0x06, 0x00}, {0x07, 0x00},
+	{0x08, 0x00}, {0x09, 0x00}, {0x0a, 0x00}, {0x0b, 0x00},
+	{0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+	/* 0x10*/
+	{0x10, 0x00}, {0x11, 0x00}, {0x12, 0x00}, {0x13, 0x00},
+	{0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x17, 0x00},
+	{0x18, 0x00}, {0x19, 0x00}, {0x1a, 0x00}, {0x1b, 0x00},
+	{0x1c, 0x00}, {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+	/* 0x20*/
+	{0x20, 0x00}, {0x21, 0x00}, {0x22, 0x00}, {0x23, 0x00},
+	{0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00},
+	{0x28, 0x00}, {0x29, 0x00}, {0x2a, 0x00}, {0x2b, 0x00},
+	{0x2c, 0x00}, {0x2d, 0x00}, {0x2e, 0x00}, {0x2f, 0x00},
+	/* 0x30*/
+	{0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+	{0x34, 0x00}, {0x35, 0x00}, {0x36, 0x00}, {0x37, 0x00},
+	{0x38, 0x00}, {0x39, 0x00}, {0x3a, 0x00}, {0x3b, 0x00},
+	{0x3c, 0x00}, {0x3d, 0x00}, {0x3e, 0x00}, {0x3f, 0x00},
+	/* 0x40*/
+	{0x40, 0x00}, {0x41, 0x00}, {0x42, 0x00}, {0x43, 0x00},
+	{0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x47, 0x00},
+	{0x48, 0x00}, {0x49, 0x00}, {0x4a, 0x00}, {0x4b, 0x00},
+	{0x4c, 0x00}, {0x4d, 0x00}, {0x4e, 0x00}, {0x4f, 0x00},
+	/* 0x50*/
+	{0x50, 0x00}, {0x51, 0x00}, {0x52, 0x00}, {0x53, 0x00},
+	{0x54, 0x00}, {0x55, 0x00}, {0x56, 0x00}, {0x57, 0x00},
+	{0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x00}, {0x5b, 0x00},
+	{0x5c, 0x00}, {0x5d, 0x00}, {0x5e, 0x00}, {0x5f, 0x00},
+	/* 0x60*/
+	{0x60, 0x00}, {0x61, 0x00}, {0x62, 0x00}, {0x63, 0x00},
+	{0x64, 0x00}, {0x65, 0x00}, {0x66, 0x00}, {0x67, 0x00},
+	{0x68, 0x00}, {0x69, 0x00}, {0x6a, 0x00}, {0x6b, 0x00},
+	{0x6c, 0x00}, {0x6d, 0x00}, {0x6e, 0x00}, {0x6f, 0x00},
+	/* 0x70*/
+	{0x70, 0x00}, {0x71, 0x00}, {0x72, 0x00}, {0x73, 0x00},
+	{0x74, 0x00}, {0x75, 0x00}, {0x76, 0x00}, {0x77, 0x00},
+	{0x78, 0x00}, {0x79, 0x00}, {0x7a, 0x00}, {0x7b, 0x00},
+	{0x7c, 0x00}, {0x7d, 0x00}, {0x7e, 0x00}, {0x7f, 0x00},
+	/* 0x80*/
+	{0x00, 0x25}, {0x02, 0x25}, {0x0c, 0x25}, {0x10, 0x25},
+	{0x14, 0x25}, {0x18, 0x25}, {0x1c, 0x25}, {0x24, 0x25},
+	{0x2c, 0x25}, {0x34, 0x25}, {0x3c, 0x25}, {0x80, 0x25},
+	{0x84, 0x25}, {0x88, 0x25}, {0x8c, 0x25}, {0x90, 0x25},
+	/* 0x90*/
+	{0x91, 0x25}, {0x92, 0x25}, {0x93, 0x25}, {0x20, 0x23},
+	{0xa0, 0x25}, {0x19, 0x22}, {0x1a, 0x22}, {0x48, 0x22},
+	{0x64, 0x22}, {0x65, 0x22}, {0xa0, 0x00}, {0x21, 0x23},
+	{0xb0, 0x00}, {0xb2, 0x00}, {0xb7, 0x00}, {0xf7, 0x00},
+	/* 0xa0*/
+	{0x50, 0x25}, {0x51, 0x25}, {0x52, 0x25}, {0x51, 0x04},
+	{0x54, 0x04}, {0x54, 0x25}, {0x56, 0x04}, {0x57, 0x04},
+	{0x57, 0x25}, {0x58, 0x25}, {0x59, 0x25}, {0x5a, 0x25},
+	{0x5b, 0x25}, {0x91, 0x04}, {0x5e, 0x04}, {0x5e, 0x25},
+	/* 0xb0*/
+	{0x5f, 0x25}, {0x60, 0x25}, {0x61, 0x25}, {0x01, 0x04},
+	{0x04, 0x04}, {0x63, 0x25}, {0x06, 0x04}, {0x07, 0x04},
+	{0x66, 0x25}, {0x67, 0x25}, {0x68, 0x25}, {0x69, 0x25},
+	{0x6a, 0x25}, {0x90, 0x04}, {0x0e, 0x04}, {0xa9, 0x00},
+	/* 0xc0*/
+	{0x4e, 0x04}, {0x30, 0x04}, {0x31, 0x04}, {0x46, 0x04},
+	{0x34, 0x04}, {0x35, 0x04}, {0x44, 0x04}, {0x33, 0x04},
+	{0x45, 0x04}, {0x38, 0x04}, {0x39, 0x04}, {0x3a, 0x04},
+	{0x3b, 0x04}, {0x3c, 0x04}, {0x3d, 0x04}, {0x3e, 0x04},
+	/* 0xd0*/
+	{0x3f, 0x04}, {0x4f, 0x04}, {0x40, 0x04}, {0x41, 0x04},
+	{0x42, 0x04}, {0x43, 0x04}, {0x36, 0x04}, {0x32, 0x04},
+	{0x4c, 0x04}, {0x4b, 0x04}, {0x37, 0x04}, {0x48, 0x04},
+	{0x4d, 0x04}, {0x49, 0x04}, {0x47, 0x04}, {0x4a, 0x04},
+	/* 0xe0*/
+	{0x2e, 0x04}, {0x10, 0x04}, {0x11, 0x04}, {0x26, 0x04},
+	{0x14, 0x04}, {0x15, 0x04}, {0x24, 0x04}, {0x13, 0x04},
+	{0x25, 0x04}, {0x18, 0x04}, {0x19, 0x04}, {0x1a, 0x04},
+	{0x1b, 0x04}, {0x1c, 0x04}, {0x1d, 0x04}, {0x1e, 0x04},
+	/* 0xf0*/
+	{0x1f, 0x04}, {0x2f, 0x04}, {0x20, 0x04}, {0x21, 0x04},
+	{0x22, 0x04}, {0x23, 0x04}, {0x16, 0x04}, {0x12, 0x04},
+	{0x2c, 0x04}, {0x2b, 0x04}, {0x17, 0x04}, {0x28, 0x04},
+	{0x2d, 0x04}, {0x29, 0x04}, {0x27, 0x04}, {0x2a, 0x04},
+};
+
+static unsigned char page00[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x9c, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x00, 0x9e, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page04[256] = {
+	0x00, 0xb3, 0x00, 0xb4, 0x00, 0xb6, 0xb7, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, /* 0x08-0x0f */
+	0xe1, 0xe2, 0xf7, 0xe7, 0xe4, 0xe5, 0xf6, 0xfa, /* 0x10-0x17 */
+	0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, /* 0x18-0x1f */
+	0xf2, 0xf3, 0xf4, 0xf5, 0xe6, 0xe8, 0xe3, 0xfe, /* 0x20-0x27 */
+	0xfb, 0xfd, 0xff, 0xf9, 0xf8, 0xfc, 0xe0, 0xf1, /* 0x28-0x2f */
+	0xc1, 0xc2, 0xd7, 0xc7, 0xc4, 0xc5, 0xd6, 0xda, /* 0x30-0x37 */
+	0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, /* 0x38-0x3f */
+	0xd2, 0xd3, 0xd4, 0xd5, 0xc6, 0xc8, 0xc3, 0xde, /* 0x40-0x47 */
+	0xdb, 0xdd, 0xdf, 0xd9, 0xd8, 0xdc, 0xc0, 0xd1, /* 0x48-0x4f */
+	0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa6, 0xa7, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0xbd, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page22[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x95, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x98, 0x99, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page23[256] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x93, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char page25[256] = {
+	0x80, 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+	0x00, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+	0x83, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+	0x85, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+	0x00, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+	0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+	0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+	0x00, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+	0xa0, 0xa1, 0xa2, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, /* 0x50-0x57 */
+	0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, /* 0x58-0x5f */
+	0xb1, 0xb2, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, /* 0x60-0x67 */
+	0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+	0x8b, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+	0x8d, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+	0x8f, 0x90, 0x91, 0x92, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+	0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */
+};
+
+static unsigned char *page_uni2charset[256] = {
+	page00, NULL,   NULL,   NULL,   page04, NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   NULL,   
+	NULL,   NULL,   page22, page23, NULL,   page25, NULL,   NULL,   
+};
+
+#if 0
+static unsigned char charset2upper[256] = {
+	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+	0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+	0x00, 0x00, 0x00, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */
+	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */
+	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */
+	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */
+	0xa0, 0xa1, 0xa2, 0x00, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */
+	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */
+	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */
+	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */
+	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */
+	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */
+	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */
+	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */
+};
+#endif
+
+static void uni2char(unsigned char ch, unsigned char cl, unsigned char *out, int boundlen, int *outlen)
+{
+	unsigned char *uni2charset;
+
+	if (boundlen <= 0)
+		return;
+
+	uni2charset = page_uni2charset[ch];
+	if (uni2charset && uni2charset[cl])
+		out[0] = uni2charset[cl];
+	else
+		out[0] = '?';
+	*outlen = 1;
+	return;
+}
+
+static void char2uni(const unsigned char *rawstring, int *offset, unsigned char *uni1, unsigned char *uni2)
+{
+	*uni1 = charset2uni[*rawstring].uni1;
+	*uni2 = charset2uni[*rawstring].uni2;
+	*offset = 1;
+	return;
+}
+
+static void inc_use_count(void)
+{
+	MOD_INC_USE_COUNT;
+}
+
+static void dec_use_count(void)
+{
+	MOD_DEC_USE_COUNT;
+}
+
+static struct nls_table table = {
+	"koi8-ru",
+	uni2char,
+	char2uni,
+	inc_use_count,
+	dec_use_count,
+	NULL
+};
+
+int __init init_nls_koi8_ru(void)
+{
+	return register_nls(&table);
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return init_nls_koi8_ru();
+}
+
+
+void cleanup_module(void)
+{
+	unregister_nls(&table);
+	return;
+}
+#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/open.c linux.19p18/fs/open.c
--- linux.vanilla/fs/open.c	Mon Dec 11 22:13:05 2000
+++ linux.19p18/fs/open.c	Sat Dec 16 17:21:47 2000
@@ -73,7 +73,7 @@
 	if ((off_t) length < 0)
 		return -EINVAL;
 
-	down(&inode->i_sem);
+	fs_down(&inode->i_sem);
 	newattrs.ia_size = length;
 	newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
 	error = notify_change(dentry, &newattrs);
@@ -83,7 +83,7 @@
 		if (inode->i_op && inode->i_op->truncate)
 			inode->i_op->truncate(inode);
 	}
-	up(&inode->i_sem);
+	fs_up(&inode->i_sem);
 	return error;
 }
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/proc/array.c linux.19p18/fs/proc/array.c
--- linux.vanilla/fs/proc/array.c	Mon Dec 11 22:13:05 2000
+++ linux.19p18/fs/proc/array.c	Tue Feb 20 13:27:21 2001
@@ -1329,7 +1329,7 @@
 extern int get_ksyms_list(char *, char **, off_t, int);
 #endif
 extern int get_device_list(char *);
-extern int get_partition_list(char *);
+extern int get_partition_list(char *, char **, off_t, int);
 extern int get_filesystem_list(char *);
 extern int get_filesystem_info( char * );
 #ifndef CONFIG_ARCH_S390
@@ -1397,7 +1397,7 @@
 			return get_device_list(page);
 
 		case PROC_PARTITIONS:
-			return get_partition_list(page);
+			return get_partition_list(page, start, offset, length);
 #ifndef CONFIG_ARCH_S390
 		case PROC_INTERRUPTS:
 			return get_irq_list(page);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/read_write.c linux.19p18/fs/read_write.c
--- linux.vanilla/fs/read_write.c	Sat Sep  9 18:42:49 2000
+++ linux.19p18/fs/read_write.c	Sat Dec 16 17:21:47 2000
@@ -166,9 +166,9 @@
 	if (!file->f_op || !(write = file->f_op->write))
 		goto out;
 
-	down(&inode->i_sem);
+	fs_down(&inode->i_sem);
 	ret = write(file, buf, count, &file->f_pos);
-	up(&inode->i_sem);
+	fs_up(&inode->i_sem);
 out:
 	fput(file);
 bad_file:
@@ -314,9 +314,9 @@
 	if (!file)
 		goto bad_file;
 	if (file->f_op && file->f_op->write && (file->f_mode & FMODE_WRITE)) {
-		down(&file->f_dentry->d_inode->i_sem);
+		fs_down(&file->f_dentry->d_inode->i_sem);
 		ret = do_readv_writev(VERIFY_READ, file, vector, count);
-		up(&file->f_dentry->d_inode->i_sem);
+		fs_up(&file->f_dentry->d_inode->i_sem);
 	}
 	fput(file);
 
@@ -386,9 +386,9 @@
 	if (pos < 0)
 		goto out;
 
-	down(&file->f_dentry->d_inode->i_sem);
+	fs_down(&file->f_dentry->d_inode->i_sem);
 	ret = write(file, buf, count, &pos);
-	up(&file->f_dentry->d_inode->i_sem);
+	fs_up(&file->f_dentry->d_inode->i_sem);
 
 out:
 	fput(file);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/smbfs/ChangeLog linux.19p18/fs/smbfs/ChangeLog
--- linux.vanilla/fs/smbfs/ChangeLog	Mon Dec 11 22:13:05 2000
+++ linux.19p18/fs/smbfs/ChangeLog	Tue Dec 19 02:06:27 2000
@@ -1,5 +1,10 @@
 ChangeLog for smbfs.
 
+2000-11-22 Igor Zhbanov <bsg@uniyar.ac.ru>
+
+	* proc.c: fixed date_unix2dos for dates earlier than 01/01/1980
+	  and date_dos2unix for date==0
+
 2000-11-04 Urban Widmark <urban@svenskatest.se>
 
 	* proc.c, sock.c: adjust max parameters & max data to follow max_xmit
@@ -41,7 +46,7 @@
 	* proc.c: removed support for old protocol levels. It didn't work
 	  anyway and was cluttering things up a lot.
 
-2000-01-?? cpg@aladdin.de
+2000-01-03 Christian Groessler <cpg@aladdin.de>
 
 	* proc.c: added posix semantics for unlink
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/fs/smbfs/proc.c linux.19p18/fs/smbfs/proc.c
--- linux.vanilla/fs/smbfs/proc.c	Mon Dec 11 22:13:05 2000
+++ linux.19p18/fs/smbfs/proc.c	Tue Dec 19 02:06:27 2000
@@ -280,7 +280,9 @@
 	int month, year;
 	time_t secs;
 
-	month = ((date >> 5) & 15) - 1;
+	/* first subtract and mask after that... Otherwise, if
+	   date == 0, bad things happen */
+	month = ((date >> 5) - 1) & 15;
 	year = date >> 9;
 	secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 + 86400 *
 	    ((date & 31) - 1 + day_n[month] + (year / 4) + year * 365 - ((year & 3) == 0 &&
@@ -299,6 +301,11 @@
 	int day, year, nl_day, month;
 
 	unix_date = utc2local(server, unix_date);
+
+	/* Jan 1 GMT 00:00:00 1980. But what about another time zone? */
+	if (unix_date < 315532800)
+		unix_date = 315532800;
+
 	*time = (unix_date % 60) / 2 +
 		(((unix_date / 60) % 60) << 5) +
 		(((unix_date / 3600) % 24) << 11);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-alpha/mmu_context.h linux.19p18/include/asm-alpha/mmu_context.h
--- linux.vanilla/include/asm-alpha/mmu_context.h	Fri Apr 21 12:46:47 2000
+++ linux.19p18/include/asm-alpha/mmu_context.h	Wed Jan  3 13:33:37 2001
@@ -65,12 +65,7 @@
 #endif /* __SMP__ */
 
 #define WIDTH_HARDWARE_ASN	8
-#ifdef __SMP__
-#define WIDTH_THIS_PROCESSOR	5
-#else
-#define WIDTH_THIS_PROCESSOR	0
-#endif
-#define ASN_FIRST_VERSION (1UL << (WIDTH_THIS_PROCESSOR + WIDTH_HARDWARE_ASN))
+#define ASN_FIRST_VERSION (1UL << WIDTH_HARDWARE_ASN)
 #define HARDWARE_ASN_MASK ((1UL << WIDTH_HARDWARE_ASN) - 1)
 
 /*
@@ -100,6 +95,7 @@
 	/* If we've wrapped, flush the whole user TLB.  */
 	if ((asn & HARDWARE_ASN_MASK) >= MAX_ASN) {
 		tbiap();
+		imb();
 		next = (asn & ~HARDWARE_ASN_MASK) + ASN_FIRST_VERSION;
 	}
 	cpu_last_asn(smp_processor_id()) = next;
@@ -125,19 +121,21 @@
 __EXTERN_INLINE void
 ev5_get_mmu_context(struct task_struct *p)
 {
-	/* Check if our ASN is of an older version, or on a different CPU,
-	   and thus invalid.  */
-	/* ??? If we have two threads on different cpus, we'll continually
-	   fight over the context.  Find a way to record a per-mm, per-cpu
-	   value for the asn.  */
-
-	unsigned long asn = cpu_last_asn(smp_processor_id());
-	struct mm_struct *mm = p->mm;
-	unsigned long mmc = mm->context;
+	/* Check if our ASN is of an older version, and thus invalid. */
+	int cpu;
+	unsigned long asn;
+	struct mm_struct *mm;
+	unsigned long mmc;
 	
+	cpu = smp_processor_id();
+	mm = p->mm;
+	ctx_cli();
+	asn = cpu_last_asn(cpu);
+	mmc = mm->context[cpu];
+
 	if ((mmc ^ asn) & ~HARDWARE_ASN_MASK) {
 		mmc = __get_new_mmu_context();
-		mm->context = mmc;
+		mm->context[cpu] = mmc;
 	}
 
 	/* Always update the PCB ASN.  Another thread may have allocated
@@ -159,7 +157,10 @@
 extern inline void
 init_new_context(struct mm_struct *mm)
 {
-	mm->context = 0;
+	int i;
+
+	for (i = 0; i < smp_num_cpus; i++)
+		mm->context[cpu_logical_map(i)] = 0;
 }
 
 extern inline void
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-alpha/page.h linux.19p18/include/asm-alpha/page.h
--- linux.vanilla/include/asm-alpha/page.h	Mon Dec 11 22:13:05 2000
+++ linux.19p18/include/asm-alpha/page.h	Wed Feb 14 14:25:46 2001
@@ -120,6 +120,10 @@
 #endif /* STRICT_MM_TYPECHECKS */
 #endif /* !ASSEMBLY */
 
+#if !defined(BUG)
+#define BUG()		__asm__ __volatile__("call_pal 129 # bugchk")
+#endif
+
 /* to align the pointer to the (next) page boundary */
 #define PAGE_ALIGN(addr)	(((addr)+PAGE_SIZE-1)&PAGE_MASK)
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-alpha/pgtable.h linux.19p18/include/asm-alpha/pgtable.h
--- linux.vanilla/include/asm-alpha/pgtable.h	Sun Jun 11 21:44:22 2000
+++ linux.19p18/include/asm-alpha/pgtable.h	Wed Jan  3 13:33:37 2001
@@ -73,7 +73,13 @@
 __EXTERN_INLINE void
 ev5_flush_tlb_other(struct mm_struct *mm)
 {
-	mm->context = 0;
+	long * mmc = &mm->context[smp_processor_id()];
+	/*
+	 * Check it's not zero first to avoid cacheline ping pong when
+	 * possible.
+	 */
+	if (*mmc)
+		*mmc = 0;
 }
 
 /*
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-alpha/ptrace.h linux.19p18/include/asm-alpha/ptrace.h
--- linux.vanilla/include/asm-alpha/ptrace.h	Fri Apr 21 12:46:47 2000
+++ linux.19p18/include/asm-alpha/ptrace.h	Wed Jan  3 13:37:59 2001
@@ -70,6 +70,7 @@
 #define user_mode(regs) (((regs)->ps & 8) != 0)
 #define instruction_pointer(regs) ((regs)->pc)
 extern void show_regs(struct pt_regs *);
+extern void __show_regs(struct pt_regs *);
 #endif
 
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-alpha/siginfo.h linux.19p18/include/asm-alpha/siginfo.h
--- linux.vanilla/include/asm-alpha/siginfo.h	Fri Apr 21 12:46:47 2000
+++ linux.19p18/include/asm-alpha/siginfo.h	Tue Feb 27 21:59:16 2001
@@ -89,8 +89,8 @@
 #define SI_ASYNCIO	-4	/* sent by AIO completion */
 #define SI_SIGIO	-5	/* sent by queued SIGIO */
 
-#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
-#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
+#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0 && (siptr)->si_code != SI_SIGIO)
+#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0 || (siptr)->si_code == SI_SIGIO)
 
 /*
  * SIGILL si_codes
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-alpha/smp.h linux.19p18/include/asm-alpha/smp.h
--- linux.vanilla/include/asm-alpha/smp.h	Mon Dec 11 22:13:05 2000
+++ linux.19p18/include/asm-alpha/smp.h	Thu Feb  1 15:01:44 2001
@@ -4,6 +4,7 @@
 #ifdef __SMP__
 
 #include <linux/tasks.h>
+#include <linux/sched.h>
 #include <asm/init.h>
 #include <asm/pal.h>
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-alpha/softirq.h linux.19p18/include/asm-alpha/softirq.h
--- linux.vanilla/include/asm-alpha/softirq.h	Fri Apr 21 12:46:47 2000
+++ linux.19p18/include/asm-alpha/softirq.h	Wed Jan  3 13:34:35 2001
@@ -9,6 +9,7 @@
 extern unsigned long local_bh_count;
 #else
 #define local_bh_count          (cpu_data[smp_processor_id()].bh_count)
+extern spinlock_t alpha_bh_lock;
 #endif
 
 #define get_active_bhs()	(bh_mask & bh_active)
@@ -28,24 +29,6 @@
 	:"Ir" (x), "m" (bh_active));
 }
 
-extern inline void init_bh(int nr, void (*routine)(void))
-{
-	bh_base[nr] = routine;
-	atomic_set(&bh_mask_count[nr], 0);
-	bh_mask |= 1 << nr;
-}
-
-extern inline void remove_bh(int nr)
-{
-	bh_base[nr] = NULL;
-	bh_mask &= ~(1 << nr);
-}
-
-extern inline void mark_bh(int nr)
-{
-	set_bit(nr, &bh_active);
-}
-
 #ifdef __SMP__
 
 /*
@@ -113,21 +96,58 @@
 
 #endif	/* SMP */
 
+extern inline void init_bh(int nr, void (*routine)(void))
+{
+	unsigned long flags;
+
+	bh_base[nr] = routine;
+	atomic_set(&bh_mask_count[nr], 0);
+
+	spin_lock_irqsave(&alpha_bh_lock, flags);
+	bh_mask |= 1 << nr;
+	spin_unlock_irqrestore(&alpha_bh_lock, flags);
+}
+
+extern inline void remove_bh(int nr)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&alpha_bh_lock, flags);
+	bh_mask &= ~(1 << nr);
+	spin_unlock_irqrestore(&alpha_bh_lock, flags);
+
+	synchronize_bh();
+	bh_base[nr] = NULL;
+}
+
+extern inline void mark_bh(int nr)
+{
+	set_bit(nr, &bh_active);
+}
+
 /*
  * These use a mask count to correctly handle
  * nested disable/enable calls
  */
 extern inline void disable_bh(int nr)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&alpha_bh_lock, flags);
 	bh_mask &= ~(1 << nr);
 	atomic_inc(&bh_mask_count[nr]);
+	spin_unlock_irqrestore(&alpha_bh_lock, flags);
 	synchronize_bh();
 }
 
 extern inline void enable_bh(int nr)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&alpha_bh_lock, flags);
 	if (atomic_dec_and_test(&bh_mask_count[nr]))
 		bh_mask |= 1 << nr;
+	spin_unlock_irqrestore(&alpha_bh_lock, flags);
 }
 
 #endif /* _ALPHA_SOFTIRQ_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-alpha/spinlock.h linux.19p18/include/asm-alpha/spinlock.h
--- linux.vanilla/include/asm-alpha/spinlock.h	Fri Apr 21 12:46:47 2000
+++ linux.19p18/include/asm-alpha/spinlock.h	Wed Jan  3 13:36:23 2001
@@ -231,6 +231,7 @@
 static inline void read_unlock(rwlock_t * lock)
 {
 	long regx;
+	mb();
 	__asm__ __volatile__(
 	"1:	ldl_l	%1,%0\n"
 	"	addl	%1,2,%1\n"
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-alpha/system.h linux.19p18/include/asm-alpha/system.h
--- linux.vanilla/include/asm-alpha/system.h	Mon Dec 11 22:13:05 2000
+++ linux.19p18/include/asm-alpha/system.h	Wed Jan  3 13:33:37 2001
@@ -112,12 +112,21 @@
 
 extern void halt(void) __attribute__((noreturn));
 
+#ifdef CONFIG_SMP
+#define ctx_cli()	__cli()
+#define ctx_sti()	__sti()
+#else
+#define ctx_cli()	do { } while(0)
+#define ctx_sti()	do { } while(0)
+#endif
+
 #define switch_to(prev,next,last)			\
 do {							\
 	unsigned long pcbb;				\
 	current = (next);				\
 	pcbb = virt_to_phys(&current->tss);		\
 	(last) = alpha_switch_to(pcbb, (prev));		\
+	ctx_sti();					\
 } while (0)
 
 extern struct task_struct* alpha_switch_to(unsigned long, struct task_struct*);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-alpha/uaccess.h linux.19p18/include/asm-alpha/uaccess.h
--- linux.vanilla/include/asm-alpha/uaccess.h	Sun Jun 11 21:44:22 2000
+++ linux.19p18/include/asm-alpha/uaccess.h	Tue Feb 27 16:30:13 2001
@@ -479,14 +479,6 @@
 	return ret;
 }
 
-/* Returns: 0 if bad, string length+1 (memory size) of string if ok */
-extern long __strlen_user(const char *);
-
-extern inline long strlen_user(const char *str)
-{
-	return access_ok(VERIFY_READ,str,0) ? __strlen_user(str) : 0;
-}
-
 /* Returns: 0 if exception before NUL or reaching the supplied limit (N),
  * a value greater than N if the limit would be exceeded, else strlen.  */
 extern long __strnlen_user(const char *, long);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/proc-armo/ptrace.h linux.19p18/include/asm-arm/proc-armo/ptrace.h
--- linux.vanilla/include/asm-arm/proc-armo/ptrace.h	Mon Dec 11 22:13:06 2000
+++ linux.19p18/include/asm-arm/proc-armo/ptrace.h	Wed Jan  3 00:57:43 2001
@@ -63,12 +63,6 @@
 #define condition_codes(regs) \
 	((regs)->ARM_pc & (CC_V_BIT|CC_C_BIT|CC_Z_BIT|CC_N_BIT))
 
-#define pc_pointer(v) \
-	((v) & 0x03fffffc)
-
-#define instruction_pointer(regs) \
-	(pc_pointer((regs)->ARM_pc))
-
 /* Are the current registers suitable for user mode?
  * (used to maintain security in signal handlers)
  */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/proc-armv/ptrace.h linux.19p18/include/asm-arm/proc-armv/ptrace.h
--- linux.vanilla/include/asm-arm/proc-armv/ptrace.h	Mon Dec 11 22:13:06 2000
+++ linux.19p18/include/asm-arm/proc-armv/ptrace.h	Wed Jan  3 00:57:43 2001
@@ -71,9 +71,6 @@
 #define condition_codes(regs) \
 	((regs)->ARM_cpsr & (CC_V_BIT|CC_C_BIT|CC_Z_BIT|CC_N_BIT))
 	
-#define instruction_pointer(regs)	((regs)->ARM_pc)
-#define pc_pointer(v)			(v)
-
 /* Are the current registers suitable for user mode?
  * (used to maintain security in signal handlers)
  */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/processor.h linux.19p18/include/asm-arm/processor.h
--- linux.vanilla/include/asm-arm/processor.h	Mon Dec 11 22:13:06 2000
+++ linux.19p18/include/asm-arm/processor.h	Wed Jan  3 00:57:43 2001
@@ -32,13 +32,25 @@
 #include <asm/arch/processor.h>
 #include <asm/proc/processor.h>
 
+struct debug_info {
+	int				nsaved;
+	struct {
+		unsigned long		address;
+		unsigned long		insn;
+	} bp[2];
+};
+
 struct thread_struct {
-	unsigned long			address;	  /* Address of fault	*/
-	unsigned long			trap_no;	  /* Trap number	*/
-	unsigned long			error_code;	  /* Error code of trap	*/
-	union fp_state			fpstate;	  /* FPE save state	*/
-	unsigned long			debug[NR_DEBUGS]; /* Debug/ptrace	*/
-	struct context_save_struct	*save;		  /* context save	*/
+							/* fault info	  */
+	unsigned long			address;
+	unsigned long			trap_no;
+	unsigned long			error_code;
+							/* floating point */
+	union fp_state			fpstate;
+							/* debugging	  */
+	struct debug_info		debug;
+							/* context info	  */
+	struct context_save_struct	*save;
 	unsigned long			memmap;		  /* page tables	*/
 	EXTRA_THREAD_STRUCT
 };
@@ -62,7 +74,7 @@
  */
 extern __inline__ unsigned long thread_saved_pc(struct thread_struct *t)
 {
-	return t->save ? t->save->pc & ~PCMASK : 0;
+	return t->save ? pc_pointer(t->save->pc) : 0;
 }
 
 extern __inline__ unsigned long get_css_fp(struct thread_struct *t)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/ptrace.h linux.19p18/include/asm-arm/ptrace.h
--- linux.vanilla/include/asm-arm/ptrace.h	Fri Apr 21 12:46:49 2000
+++ linux.19p18/include/asm-arm/ptrace.h	Wed Jan  3 00:57:43 2001
@@ -3,9 +3,27 @@
 
 #include <asm/proc/ptrace.h>
 
+#ifndef __ASSEMBLY__
+#define pc_pointer(v) \
+	((v) & ~PCMASK)
+
+#define instruction_pointer(regs) \
+	(pc_pointer((regs)->ARM_pc))
+
 #ifdef __KERNEL__
+#define PTRACE_GETREGS		12
+#define PTRACE_SETREGS		13
+#define PTRACE_GETFPREGS	14
+#define PTRACE_SETFPREGS	15
+
 extern void show_regs(struct pt_regs *);
+
+#define predicate(x)	(x & 0xf0000000)
+#define PREDICATE_ALWAYS	0xe0000000
+
 #endif
+
+#endif /* __ASSEMBLY__ */
 
 #endif
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/siginfo.h linux.19p18/include/asm-arm/siginfo.h
--- linux.vanilla/include/asm-arm/siginfo.h	Fri Apr 21 12:46:49 2000
+++ linux.19p18/include/asm-arm/siginfo.h	Tue Feb 27 21:59:16 2001
@@ -89,8 +89,8 @@
 #define SI_ASYNCIO	-4	/* sent by AIO completion */
 #define SI_SIGIO	-5	/* sent by queued SIGIO */
 
-#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
-#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
+#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0 && (siptr)->si_code != SI_SIGIO)
+#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0 || (siptr)->si_code == SI_SIGIO)
 
 /*
  * SIGILL si_codes
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-arm/uaccess.h linux.19p18/include/asm-arm/uaccess.h
--- linux.vanilla/include/asm-arm/uaccess.h	Mon Dec 11 22:13:06 2000
+++ linux.19p18/include/asm-arm/uaccess.h	Tue Feb 27 16:30:13 2001
@@ -121,8 +121,6 @@
 	return res;
 }
 
-#define strlen_user(s)	strnlen_user(s, ~0UL >> 1)
-
 extern __inline__ long strnlen_user (const char *s, long n)
 {
 	unsigned long res = 0;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/bugs.h linux.19p18/include/asm-i386/bugs.h
--- linux.vanilla/include/asm-i386/bugs.h	Mon Dec 11 22:13:06 2000
+++ linux.19p18/include/asm-i386/bugs.h	Tue Dec 19 02:15:14 2000
@@ -188,6 +188,7 @@
 __initfunc(static void check_amd_k6(void))
 {
 	if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
+	    boot_cpu_data.x86 == 5 &&
 	    boot_cpu_data.x86_model == 6 &&
 	    boot_cpu_data.x86_mask == 1)
 	{
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/e820.h linux.19p18/include/asm-i386/e820.h
--- linux.vanilla/include/asm-i386/e820.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/include/asm-i386/e820.h	Thu Dec 14 10:25:21 2000
@@ -0,0 +1,40 @@
+/*
+ * structures and definitions for the int 15, ax=e820 memory map
+ * scheme.
+ *
+ * In a nutshell, arch/i386/boot/setup.S populates a scratch table
+ * in the empty_zero_block that contains a list of usable address/size
+ * duples.   In arch/i386/kernel/setup.c, this information is
+ * transferred into the e820map, and in arch/i386/mm/init.c, that
+ * new information is used to mark pages reserved or not.
+ *
+ */
+#ifndef __E820_HEADER
+#define __E820_HEADER
+
+#define E820MAP	0x2d0		/* our map */
+#define E820MAX	32		/* number of entries in E820MAP */
+#define E820NR	0x1e8		/* # entries in E820MAP */
+
+#define E820_RAM	1
+#define E820_RESERVED	2
+#define E820_ACPI	3 /* usable as RAM once ACPI tables have been read */
+#define E820_NVS	4
+
+#define HIGH_MEMORY	(1024*1024)
+
+#ifndef __ASSEMBLY__
+
+struct e820map {
+    int nr_map;
+    struct e820entry {
+	unsigned long long addr;	/* start of memory segment */
+	unsigned long long size;	/* size of memory segment */
+	unsigned long type;		/* type of memory segment */
+    } map[E820MAX];
+};
+
+extern struct e820map e820;
+#endif/*!__ASSEMBLY__*/
+
+#endif/*__E820_HEADER*/
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/msr.h linux.19p18/include/asm-i386/msr.h
--- linux.vanilla/include/asm-i386/msr.h	Fri Apr 21 12:46:49 2000
+++ linux.19p18/include/asm-i386/msr.h	Wed Dec 13 21:50:26 2000
@@ -28,3 +28,7 @@
 			  : "=a" (low), "=d" (high) \
 			  : "c" (counter))
 
+/* symbolic names for some interesting MSRs */
+#define MSR_IA32_PLATFORM_ID	0x17
+#define MSR_IA32_UCODE_WRITE	0x79
+#define MSR_IA32_UCODE_REV	0x8B
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/processor.h linux.19p18/include/asm-i386/processor.h
--- linux.vanilla/include/asm-i386/processor.h	Mon Dec 11 22:13:06 2000
+++ linux.19p18/include/asm-i386/processor.h	Wed Dec 13 22:57:09 2000
@@ -327,6 +327,23 @@
 #define init_task	(init_task_union.task)
 #define init_stack	(init_task_union.stack)
 
+/* '6' because it used to be for P6 only, now supports P15 too */
+#define MICROCODE_IOCFREE _IO('6',0)
+
+/* physical layour of IA32 microcode chunks */
+struct microcode {
+	unsigned int hdrver;
+	unsigned int rev;
+	unsigned int date;
+	unsigned int sig;
+	unsigned int cksum;
+	unsigned int ldrver;
+	unsigned int pf;
+	unsigned int reserved[5];
+	unsigned int bits[500];
+};
+
+
 /* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
 extern inline void rep_nop(void)
 {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/siginfo.h linux.19p18/include/asm-i386/siginfo.h
--- linux.vanilla/include/asm-i386/siginfo.h	Fri Apr 21 23:10:16 2000
+++ linux.19p18/include/asm-i386/siginfo.h	Tue Feb 27 21:59:16 2001
@@ -89,8 +89,8 @@
 #define SI_ASYNCIO	-4	/* sent by AIO completion */
 #define SI_SIGIO	-5	/* sent by queued SIGIO */
 
-#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
-#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
+#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0 && (siptr)->si_code != SI_SIGIO)
+#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0 || (siptr)->si_code == SI_SIGIO)
 
 /*
  * SIGILL si_codes
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-i386/uaccess.h linux.19p18/include/asm-i386/uaccess.h
--- linux.vanilla/include/asm-i386/uaccess.h	Sun Jun 11 21:44:22 2000
+++ linux.19p18/include/asm-i386/uaccess.h	Sat Mar  3 22:39:09 2001
@@ -510,20 +510,20 @@
 			"	popl %0\n"			\
 			"	shl $2,%0\n"			\
 			"	addl $3,%0\n"			\
-			"	jmp 2b\n"			\
+			"	jmp 3b\n"			\
 			"5:	pushl %%eax\n"			\
 			"	xorl %%eax,%%eax\n"		\
 			"	stosw\n"			\
 			"	stosb\n"			\
 			"	popl %%eax\n"			\
 			"	addl $3,%0\n"			\
-			"	jmp 2b\n"			\
+			"	jmp 3b\n"			\
 			"6:	pushl %%eax\n"			\
 			"	xorl %%eax,%%eax\n"		\
 			"	stosb\n"			\
 			"	popl %%eax\n"			\
 			"	incl %0\n"			\
-			"	jmp 2b\n"			\
+			"	jmp 3b\n"			\
 			".previous\n"				\
 			".section __ex_table,\"a\"\n"		\
 			"	.align 4\n"			\
@@ -597,7 +597,6 @@
 
 long strncpy_from_user(char *dst, const char *src, long count);
 long __strncpy_from_user(char *dst, const char *src, long count);
-#define strlen_user(str) strnlen_user(str, ~0UL >> 1)
 long strnlen_user(const char *str, long n);
 unsigned long clear_user(void *mem, unsigned long len);
 unsigned long __clear_user(void *mem, unsigned long len);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-m68k/siginfo.h linux.19p18/include/asm-m68k/siginfo.h
--- linux.vanilla/include/asm-m68k/siginfo.h	Fri Apr 21 12:46:49 2000
+++ linux.19p18/include/asm-m68k/siginfo.h	Tue Feb 27 21:59:16 2001
@@ -89,8 +89,8 @@
 #define SI_ASYNCIO	-4	/* sent by AIO completion */
 #define SI_SIGIO	-5	/* sent by queued SIGIO */
 
-#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
-#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
+#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0 && (siptr)->si_code != SI_SIGIO)
+#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0 || (siptr)->si_code == SI_SIGIO)
 
 /*
  * SIGILL si_codes
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-m68k/uaccess.h linux.19p18/include/asm-m68k/uaccess.h
--- linux.vanilla/include/asm-m68k/uaccess.h	Mon Dec 11 22:13:06 2000
+++ linux.19p18/include/asm-m68k/uaccess.h	Tue Feb 27 16:30:13 2001
@@ -801,7 +801,6 @@
  *
  * Return 0 for error
  */
-#define strlen_user(str) strnlen_user(str, ~0UL >> 1)
 static inline long strnlen_user(const char * src, long n)
 {
     long res = -(long) src;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-mips/siginfo.h linux.19p18/include/asm-mips/siginfo.h
--- linux.vanilla/include/asm-mips/siginfo.h	Fri Apr 21 12:46:49 2000
+++ linux.19p18/include/asm-mips/siginfo.h	Tue Feb 27 21:59:16 2001
@@ -97,8 +97,8 @@
 #define SI_MESGQ	-4	/* sent by real time mesq state change */
 #define SI_SIGIO	-5	/* sent by queued SIGIO */
 
-#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
-#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
+#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0 && (siptr)->si_code != SI_SIGIO)
+#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0 || (siptr)->si_code == SI_SIGIO)
 
 /*
  * SIGILL si_codes
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ppc/ide.h linux.19p18/include/asm-ppc/ide.h
--- linux.vanilla/include/asm-ppc/ide.h	Sat Sep  9 18:42:50 2000
+++ linux.19p18/include/asm-ppc/ide.h	Thu Feb 15 16:12:01 2001
@@ -36,6 +36,7 @@
 extern ide_ioreg_t chrp_idedma_regbase; /* one for both channels */
 extern unsigned int chrp_ide_irq;
 extern void chrp_ide_probe(void);
+extern void ide_pmac_init(void);
 
 struct ide_machdep_calls {
         void        (*insw)(ide_ioreg_t port, void *buf, int ns);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ppc/mman.h linux.19p18/include/asm-ppc/mman.h
--- linux.vanilla/include/asm-ppc/mman.h	Fri Apr 21 12:46:49 2000
+++ linux.19p18/include/asm-ppc/mman.h	Thu Feb 15 16:12:01 2001
@@ -13,6 +13,7 @@
 #define MAP_ANONYMOUS	0x20		/* don't use a file */
 #define MAP_RENAME      MAP_ANONYMOUS   /* In SunOS terminology */
 #define MAP_NORESERVE   0x40            /* don't reserve swap pages */
+#define MAP_LOCKED	0x80
 
 #define MAP_GROWSDOWN	0x0100		/* stack-like segment */
 #define MAP_DENYWRITE	0x0800		/* ETXTBSY */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ppc/page.h linux.19p18/include/asm-ppc/page.h
--- linux.vanilla/include/asm-ppc/page.h	Mon Dec 11 22:13:06 2000
+++ linux.19p18/include/asm-ppc/page.h	Thu Feb 15 16:12:01 2001
@@ -14,6 +14,19 @@
 #ifndef __ASSEMBLY__
 #ifdef __KERNEL__
 
+#ifdef CONFIG_XMON
+#define BUG() do { \
+	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
+	xmon(0); \
+} while (0)
+#else
+#define BUG() do { \
+	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
+	__asm__ __volatile__(".long 0x0"); \
+} while (0)
+#endif
+#define PAGE_BUG(page) do { BUG(); } while (0)
+
 #define STRICT_MM_TYPECHECKS
 
 #ifdef STRICT_MM_TYPECHECKS
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ppc/siginfo.h linux.19p18/include/asm-ppc/siginfo.h
--- linux.vanilla/include/asm-ppc/siginfo.h	Fri Apr 21 12:46:49 2000
+++ linux.19p18/include/asm-ppc/siginfo.h	Tue Feb 27 21:59:16 2001
@@ -89,8 +89,8 @@
 #define SI_ASYNCIO	-4	/* sent by AIO completion */
 #define SI_SIGIO	-5	/* sent by queued SIGIO */
 
-#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
-#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
+#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0 && (siptr)->si_code != SI_SIGIO)
+#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0 || (siptr)->si_code == SI_SIGIO)
 
 /*
  * SIGILL si_codes
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-ppc/uaccess.h linux.19p18/include/asm-ppc/uaccess.h
--- linux.vanilla/include/asm-ppc/uaccess.h	Mon Dec 11 22:13:06 2000
+++ linux.19p18/include/asm-ppc/uaccess.h	Tue Feb 27 16:30:13 2001
@@ -276,8 +276,6 @@
 	return __strnlen_user(str, len, top);
 }
 
-#define strlen_user(str)	strnlen_user((str), 0x7ffffffe)
-
 #endif  /* __ASSEMBLY__ */
 
 #endif	/* _PPC_UACCESS_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/bitops.h linux.19p18/include/asm-s390/bitops.h
--- linux.vanilla/include/asm-s390/bitops.h	Mon Dec 11 22:13:06 2000
+++ linux.19p18/include/asm-s390/bitops.h	Mon Feb 19 18:37:49 2001
@@ -495,9 +495,9 @@
              "   lhi   2,7\n"
              "   xr    1,%1\n"
              "   nr    2,1\n"
-             "   srl   1,3(0)\n"
+             "   srl   1,3\n"
              "   la    1,0(1,%2)\n"
-             "   ic    %0,0(0,1)\n"
+             "   ic    %0,0(1)\n"
              "   srl   %0,0(2)\n"
              "   n     %0,%4\n"
              "   la    2,0(2,%3)\n"
@@ -521,9 +521,9 @@
              "   lhi   2,7\n"
              "   xr    1,%1\n"
              "   nr    2,1\n"
-             "   srl   1,3(0)\n"
+             "   srl   1,3\n"
              "   la    1,0(1,%2)\n"
-             "   ic    %0,0(0,1)\n"
+             "   ic    %0,0(1)\n"
              "   srl   %0,0(2)\n"
              "   n     %0,%4\n"
              "   la    2,0(2,%3)\n"
@@ -547,9 +547,9 @@
              "   lhi   2,7\n"
              "   xr    1,%1\n"
              "   nr    2,1\n"
-             "   srl   1,3(0)\n"
+             "   srl   1,3\n"
              "   la    1,0(1,%2)\n"
-             "   ic    %0,0(0,1)\n"
+             "   ic    %0,0(1)\n"
              "   srl   %0,0(2)\n"
              "   n     %0,%4\n"
              "   la    2,0(2,%3)\n"
@@ -632,7 +632,7 @@
                 "   lr   2,%1\n"
                 "   j    4f\n"
                 "1: l    1,0(2,%2)\n"
-                "   sll  2,3(0)\n"
+                "   sll  2,3\n"
                 "   tml  1,0xFFFF\n"
                 "   jno  2f\n"
                 "   ahi  2,16\n"
@@ -804,7 +804,7 @@
                 "   lr   2,%1\n"
                 "   j    4f\n"
                 "1: l    1,0(2,%2)\n"
-                "   sll  2,3(0)\n"
+                "   sll  2,3\n"
                 "   lhi  0,0xff\n"
                 "   ahi  2,24\n"
                 "   tmh  1,0xFFFF\n"
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/ccwcache.h linux.19p18/include/asm-s390/ccwcache.h
--- linux.vanilla/include/asm-s390/ccwcache.h	Mon Dec 11 22:13:06 2000
+++ linux.19p18/include/asm-s390/ccwcache.h	Tue Feb 20 13:26:26 2001
@@ -1,5 +1,5 @@
 /* 
-   * File...........: linux/drivers/s390/block/ccwcache.c
+   * File...........: linux/include/asm-s390/ccwcache.h
    * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
    * Bugreports.to..: <Linux390@de.ibm.com>
    * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
@@ -34,7 +34,8 @@
 	devstat_t *dstat;	/* The device status in case of an error */
 
 	/* these are important for recovering erroneous requests */
-	int retries;		/* A retry counter to be set when filling */
+	short retries;		/* A retry counter to be set when filling */
+	char lpm;               /* logical path mask                      */
 	devstat_t *devstat;	/* Keeping the device status */
 	struct ccw_req_t *refers;	/* Does this request refer to another one? */
 	void *function; /* refers to the originating ERP action */ ;
@@ -64,6 +65,7 @@
 #define CQR_STATUS_DONE     0x08	/* request is completed sucessfully */
 #define CQR_STATUS_ERROR    0x10	/* request is completed with error */
 #define CQR_STATUS_FAILED   0x20	/* request is finally failed */
+#define CQR_STATUS_PENDING  0x07        /* request is waiting for interrupt - ERP only */ 
 #define CQR_STATUS_FINISHED 0x40	/* request is ready for cleanup */
 
 #ifdef __KERNEL__
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/dasd.h linux.19p18/include/asm-s390/dasd.h
--- linux.vanilla/include/asm-s390/dasd.h	Mon Dec 11 22:13:06 2000
+++ linux.19p18/include/asm-s390/dasd.h	Sun Feb 25 23:10:55 2001
@@ -2,12 +2,15 @@
 #ifndef DASD_H
 #define DASD_H
 
+#undef ERP_DEBUG               /* enable debug messages */
+
 /* First of all the external stuff */
 #include <linux/version.h>
 #include <linux/ioctl.h>
 #include <linux/major.h>
 #include <linux/wait.h>
 #include <asm/ccwcache.h>
+#include <asm/todclk.h>
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
 #include <linux/blkdev.h> 
 #endif
@@ -65,6 +68,12 @@
 	dasd_era_recover = 2	/* recovery action recommended       */
 } dasd_era_t;
 
+/* BIT DEFINITIONS FOR SENSE DATA */
+#define DASD_SENSE_BIT_0 0x80
+#define DASD_SENSE_BIT_1 0x40
+#define DASD_SENSE_BIT_2 0x20
+#define DASD_SENSE_BIT_3 0x10
+
 /* 
  * struct dasd_sizes_t
  * represents all data needed to access dasd with properly set up sectors
@@ -97,7 +106,7 @@
 struct dasd_device_t;
 
 typedef ccw_req_t *(*dasd_erp_action_fn_t) (ccw_req_t * cqr);
-typedef int (*dasd_erp_postaction_fn_t) (ccw_req_t * cqr, int);
+typedef ccw_req_t *(*dasd_erp_postaction_fn_t) (ccw_req_t * cqr);
 
 typedef int (*dasd_ck_id_fn_t) (dev_info_t *);
 typedef int (*dasd_ck_characteristics_fn_t) (struct dasd_device_t *);
@@ -116,6 +125,7 @@
 typedef struct dasd_discipline_t {
 	char ebcname[8]; /* a name used for tagging and printks */
         char name[8];		/* a name used for tagging and printks */
+	int max_blocks; /* how many blocks are allowed to be chained */
 
 	struct dasd_discipline_t *next;	/* used for list of disciplines */
 
@@ -165,6 +175,7 @@
         struct wait_queue wait;
         struct wait_queue *wait_q;
 #endif /* LINUX_IS_24 */
+        struct timer_list timer;      /* HUM new */
         dasd_sizes_t sizes;
 	devstat_t dev_status;
 	char *characteristics;
@@ -231,6 +242,24 @@
 int dasd_discipline_deq(dasd_discipline_t *);
 int dasd_start_IO (ccw_req_t *);
 void dasd_int_handler (int , void *, struct pt_regs *);
+ccw_req_t *default_erp_action (ccw_req_t *);
+ccw_req_t *default_erp_postaction (ccw_req_t *);
+int dasd_chanq_deq (dasd_chanq_t *, ccw_req_t *);
+ccw_req_t *dasd_alloc_request (char *, int, int);
+void dasd_free_request (ccw_req_t *);
+
+
+#define DASD_MESSAGE(d_loglevel,d_device,d_string,d_args...)\
+do { \
+        int d_devno = d_device->devinfo.devno; \
+        int d_irq = d_device->devinfo.irq; \
+        char *d_name = d_device->name; \
+        int d_major = MAJOR(d_device->kdev); \
+        int d_minor = MINOR(d_device->kdev); \
+        printk(d_loglevel PRINTK_HEADER \
+               "/dev/%s(%d:%d), 0x%04X on SCH 0x%x: " \
+               d_string "\n",d_name,d_major,d_minor,d_devno,d_irq,d_args ); \
+} while(0)
 
 #endif /* __KERNEL__ */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/debug.h linux.19p18/include/asm-s390/debug.h
--- linux.vanilla/include/asm-s390/debug.h	Mon Dec 11 22:13:06 2000
+++ linux.19p18/include/asm-s390/debug.h	Mon Feb 19 18:33:37 2001
@@ -9,42 +9,59 @@
 #ifndef DEBUG_H
 #define DEBUG_H
 
-#ifdef __KERNEL__
+/* Note:
+ * struct __debug_entry must be defined outside of #ifdef __KERNEL__ 
+ * in order to allow a user program to analyze the 'raw'-view.
+ */
+
+struct __debug_entry{
+        union {
+                struct {
+                        unsigned long long clock:52;
+                        unsigned long long exception:1;
+                        unsigned long long level:3;
+                        unsigned long long cpuid:8;
+                } fields;
+
+                unsigned long long stck;
+        } id;
+        void* caller;
+} __attribute__((packed));
+
 
-#include <asm/spinlock.h>
+#define __DEBUG_FEATURE_VERSION      1  /* version of debug feature */
+
+#ifdef __KERNEL__
+#include <linux/version.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+ #include <asm/spinlock.h>
+#else
+ #include <linux/spinlock.h>
+#endif /* LINUX_VERSION_CODE */
 #include <linux/kernel.h>
 #include <linux/time.h>
 #include <linux/proc_fs.h>
 
-#define DEBUG_MAX_AREAS            16 /* max number of allowed registers */
 #define DEBUG_MAX_LEVEL            6  /* debug levels range from 0 to 6 */
+#define DEBUG_OFF_LEVEL            -1 /* level where debug is switched off */
 #define DEBUG_MAX_VIEWS            10 /* max number of views in proc fs */
 #define DEBUG_MAX_PROCF_LEN        16 /* max length for a proc file name */
 #define DEBUG_DEFAULT_LEVEL        3  /* initial debug level */
 
 #define DEBUG_DIR_ROOT "s390dbf" /* name of debug root directory in proc fs */
 
+#define DEBUG_DATA(entry) (char*)(entry + 1) /* data is stored behind */
+                                             /* the entry information */
+
 #define STCK(x)	asm volatile ("STCK %0":"=m" (x))
 
-typedef struct {
-	union {
-		struct {
-			unsigned long long clock:52;
-			unsigned long long unused:2;
-			unsigned long long cpuid:8;
-			unsigned long long exception:1;
-			unsigned long long used:1;
-		} fields;
-
-		unsigned long long stck;
-	} id;
-	void* caller;
-	char data[4];
-} debug_entry_t;
+typedef struct __debug_entry debug_entry_t;
 
 struct debug_view;
 
-typedef struct {	
+typedef struct debug_info {	
+	struct debug_info* next;
+	struct debug_info* prev;
 	atomic_t ref_count;
 	spinlock_t lock;			
 	int level;
@@ -54,7 +71,7 @@
 	int entry_size;	
 	debug_entry_t** areas;
 	int active_area;
-	int active_entry[DEBUG_MAX_AREAS];
+	int *active_entry;
 	struct proc_dir_entry* proc_root_entry;
 	struct proc_dir_entry* proc_entries[DEBUG_MAX_VIEWS];
 	struct debug_view* views[DEBUG_MAX_VIEWS];	
@@ -87,29 +104,97 @@
 	debug_header_proc_t* header_proc;
 	debug_format_proc_t* format_proc;
 	debug_input_proc_t*  input_proc;
+	void*                private_data;
 };
 
-extern struct debug_view debug_ascii_view;
-extern struct debug_view debug_ebcdic_view;
-extern struct debug_view debug_hex_view;
+extern struct debug_view debug_hex_ascii_view;
+extern struct debug_view debug_raw_view;
+extern struct debug_view debug_sprintf_view;
+
+/* do NOT use the _common functions */
+
+debug_entry_t* debug_event_common(debug_info_t* id, int level, 
+                                  const void* data, int length);
+
+debug_entry_t* debug_exception_common(debug_info_t* id, int level, 
+                                      const void* data, int length);
+
+/* Debug Feature API: */
 
 debug_info_t* debug_register(char* name, int pages_index, int nr_areas,
-			     int buf_size);
+                             int buf_size);
+
 void debug_unregister(debug_info_t* id);
 
-debug_entry_t* debug_event(debug_info_t* id, int level, void* data,
-			   int length);
-debug_entry_t* debug_int_event(debug_info_t* id, int level,
-			       unsigned int tag);
-debug_entry_t* debug_text_event(debug_info_t* id, int level,
-				const char* txt);
-
-debug_entry_t* debug_exception(debug_info_t* id, int level, void* data,
-			       int length);
-debug_entry_t* debug_int_exception(debug_info_t* id, int level,
-				   unsigned int tag);
-debug_entry_t* debug_text_exception(debug_info_t* id, int level,
-				    const char* txt);
+void debug_set_level(debug_info_t* id, int new_level);
+
+extern inline debug_entry_t* 
+debug_event(debug_info_t* id, int level, void* data, int length)
+{
+	if ((!id) || (level > id->level)) return NULL;
+        return debug_event_common(id,level,data,length);
+}
+
+extern inline debug_entry_t* 
+debug_int_event(debug_info_t* id, int level, unsigned int tag)
+{
+        unsigned int t=tag;
+	if ((!id) || (level > id->level)) return NULL;
+        return debug_event_common(id,level,&t,sizeof(unsigned int));
+}
+
+extern inline debug_entry_t *
+debug_long_event (debug_info_t* id, int level, unsigned long tag)
+{
+        unsigned long t=tag;
+	if ((!id) || (level > id->level)) return NULL;
+        return debug_event_common(id,level,&t,sizeof(unsigned long));
+}
+
+extern inline debug_entry_t* 
+debug_text_event(debug_info_t* id, int level, const char* txt)
+{
+	if ((!id) || (level > id->level)) return NULL;
+        return debug_event_common(id,level,txt,strlen(txt));
+}
+
+extern debug_entry_t *
+debug_sprintf_event(debug_info_t* id,int level,char *string,...);
+
+
+extern inline debug_entry_t* 
+debug_exception(debug_info_t* id, int level, void* data, int length)
+{
+	if ((!id) || (level > id->level)) return NULL;
+        return debug_exception_common(id,level,data,length);
+}
+
+extern inline debug_entry_t* 
+debug_int_exception(debug_info_t* id, int level, unsigned int tag)
+{
+        unsigned int t=tag;
+	if ((!id) || (level > id->level)) return NULL;
+        return debug_exception_common(id,level,&t,sizeof(unsigned int));
+}
+
+extern inline debug_entry_t * 
+debug_long_exception (debug_info_t* id, int level, unsigned long tag)
+{
+        unsigned long t=tag;
+	if ((!id) || (level > id->level)) return NULL;
+        return debug_exception_common(id,level,&t,sizeof(unsigned long));
+}
+
+extern inline debug_entry_t* 
+debug_text_exception(debug_info_t* id, int level, const char* txt)
+{
+	if ((!id) || (level > id->level)) return NULL;
+        return debug_exception_common(id,level,txt,strlen(txt));
+}
+
+
+extern debug_entry_t *
+debug_sprintf_exception(debug_info_t* id,int level,char *string,...);
 
 int debug_register_view(debug_info_t* id, struct debug_view* view);
 int debug_unregister_view(debug_info_t* id, struct debug_view* view);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/elf.h linux.19p18/include/asm-s390/elf.h
--- linux.vanilla/include/asm-s390/elf.h	Fri Apr 21 12:46:49 2000
+++ linux.19p18/include/asm-s390/elf.h	Mon Feb 19 18:34:53 2001
@@ -22,7 +22,8 @@
 /*
  * This is used to ensure we don't load something for the wrong architecture.
  */
-#define elf_check_arch(x) ((x) == EM_S390) 
+#define elf_check_arch(x) \
+        ((x) == EM_S390 || (x) == EM_S390_OLD)
 
 /*
  * These are used to set parameters in the core dumps.
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/idals.h linux.19p18/include/asm-s390/idals.h
--- linux.vanilla/include/asm-s390/idals.h	Mon Dec 11 22:13:06 2000
+++ linux.19p18/include/asm-s390/idals.h	Mon Feb 19 18:33:37 2001
@@ -7,19 +7,50 @@
    * History of changes
    * 07/24/00 new file
  */
-
-#define IDAL_NUMBER_CACHES 7
+#include <asm/irq.h>
 
 typedef unsigned long idaw_t;
 
-#ifdef CONFIG_ARCH_S390
-extern inline int 
-normalize_cpa(ccw1_t * ccw, unsigned long address)
+static inline idaw_t *
+idal_alloc ( int nridaws )
 {
-	return address;
+	if ( nridaws > 33 )
+		BUG();
+	return kmalloc(nridaws * sizeof(idaw_t), GFP_ATOMIC | GFP_DMA );
 }
+
+static inline void 
+idal_free ( idaw_t *idal )
+{
+	kfree (idal);
+}
+
+/*
+ * Function: set_normalized_cda
+ * sets the address of the data in CCW
+ * if necessary it allocates an IDAL and sets sthe appropriate flags
+ */
+#if defined (CONFIG_ARCH_S390)
+static inline void
+set_normalized_cda(ccw1_t * ccw, unsigned long address)
+{
+	ccw->cda = address;
+}
+#elif defined (CONFIG_ARCH_S390X)
+extern void set_normalized_cda(ccw1_t * ccw, unsigned long address);
 #endif
 
-int idal_alloc ( int nridaws );
-void idal_release ( idaw_t *idal );
+/*
+ * Function: clear_normalized_cda
+ * releases any allocated IDAL related to the CCW
+ */
+static inline void
+clear_normalized_cda ( ccw1_t * ccw ) 
+{
+	if ( ccw -> flags & CCW_FLAG_IDA ) {
+		idal_free ( (idaw_t *) (ccw -> cda ));
+		ccw -> flags &= ~CCW_FLAG_IDA;
+	}
+	ccw -> cda = 0;
+}
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/io.h linux.19p18/include/asm-s390/io.h
--- linux.vanilla/include/asm-s390/io.h	Fri Apr 21 12:46:49 2000
+++ linux.19p18/include/asm-s390/io.h	Mon Feb 19 18:37:49 2001
@@ -25,7 +25,7 @@
 extern inline unsigned long virt_to_phys(volatile void * address)
 {
 	unsigned long real_address;
-	__asm__ ("   lra    %0,0(0,%1)\n"
+	__asm__ ("   lra    %0,0(%1)\n"
                  "   jz     0f\n"
                  "   sr     %0,%0\n"
                  "0:"
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/irq.h linux.19p18/include/asm-s390/irq.h
--- linux.vanilla/include/asm-s390/irq.h	Mon Dec 11 22:13:06 2000
+++ linux.19p18/include/asm-s390/irq.h	Mon Feb 19 18:32:03 2001
@@ -183,6 +183,33 @@
 #define SNS0_EQUIPMENT_CHECK    0x10
 #define SNS0_DATA_CHECK         0x08
 #define SNS0_OVERRUN            0x04
+/*                              0x02 reserved */
+#define SNS0_INCOMPL_DOMAIN     0x01
+
+/*
+ * architectured values for second sense byte
+ */
+#define SNS1_PERM_ERR           0x80
+#define SNS1_INV_TRACK_FORMAT   0x40
+#define SNS1_EOC                0x20
+#define SNS1_MESSAGE_TO_OPER    0x10
+#define SNS1_NO_REC_FOUND       0x08
+#define SNS1_FILE_PROTECTED     0x04
+#define SNS1_WRITE_INHIBITED    0x02
+#define SNS1_INPRECISE_END      0x01
+
+/*
+ * architectured values for third sense byte
+ */
+#define SNS2_REQ_INH_WRITE      0x80
+#define SNS2_CORRECTABLE        0x40
+#define SNS2_FIRST_LOG_ERR      0x20
+#define SNS2_ENV_DATA_PRESENT   0x10
+/*                              0x08 reserved */
+#define SNS2_INPRECISE_END      0x04
+/*                              0x02 reserved */
+/*                              0x01 reserved */
+
 
 /*
  * operation request block
@@ -319,6 +346,7 @@
 #define CIW_TYPE_SII    0x1    // set interface identifier
 #define CIW_TYPE_RNI    0x2    // read node identifier
 
+#define MAX_CIWS 8
 //
 // sense-id response buffer layout
 //
@@ -331,7 +359,7 @@
       __u8           dev_model;    /* device model */
       __u8           unused;       /* padding byte */
   /* extended part */
-      ciw_t    ciw[16];            /* variable # of CIWs */
+      ciw_t    ciw[MAX_CIWS];      /* variable # of CIWs */
    }  __attribute__ ((packed,aligned(4))) senseid_t;
 
 #endif /* __KERNEL__ */
@@ -383,6 +411,7 @@
 #define DEVSTAT_FINAL_STATUS       0x80000000
 
 #define INTPARM_STATUS_PENDING     0xFFFFFFFF
+
 #ifdef __KERNEL__
 
 typedef  void (* io_handler_func1_t) ( int             irq,
@@ -543,7 +572,7 @@
                               not_oper_handler_func_t  not_oper_handler,
                               unsigned long            irqflags,
                               const char              *devname,
-                              void                    *dev_id);
+                              devstat_t               *dev_id);
 
 extern int handle_IRQ_event( unsigned int irq, int cpu, struct pt_regs *);
 
@@ -809,7 +838,7 @@
 {
         if (prof_buffer && current->pid) {
                 addr &= 0x7fffffff;
-                addr -= (unsigned long)&_stext;
+                addr -= (unsigned long) &_stext;
                 addr >>= prof_shift;
                 /*
                  * Don't ignore out-of-bounds EIP values silently,
@@ -832,8 +861,10 @@
 
 #define s390irq_spin_lock_irqsave(irq,flags) \
         spin_lock_irqsave(&(ioinfo[irq]->irq_lock), flags)
+
 #define s390irq_spin_unlock_irqrestore(irq,flags) \
         spin_unlock_irqrestore(&(ioinfo[irq]->irq_lock), flags)
 #endif /* __KERNEL__ */
+
 #endif
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/page.h linux.19p18/include/asm-s390/page.h
--- linux.vanilla/include/asm-s390/page.h	Mon Dec 11 22:13:06 2000
+++ linux.19p18/include/asm-s390/page.h	Sun Feb 25 23:11:35 2001
@@ -26,6 +26,11 @@
 #define clear_page(page)        memset((void *)(page), 0, PAGE_SIZE)
 #define copy_page(to,from)      memcpy((void *)(to), (void *)(from), PAGE_SIZE)
 
+#define BUG() do { \
+	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
+	__asm__ __volatile__(".word 0x0000"); \
+} while (0)
+
 extern __inline__ int get_order(unsigned long size)
 {
         int order;
@@ -103,7 +108,6 @@
 #define __pa(x)                 ((unsigned long)(x)-PAGE_OFFSET)
 #define __va(x)                 ((void *)((unsigned long)(x)+PAGE_OFFSET))
 #define MAP_NR(addr)            (__pa(addr) >> PAGE_SHIFT)
-
 
 #endif                                 /* __KERNEL__                       */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/pgtable.h linux.19p18/include/asm-s390/pgtable.h
--- linux.vanilla/include/asm-s390/pgtable.h	Mon Dec 11 22:13:06 2000
+++ linux.19p18/include/asm-s390/pgtable.h	Mon Feb 19 18:32:03 2001
@@ -546,7 +546,7 @@
 extern __inline__ pgd_t* get_pgd_slow(void)
 {
         int i;
-        pgd_t *pgd,*ret = (pgd_t *)__get_free_pages(GFP_KERNEL,2);
+        pgd_t *pgd,*ret = (pgd_t *)__get_free_pages(GFP_KERNEL,1);
 	if (ret)
 		for (i=0,pgd=ret;i<USER_PTRS_PER_PGD;i++,pgd++)
 			pmd_clear(pmd_offset(pgd,i*PGDIR_SIZE));
@@ -560,17 +560,7 @@
         if((ret = pgd_quicklist) != NULL) {
                 pgd_quicklist = (unsigned long *)(*ret);
                 ret[0] = ret[1];
-                pgtable_cache_size--;
-		/*
-		 * Need to flush tlb, since private page tables
-		 * are unique thru address of pgd and virtual address.
-		 * If we reuse pgd we need to be sure no tlb entry
-		 * with that pdg is left -> global flush
-		 *
-		 * Fixme: To avoid this global flush we should
-		 * use pdg_quicklist as fix lenght fifo list
-		 * and not as stack
-		 */
+                pgtable_cache_size -= 2;
         } else
                 ret = (unsigned long *)get_pgd_slow();
         return (pgd_t *)ret;
@@ -580,12 +570,12 @@
 {
         *(unsigned long *)pgd = (unsigned long) pgd_quicklist;
         pgd_quicklist = (unsigned long *) pgd;
-        pgtable_cache_size++;
+        pgtable_cache_size += 2;
 }
 
 extern __inline__ void free_pgd_slow(pgd_t *pgd)
 {
-        free_pages((unsigned long)pgd,2);
+        free_pages((unsigned long)pgd, 1);
 }
 
 extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/siginfo.h linux.19p18/include/asm-s390/siginfo.h
--- linux.vanilla/include/asm-s390/siginfo.h	Fri Apr 21 12:46:49 2000
+++ linux.19p18/include/asm-s390/siginfo.h	Tue Feb 27 21:59:16 2001
@@ -97,8 +97,8 @@
 #define SI_ASYNCIO	-4	/* sent by AIO completion */
 #define SI_SIGIO	-5	/* sent by queued SIGIO */
 
-#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
-#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
+#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0 && (siptr)->si_code != SI_SIGIO)
+#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0 || (siptr)->si_code == SI_SIGIO)
 
 /*
  * SIGILL si_codes
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/system.h linux.19p18/include/asm-s390/system.h
--- linux.vanilla/include/asm-s390/system.h	Mon Dec 11 22:13:06 2000
+++ linux.19p18/include/asm-s390/system.h	Mon Feb 19 18:32:03 2001
@@ -33,14 +33,14 @@
                                 "   nr    1,%0\n"     /* isolate last 2 bits */
                                 "   xr    %0,1\n"     /* align ptr */
                                 "   bras  2,0f\n"
-                                "   icm   1,8,%1\n"   /* for ptr&3 == 0 */
-                                "   stcm  0,8,%1\n"
-                                "   icm   1,4,%1\n"   /* for ptr&3 == 1 */
-                                "   stcm  0,4,%1\n"
-                                "   icm   1,2,%1\n"   /* for ptr&3 == 2 */
-                                "   stcm  0,2,%1\n"
-                                "   icm   1,1,%1\n"   /* for ptr&3 == 3 */
-                                "   stcm  0,1,%1\n"
+                                "   icm   1,8,3(%1)\n"   /* for ptr&3 == 0 */
+                                "   stcm  0,8,3(%1)\n"
+                                "   icm   1,4,3(%1)\n"   /* for ptr&3 == 1 */
+                                "   stcm  0,4,3(%1)\n"
+                                "   icm   1,2,3(%1)\n"   /* for ptr&3 == 2 */
+                                "   stcm  0,2,3(%1)\n"
+                                "   icm   1,1,3(%1)\n"   /* for ptr&3 == 3 */
+                                "   stcm  0,1,3(%1)\n"
                                 "0: sll   1,3\n"
                                 "   la    2,0(1,2)\n" /* r2 points to an icm */
                                 "   l     0,0(%0)\n"  /* get fullword */
@@ -49,8 +49,9 @@
                                 "   cs    0,1,0(%0)\n"
                                 "   jl    1b\n"
                                 "   ex    0,4(2)"     /* store *ptr to x */
-                                : "+a&" (ptr), "+m" (x) :
+                                : "+a&" (ptr) : "a" (&x)
                                 : "memory", "0", "1", "2");
+			break;
                 case 2:
                         if(((__u32)ptr)&1)
                                 panic("misaligned (__u16 *) in __xchg\n");
@@ -59,10 +60,10 @@
                                 "   nr    1,%0\n"     /* isolate bit 2^1 */
                                 "   xr    %0,1\n"     /* align ptr */
                                 "   bras  2,0f\n"
-                                "   icm   1,12,%1\n"   /* for ptr&2 == 0 */
-                                "   stcm  0,12,%1\n"
-                                "   icm   1,3,%1\n"    /* for ptr&2 == 1 */
-                                "   stcm  0,3,%1\n"
+                                "   icm   1,12,2(%1)\n"   /* for ptr&2 == 0 */
+                                "   stcm  0,12,2(%1)\n"
+                                "   icm   1,3,2(%1)\n"    /* for ptr&2 == 1 */
+                                "   stcm  0,3,2(%1)\n"
                                 "0: sll   1,2\n"
                                 "   la    2,0(1,2)\n" /* r2 points to an icm */
                                 "   l     0,0(%0)\n"  /* get fullword */
@@ -71,7 +72,7 @@
                                 "   cs    0,1,0(%0)\n"
                                 "   jl    1b\n"
                                 "   ex    0,4(2)"     /* store *ptr to x */
-                                : "+a&" (ptr), "+m" (x) :
+                                : "+a&" (ptr) : "a" (&x)
                                 : "memory", "0", "1", "2");
                         break;
                 case 4:
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/todclk.h linux.19p18/include/asm-s390/todclk.h
--- linux.vanilla/include/asm-s390/todclk.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/include/asm-s390/todclk.h	Tue Feb 20 13:26:26 2001
@@ -0,0 +1,19 @@
+/*
+ * File...........: linux/include/asm/todclk.h
+ * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
+ *
+ * History of changes (starts July 2000)
+ */
+
+#ifndef __ASM_TODCLK_H
+#define __ASM_TODCLK_H
+
+#define TOD_uSEC (0x1000ULL)
+#define TOD_mSEC (1000 * TOD_uSEC)
+#define TOD_SEC (1000 * TOD_mSEC)
+#define TOD_MIN (60 * TOD_SEC)
+#define TOD_HOUR (60 * TOD_MIN)
+
+#endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-s390/uaccess.h linux.19p18/include/asm-s390/uaccess.h
--- linux.vanilla/include/asm-s390/uaccess.h	Mon Dec 11 22:13:06 2000
+++ linux.19p18/include/asm-s390/uaccess.h	Tue Feb 27 16:30:13 2001
@@ -505,7 +505,6 @@
 			      : "cc", "0", "4" );
         return n;
 }
-#define strlen_user(str) strnlen_user(str, ~0UL)
 
 /*
  * Zero Userspace
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc/asm_offsets.h linux.19p18/include/asm-sparc/asm_offsets.h
--- linux.vanilla/include/asm-sparc/asm_offsets.h	Mon Dec 11 22:13:06 2000
+++ linux.19p18/include/asm-sparc/asm_offsets.h	Tue Jan  9 11:57:27 2001
@@ -40,153 +40,163 @@
 #define ASIZ_task_next_run	0x00000004
 #define AOFF_task_prev_run	0x00000040
 #define ASIZ_task_prev_run	0x00000004
-#define AOFF_task_binfmt	0x00000044
+#define AOFF_task_task_exclusive	0x00000044
+#define ASIZ_task_task_exclusive	0x00000004
+#define AOFF_task_binfmt	0x00000048
 #define ASIZ_task_binfmt	0x00000004
-#define AOFF_task_exit_code	0x00000048
+#define AOFF_task_exit_code	0x0000004c
 #define ASIZ_task_exit_code	0x00000004
-#define AOFF_task_exit_signal	0x0000004c
+#define AOFF_task_exit_signal	0x00000050
 #define ASIZ_task_exit_signal	0x00000004
-#define AOFF_task_pdeath_signal	0x00000050
+#define AOFF_task_pdeath_signal	0x00000054
 #define ASIZ_task_pdeath_signal	0x00000004
-#define AOFF_task_personality	0x00000054
+#define AOFF_task_personality	0x00000058
 #define ASIZ_task_personality	0x00000004
-#define AOFF_task_pid	0x0000005c
+#define AOFF_task_pid	0x00000060
 #define ASIZ_task_pid	0x00000004
-#define AOFF_task_pgrp	0x00000060
+#define AOFF_task_pgrp	0x00000064
 #define ASIZ_task_pgrp	0x00000004
-#define AOFF_task_tty_old_pgrp	0x00000064
+#define AOFF_task_tty_old_pgrp	0x00000068
 #define ASIZ_task_tty_old_pgrp	0x00000004
-#define AOFF_task_session	0x00000068
+#define AOFF_task_session	0x0000006c
 #define ASIZ_task_session	0x00000004
-#define AOFF_task_leader	0x0000006c
+#define AOFF_task_leader	0x00000070
 #define ASIZ_task_leader	0x00000004
-#define AOFF_task_p_opptr	0x00000070
+#define AOFF_task_p_opptr	0x00000074
 #define ASIZ_task_p_opptr	0x00000004
-#define AOFF_task_p_pptr	0x00000074
+#define AOFF_task_p_pptr	0x00000078
 #define ASIZ_task_p_pptr	0x00000004
-#define AOFF_task_p_cptr	0x00000078
+#define AOFF_task_p_cptr	0x0000007c
 #define ASIZ_task_p_cptr	0x00000004
-#define AOFF_task_p_ysptr	0x0000007c
+#define AOFF_task_p_ysptr	0x00000080
 #define ASIZ_task_p_ysptr	0x00000004
-#define AOFF_task_p_osptr	0x00000080
+#define AOFF_task_p_osptr	0x00000084
 #define ASIZ_task_p_osptr	0x00000004
-#define AOFF_task_pidhash_next	0x00000084
+#define AOFF_task_pidhash_next	0x00000088
 #define ASIZ_task_pidhash_next	0x00000004
-#define AOFF_task_pidhash_pprev	0x00000088
+#define AOFF_task_pidhash_pprev	0x0000008c
 #define ASIZ_task_pidhash_pprev	0x00000004
-#define AOFF_task_tarray_ptr	0x0000008c
+#define AOFF_task_tarray_ptr	0x00000090
 #define ASIZ_task_tarray_ptr	0x00000004
-#define AOFF_task_wait_chldexit	0x00000090
+#define AOFF_task_wait_chldexit	0x00000094
 #define ASIZ_task_wait_chldexit	0x00000004
-#define AOFF_task_vfork_sem	0x00000094
+#define AOFF_task_vfork_sem	0x00000098
 #define ASIZ_task_vfork_sem	0x00000004
-#define AOFF_task_policy	0x00000098
+#define AOFF_task_policy	0x0000009c
 #define ASIZ_task_policy	0x00000004
-#define AOFF_task_rt_priority	0x0000009c
+#define AOFF_task_rt_priority	0x000000a0
 #define ASIZ_task_rt_priority	0x00000004
-#define AOFF_task_it_real_value	0x000000a0
+#define AOFF_task_it_real_value	0x000000a4
 #define ASIZ_task_it_real_value	0x00000004
-#define AOFF_task_it_prof_value	0x000000a4
+#define AOFF_task_it_prof_value	0x000000a8
 #define ASIZ_task_it_prof_value	0x00000004
-#define AOFF_task_it_virt_value	0x000000a8
+#define AOFF_task_it_virt_value	0x000000ac
 #define ASIZ_task_it_virt_value	0x00000004
-#define AOFF_task_it_real_incr	0x000000ac
+#define AOFF_task_it_real_incr	0x000000b0
 #define ASIZ_task_it_real_incr	0x00000004
-#define AOFF_task_it_prof_incr	0x000000b0
+#define AOFF_task_it_prof_incr	0x000000b4
 #define ASIZ_task_it_prof_incr	0x00000004
-#define AOFF_task_it_virt_incr	0x000000b4
+#define AOFF_task_it_virt_incr	0x000000b8
 #define ASIZ_task_it_virt_incr	0x00000004
-#define AOFF_task_real_timer	0x000000b8
+#define AOFF_task_real_timer	0x000000bc
 #define ASIZ_task_real_timer	0x00000014
-#define AOFF_task_times	0x000000cc
+#define AOFF_task_times	0x000000d0
 #define ASIZ_task_times	0x00000010
-#define AOFF_task_start_time	0x000000dc
+#define AOFF_task_start_time	0x000000e0
 #define ASIZ_task_start_time	0x00000004
-#define AOFF_task_per_cpu_utime	0x000000e0
+#define AOFF_task_per_cpu_utime	0x000000e4
 #define ASIZ_task_per_cpu_utime	0x00000004
-#define AOFF_task_min_flt	0x000000e8
+#define AOFF_task_min_flt	0x000000ec
 #define ASIZ_task_min_flt	0x00000004
-#define AOFF_task_maj_flt	0x000000ec
+#define AOFF_task_maj_flt	0x000000f0
 #define ASIZ_task_maj_flt	0x00000004
-#define AOFF_task_nswap	0x000000f0
+#define AOFF_task_nswap	0x000000f4
 #define ASIZ_task_nswap	0x00000004
-#define AOFF_task_cmin_flt	0x000000f4
+#define AOFF_task_cmin_flt	0x000000f8
 #define ASIZ_task_cmin_flt	0x00000004
-#define AOFF_task_cmaj_flt	0x000000f8
+#define AOFF_task_cmaj_flt	0x000000fc
 #define ASIZ_task_cmaj_flt	0x00000004
-#define AOFF_task_cnswap	0x000000fc
+#define AOFF_task_cnswap	0x00000100
 #define ASIZ_task_cnswap	0x00000004
-#define AOFF_task_uid	0x00000102
+#define AOFF_task_uid	0x00000106
 #define ASIZ_task_uid	0x00000002
-#define AOFF_task_euid	0x00000104
+#define AOFF_task_euid	0x00000108
 #define ASIZ_task_euid	0x00000002
-#define AOFF_task_suid	0x00000106
+#define AOFF_task_suid	0x0000010a
 #define ASIZ_task_suid	0x00000002
-#define AOFF_task_fsuid	0x00000108
+#define AOFF_task_fsuid	0x0000010c
 #define ASIZ_task_fsuid	0x00000002
-#define AOFF_task_gid	0x0000010a
+#define AOFF_task_gid	0x0000010e
 #define ASIZ_task_gid	0x00000002
-#define AOFF_task_egid	0x0000010c
+#define AOFF_task_egid	0x00000110
 #define ASIZ_task_egid	0x00000002
-#define AOFF_task_sgid	0x0000010e
+#define AOFF_task_sgid	0x00000112
 #define ASIZ_task_sgid	0x00000002
-#define AOFF_task_fsgid	0x00000110
+#define AOFF_task_fsgid	0x00000114
 #define ASIZ_task_fsgid	0x00000002
-#define AOFF_task_ngroups	0x00000114
+#define AOFF_task_ngroups	0x00000118
 #define ASIZ_task_ngroups	0x00000004
-#define AOFF_task_groups	0x00000118
+#define AOFF_task_groups	0x0000011c
 #define ASIZ_task_groups	0x00000040
-#define AOFF_task_cap_effective	0x00000158
+#define AOFF_task_cap_effective	0x0000015c
 #define ASIZ_task_cap_effective	0x00000004
-#define AOFF_task_cap_inheritable	0x0000015c
+#define AOFF_task_cap_inheritable	0x00000160
 #define ASIZ_task_cap_inheritable	0x00000004
-#define AOFF_task_cap_permitted	0x00000160
+#define AOFF_task_cap_permitted	0x00000164
 #define ASIZ_task_cap_permitted	0x00000004
-#define AOFF_task_user	0x00000168
+#define AOFF_task_user	0x0000016c
 #define ASIZ_task_user	0x00000004
-#define AOFF_task_rlim	0x0000016c
+#define AOFF_task_rlim	0x00000170
 #define ASIZ_task_rlim	0x00000050
-#define AOFF_task_used_math	0x000001bc
+#define AOFF_task_used_math	0x000001c0
 #define ASIZ_task_used_math	0x00000002
-#define AOFF_task_comm	0x000001be
+#define AOFF_task_comm	0x000001c2
 #define ASIZ_task_comm	0x00000010
-#define AOFF_task_link_count	0x000001d0
+#define AOFF_task_link_count	0x000001d4
 #define ASIZ_task_link_count	0x00000004
-#define AOFF_task_tty	0x000001d4
+#define AOFF_task_tty	0x000001d8
 #define ASIZ_task_tty	0x00000004
-#define AOFF_task_semundo	0x000001d8
+#define AOFF_task_semundo	0x000001dc
 #define ASIZ_task_semundo	0x00000004
-#define AOFF_task_semsleeping	0x000001dc
+#define AOFF_task_semsleeping	0x000001e0
 #define ASIZ_task_semsleeping	0x00000004
-#define AOFF_task_tss	0x000001e0
+#define AOFF_task_tss	0x000001e8
 #define ASIZ_task_tss	0x00000388
-#define AOFF_task_fs	0x00000568
+#define AOFF_task_fs	0x00000570
 #define ASIZ_task_fs	0x00000004
-#define AOFF_task_files	0x0000056c
+#define AOFF_task_files	0x00000574
 #define ASIZ_task_files	0x00000004
-#define AOFF_task_mm	0x00000570
+#define AOFF_task_mm	0x00000578
 #define ASIZ_task_mm	0x00000004
-#define AOFF_task_sigmask_lock	0x00000574
+#define AOFF_task_local_pages	0x0000057c
+#define ASIZ_task_local_pages	0x00000008
+#define AOFF_task_allocation_order	0x00000584
+#define ASIZ_task_allocation_order	0x00000004
+#define AOFF_task_nr_local_pages	0x00000588
+#define ASIZ_task_nr_local_pages	0x00000004
+#define AOFF_task_fs_locks	0x0000058c
+#define ASIZ_task_fs_locks	0x00000004
+#define AOFF_task_sigmask_lock	0x00000590
 #define ASIZ_task_sigmask_lock	0x00000001
-#define AOFF_task_sig	0x00000578
+#define AOFF_task_sig	0x00000594
 #define ASIZ_task_sig	0x00000004
-#define AOFF_task_signal	0x0000057c
+#define AOFF_task_signal	0x00000598
 #define ASIZ_task_signal	0x00000008
-#define AOFF_task_blocked	0x00000584
+#define AOFF_task_blocked	0x000005a0
 #define ASIZ_task_blocked	0x00000008
-#define AOFF_task_sigqueue	0x0000058c
+#define AOFF_task_sigqueue	0x000005a8
 #define ASIZ_task_sigqueue	0x00000004
-#define AOFF_task_sigqueue_tail	0x00000590
+#define AOFF_task_sigqueue_tail	0x000005ac
 #define ASIZ_task_sigqueue_tail	0x00000004
-#define AOFF_task_sas_ss_sp	0x00000594
+#define AOFF_task_sas_ss_sp	0x000005b0
 #define ASIZ_task_sas_ss_sp	0x00000004
-#define AOFF_task_sas_ss_size	0x00000598
+#define AOFF_task_sas_ss_size	0x000005b4
 #define ASIZ_task_sas_ss_size	0x00000004
-#define AOFF_task_parent_exec_id	0x0000059c
+#define AOFF_task_parent_exec_id	0x000005b8
 #define ASIZ_task_parent_exec_id	0x00000004
-#define AOFF_task_self_exec_id	0x000005a0
+#define AOFF_task_self_exec_id	0x000005bc
 #define ASIZ_task_self_exec_id	0x00000004
-#define AOFF_task_oom_kill_try	0x000005a4
+#define AOFF_task_oom_kill_try	0x000005c0
 #define ASIZ_task_oom_kill_try	0x00000004
 #define AOFF_mm_mmap	0x00000000
 #define ASIZ_mm_mmap	0x00000004
@@ -321,153 +331,163 @@
 #define ASIZ_task_next_run	0x00000004
 #define AOFF_task_prev_run	0x00000040
 #define ASIZ_task_prev_run	0x00000004
-#define AOFF_task_binfmt	0x00000044
+#define AOFF_task_task_exclusive	0x00000044
+#define ASIZ_task_task_exclusive	0x00000004
+#define AOFF_task_binfmt	0x00000048
 #define ASIZ_task_binfmt	0x00000004
-#define AOFF_task_exit_code	0x00000048
+#define AOFF_task_exit_code	0x0000004c
 #define ASIZ_task_exit_code	0x00000004
-#define AOFF_task_exit_signal	0x0000004c
+#define AOFF_task_exit_signal	0x00000050
 #define ASIZ_task_exit_signal	0x00000004
-#define AOFF_task_pdeath_signal	0x00000050
+#define AOFF_task_pdeath_signal	0x00000054
 #define ASIZ_task_pdeath_signal	0x00000004
-#define AOFF_task_personality	0x00000054
+#define AOFF_task_personality	0x00000058
 #define ASIZ_task_personality	0x00000004
-#define AOFF_task_pid	0x0000005c
+#define AOFF_task_pid	0x00000060
 #define ASIZ_task_pid	0x00000004
-#define AOFF_task_pgrp	0x00000060
+#define AOFF_task_pgrp	0x00000064
 #define ASIZ_task_pgrp	0x00000004
-#define AOFF_task_tty_old_pgrp	0x00000064
+#define AOFF_task_tty_old_pgrp	0x00000068
 #define ASIZ_task_tty_old_pgrp	0x00000004
-#define AOFF_task_session	0x00000068
+#define AOFF_task_session	0x0000006c
 #define ASIZ_task_session	0x00000004
-#define AOFF_task_leader	0x0000006c
+#define AOFF_task_leader	0x00000070
 #define ASIZ_task_leader	0x00000004
-#define AOFF_task_p_opptr	0x00000070
+#define AOFF_task_p_opptr	0x00000074
 #define ASIZ_task_p_opptr	0x00000004
-#define AOFF_task_p_pptr	0x00000074
+#define AOFF_task_p_pptr	0x00000078
 #define ASIZ_task_p_pptr	0x00000004
-#define AOFF_task_p_cptr	0x00000078
+#define AOFF_task_p_cptr	0x0000007c
 #define ASIZ_task_p_cptr	0x00000004
-#define AOFF_task_p_ysptr	0x0000007c
+#define AOFF_task_p_ysptr	0x00000080
 #define ASIZ_task_p_ysptr	0x00000004
-#define AOFF_task_p_osptr	0x00000080
+#define AOFF_task_p_osptr	0x00000084
 #define ASIZ_task_p_osptr	0x00000004
-#define AOFF_task_pidhash_next	0x00000084
+#define AOFF_task_pidhash_next	0x00000088
 #define ASIZ_task_pidhash_next	0x00000004
-#define AOFF_task_pidhash_pprev	0x00000088
+#define AOFF_task_pidhash_pprev	0x0000008c
 #define ASIZ_task_pidhash_pprev	0x00000004
-#define AOFF_task_tarray_ptr	0x0000008c
+#define AOFF_task_tarray_ptr	0x00000090
 #define ASIZ_task_tarray_ptr	0x00000004
-#define AOFF_task_wait_chldexit	0x00000090
+#define AOFF_task_wait_chldexit	0x00000094
 #define ASIZ_task_wait_chldexit	0x00000004
-#define AOFF_task_vfork_sem	0x00000094
+#define AOFF_task_vfork_sem	0x00000098
 #define ASIZ_task_vfork_sem	0x00000004
-#define AOFF_task_policy	0x00000098
+#define AOFF_task_policy	0x0000009c
 #define ASIZ_task_policy	0x00000004
-#define AOFF_task_rt_priority	0x0000009c
+#define AOFF_task_rt_priority	0x000000a0
 #define ASIZ_task_rt_priority	0x00000004
-#define AOFF_task_it_real_value	0x000000a0
+#define AOFF_task_it_real_value	0x000000a4
 #define ASIZ_task_it_real_value	0x00000004
-#define AOFF_task_it_prof_value	0x000000a4
+#define AOFF_task_it_prof_value	0x000000a8
 #define ASIZ_task_it_prof_value	0x00000004
-#define AOFF_task_it_virt_value	0x000000a8
+#define AOFF_task_it_virt_value	0x000000ac
 #define ASIZ_task_it_virt_value	0x00000004
-#define AOFF_task_it_real_incr	0x000000ac
+#define AOFF_task_it_real_incr	0x000000b0
 #define ASIZ_task_it_real_incr	0x00000004
-#define AOFF_task_it_prof_incr	0x000000b0
+#define AOFF_task_it_prof_incr	0x000000b4
 #define ASIZ_task_it_prof_incr	0x00000004
-#define AOFF_task_it_virt_incr	0x000000b4
+#define AOFF_task_it_virt_incr	0x000000b8
 #define ASIZ_task_it_virt_incr	0x00000004
-#define AOFF_task_real_timer	0x000000b8
+#define AOFF_task_real_timer	0x000000bc
 #define ASIZ_task_real_timer	0x00000014
-#define AOFF_task_times	0x000000cc
+#define AOFF_task_times	0x000000d0
 #define ASIZ_task_times	0x00000010
-#define AOFF_task_start_time	0x000000dc
+#define AOFF_task_start_time	0x000000e0
 #define ASIZ_task_start_time	0x00000004
-#define AOFF_task_per_cpu_utime	0x000000e0
+#define AOFF_task_per_cpu_utime	0x000000e4
 #define ASIZ_task_per_cpu_utime	0x00000080
-#define AOFF_task_min_flt	0x000001e0
+#define AOFF_task_min_flt	0x000001e4
 #define ASIZ_task_min_flt	0x00000004
-#define AOFF_task_maj_flt	0x000001e4
+#define AOFF_task_maj_flt	0x000001e8
 #define ASIZ_task_maj_flt	0x00000004
-#define AOFF_task_nswap	0x000001e8
+#define AOFF_task_nswap	0x000001ec
 #define ASIZ_task_nswap	0x00000004
-#define AOFF_task_cmin_flt	0x000001ec
+#define AOFF_task_cmin_flt	0x000001f0
 #define ASIZ_task_cmin_flt	0x00000004
-#define AOFF_task_cmaj_flt	0x000001f0
+#define AOFF_task_cmaj_flt	0x000001f4
 #define ASIZ_task_cmaj_flt	0x00000004
-#define AOFF_task_cnswap	0x000001f4
+#define AOFF_task_cnswap	0x000001f8
 #define ASIZ_task_cnswap	0x00000004
-#define AOFF_task_uid	0x000001fa
+#define AOFF_task_uid	0x000001fe
 #define ASIZ_task_uid	0x00000002
-#define AOFF_task_euid	0x000001fc
+#define AOFF_task_euid	0x00000200
 #define ASIZ_task_euid	0x00000002
-#define AOFF_task_suid	0x000001fe
+#define AOFF_task_suid	0x00000202
 #define ASIZ_task_suid	0x00000002
-#define AOFF_task_fsuid	0x00000200
+#define AOFF_task_fsuid	0x00000204
 #define ASIZ_task_fsuid	0x00000002
-#define AOFF_task_gid	0x00000202
+#define AOFF_task_gid	0x00000206
 #define ASIZ_task_gid	0x00000002
-#define AOFF_task_egid	0x00000204
+#define AOFF_task_egid	0x00000208
 #define ASIZ_task_egid	0x00000002
-#define AOFF_task_sgid	0x00000206
+#define AOFF_task_sgid	0x0000020a
 #define ASIZ_task_sgid	0x00000002
-#define AOFF_task_fsgid	0x00000208
+#define AOFF_task_fsgid	0x0000020c
 #define ASIZ_task_fsgid	0x00000002
-#define AOFF_task_ngroups	0x0000020c
+#define AOFF_task_ngroups	0x00000210
 #define ASIZ_task_ngroups	0x00000004
-#define AOFF_task_groups	0x00000210
+#define AOFF_task_groups	0x00000214
 #define ASIZ_task_groups	0x00000040
-#define AOFF_task_cap_effective	0x00000250
+#define AOFF_task_cap_effective	0x00000254
 #define ASIZ_task_cap_effective	0x00000004
-#define AOFF_task_cap_inheritable	0x00000254
+#define AOFF_task_cap_inheritable	0x00000258
 #define ASIZ_task_cap_inheritable	0x00000004
-#define AOFF_task_cap_permitted	0x00000258
+#define AOFF_task_cap_permitted	0x0000025c
 #define ASIZ_task_cap_permitted	0x00000004
-#define AOFF_task_user	0x00000260
+#define AOFF_task_user	0x00000264
 #define ASIZ_task_user	0x00000004
-#define AOFF_task_rlim	0x00000264
+#define AOFF_task_rlim	0x00000268
 #define ASIZ_task_rlim	0x00000050
-#define AOFF_task_used_math	0x000002b4
+#define AOFF_task_used_math	0x000002b8
 #define ASIZ_task_used_math	0x00000002
-#define AOFF_task_comm	0x000002b6
+#define AOFF_task_comm	0x000002ba
 #define ASIZ_task_comm	0x00000010
-#define AOFF_task_link_count	0x000002c8
+#define AOFF_task_link_count	0x000002cc
 #define ASIZ_task_link_count	0x00000004
-#define AOFF_task_tty	0x000002cc
+#define AOFF_task_tty	0x000002d0
 #define ASIZ_task_tty	0x00000004
-#define AOFF_task_semundo	0x000002d0
+#define AOFF_task_semundo	0x000002d4
 #define ASIZ_task_semundo	0x00000004
-#define AOFF_task_semsleeping	0x000002d4
+#define AOFF_task_semsleeping	0x000002d8
 #define ASIZ_task_semsleeping	0x00000004
-#define AOFF_task_tss	0x000002d8
+#define AOFF_task_tss	0x000002e0
 #define ASIZ_task_tss	0x00000388
-#define AOFF_task_fs	0x00000660
+#define AOFF_task_fs	0x00000668
 #define ASIZ_task_fs	0x00000004
-#define AOFF_task_files	0x00000664
+#define AOFF_task_files	0x0000066c
 #define ASIZ_task_files	0x00000004
-#define AOFF_task_mm	0x00000668
+#define AOFF_task_mm	0x00000670
 #define ASIZ_task_mm	0x00000004
-#define AOFF_task_sigmask_lock	0x0000066c
+#define AOFF_task_local_pages	0x00000674
+#define ASIZ_task_local_pages	0x00000008
+#define AOFF_task_allocation_order	0x0000067c
+#define ASIZ_task_allocation_order	0x00000004
+#define AOFF_task_nr_local_pages	0x00000680
+#define ASIZ_task_nr_local_pages	0x00000004
+#define AOFF_task_fs_locks	0x00000684
+#define ASIZ_task_fs_locks	0x00000004
+#define AOFF_task_sigmask_lock	0x00000688
 #define ASIZ_task_sigmask_lock	0x00000001
-#define AOFF_task_sig	0x00000670
+#define AOFF_task_sig	0x0000068c
 #define ASIZ_task_sig	0x00000004
-#define AOFF_task_signal	0x00000674
+#define AOFF_task_signal	0x00000690
 #define ASIZ_task_signal	0x00000008
-#define AOFF_task_blocked	0x0000067c
+#define AOFF_task_blocked	0x00000698
 #define ASIZ_task_blocked	0x00000008
-#define AOFF_task_sigqueue	0x00000684
+#define AOFF_task_sigqueue	0x000006a0
 #define ASIZ_task_sigqueue	0x00000004
-#define AOFF_task_sigqueue_tail	0x00000688
+#define AOFF_task_sigqueue_tail	0x000006a4
 #define ASIZ_task_sigqueue_tail	0x00000004
-#define AOFF_task_sas_ss_sp	0x0000068c
+#define AOFF_task_sas_ss_sp	0x000006a8
 #define ASIZ_task_sas_ss_sp	0x00000004
-#define AOFF_task_sas_ss_size	0x00000690
+#define AOFF_task_sas_ss_size	0x000006ac
 #define ASIZ_task_sas_ss_size	0x00000004
-#define AOFF_task_parent_exec_id	0x00000694
+#define AOFF_task_parent_exec_id	0x000006b0
 #define ASIZ_task_parent_exec_id	0x00000004
-#define AOFF_task_self_exec_id	0x00000698
+#define AOFF_task_self_exec_id	0x000006b4
 #define ASIZ_task_self_exec_id	0x00000004
-#define AOFF_task_oom_kill_try	0x0000069c
+#define AOFF_task_oom_kill_try	0x000006b8
 #define ASIZ_task_oom_kill_try	0x00000004
 #define AOFF_mm_mmap	0x00000000
 #define ASIZ_mm_mmap	0x00000004
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc/audioio.h linux.19p18/include/asm-sparc/audioio.h
--- linux.vanilla/include/asm-sparc/audioio.h	Sun Jun 11 21:44:23 2000
+++ linux.19p18/include/asm-sparc/audioio.h	Tue Jan  9 11:57:27 2001
@@ -432,6 +432,7 @@
 extern void sparcaudio_input_done(struct sparcaudio_driver *, int);
 extern int sparcaudio_init(void);
 extern int amd7930_init(void);
+extern int dbri_init(void);
 extern int cs4231_init(void);
 
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc/page.h linux.19p18/include/asm-sparc/page.h
--- linux.vanilla/include/asm-sparc/page.h	Fri Apr 21 12:46:50 2000
+++ linux.19p18/include/asm-sparc/page.h	Tue Feb 20 13:28:55 2001
@@ -1,4 +1,4 @@
-/* $Id: page.h,v 1.43 1998/05/11 08:40:11 davem Exp $
+/* $Id: page.h,v 1.43.2.1 2001/02/20 04:21:45 davem Exp $
  * page.h:  Various defines and such for MMU operations on the Sparc for
  *          the Linux kernel.
  *
@@ -27,6 +27,10 @@
 #define TASK_UNION_SIZE		8192
 
 #ifndef __ASSEMBLY__
+
+#define BUG() do { \
+	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); *(int *)0=0; \
+} while (0)
 
 #define clear_page(page)	memset((void *)(page), 0, PAGE_SIZE)
 #define copy_page(to,from)	memcpy((void *)(to), (void *)(from), PAGE_SIZE)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc/siginfo.h linux.19p18/include/asm-sparc/siginfo.h
--- linux.vanilla/include/asm-sparc/siginfo.h	Fri Apr 21 12:46:50 2000
+++ linux.19p18/include/asm-sparc/siginfo.h	Tue Feb 27 21:59:16 2001
@@ -93,8 +93,8 @@
 #define SI_ASYNCIO	-4	/* sent by AIO completion */
 #define SI_SIGIO	-5	/* sent by queued SIGIO */
 
-#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
-#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
+#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0 && (siptr)->si_code != SI_SIGIO)
+#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0 || (siptr)->si_code == SI_SIGIO)
 
 /*
  * SIGILL si_codes
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc/uaccess.h linux.19p18/include/asm-sparc/uaccess.h
--- linux.vanilla/include/asm-sparc/uaccess.h	Fri Apr 21 12:46:50 2000
+++ linux.19p18/include/asm-sparc/uaccess.h	Tue Feb 27 16:30:14 2001
@@ -383,16 +383,7 @@
 __sfu_res = __strncpy_from_user((unsigned long) (dest), __sfu_src, __sfu_count); \
 } __sfu_res; })
 
-extern int __strlen_user(const char *);
 extern int __strnlen_user(const char *, long len);
-
-extern __inline__ int strlen_user(const char *str)
-{
-	if(!access_ok(VERIFY_READ, str, 0))
-		return 0;
-	else
-		return __strlen_user(str);
-}
 
 extern __inline__ int strnlen_user(const char *str, long len)
 {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc/unistd.h linux.19p18/include/asm-sparc/unistd.h
--- linux.vanilla/include/asm-sparc/unistd.h	Fri Apr 21 12:46:50 2000
+++ linux.19p18/include/asm-sparc/unistd.h	Wed Feb  7 09:45:38 2001
@@ -1,4 +1,4 @@
-/* $Id: unistd.h,v 1.55 1999/04/07 17:14:15 davem Exp $ */
+/* $Id: unistd.h,v 1.55.2.2 2001/01/11 19:12:10 davem Exp $ */
 #ifndef _SPARC_UNISTD_H
 #define _SPARC_UNISTD_H
 
@@ -59,7 +59,7 @@
 #define __NR_dup                 41 /* Common                                      */
 #define __NR_pipe                42 /* Common                                      */
 #define __NR_times               43 /* Implemented via getrusage() in SunOS        */
-/* #define __NR_profil           44    Common                                      */
+/* #define __NR_getuid32         44    Linux Sparc32 Specific                      */
 #define __NR_umount2             45 /* Linux Specific                              */
 #define __NR_setgid              46 /* Implemented via setregid() in SunOS         */
 #define __NR_getgid              47 /* Common                                      */
@@ -169,8 +169,8 @@
 /* #define __NR_getmsg          151    SunOS Specific                              */
 /* #define __NR_putmsg          152    SunOS Specific                              */
 #define __NR_poll               153 /* Common                                      */
-/* #define __NR_ni_syscall      154    ENOSYS under SunOS                          */
-/* #define __NR_nfssvc          155    SunOS Specific                              */
+/* #define __NR_getdents64      154    Linux Sparc32 Specific                      */
+/* #define __NR_fcntl64         155    Linux Sparc32 Specific                      */
 /* #define __NR_getdirentries   156    SunOS Specific                              */
 #define __NR_statfs             157 /* Common                                      */
 #define __NR_fstatfs            158 /* Common                                      */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc64/asm_offsets.h linux.19p18/include/asm-sparc64/asm_offsets.h
--- linux.vanilla/include/asm-sparc64/asm_offsets.h	Fri Apr 21 12:46:50 2000
+++ linux.19p18/include/asm-sparc64/asm_offsets.h	Tue Jan  9 11:57:27 2001
@@ -40,155 +40,165 @@
 #define ASIZ_task_next_run	0x00000008
 #define AOFF_task_prev_run	0x00000070
 #define ASIZ_task_prev_run	0x00000008
-#define AOFF_task_binfmt	0x00000078
+#define AOFF_task_task_exclusive	0x00000078
+#define ASIZ_task_task_exclusive	0x00000004
+#define AOFF_task_binfmt	0x00000080
 #define ASIZ_task_binfmt	0x00000008
-#define AOFF_task_exit_code	0x00000080
+#define AOFF_task_exit_code	0x00000088
 #define ASIZ_task_exit_code	0x00000004
-#define AOFF_task_exit_signal	0x00000084
+#define AOFF_task_exit_signal	0x0000008c
 #define ASIZ_task_exit_signal	0x00000004
-#define AOFF_task_pdeath_signal	0x00000088
+#define AOFF_task_pdeath_signal	0x00000090
 #define ASIZ_task_pdeath_signal	0x00000004
-#define AOFF_task_personality	0x00000090
+#define AOFF_task_personality	0x00000098
 #define ASIZ_task_personality	0x00000008
-#define AOFF_task_pid	0x0000009c
+#define AOFF_task_pid	0x000000a4
 #define ASIZ_task_pid	0x00000004
-#define AOFF_task_pgrp	0x000000a0
+#define AOFF_task_pgrp	0x000000a8
 #define ASIZ_task_pgrp	0x00000004
-#define AOFF_task_tty_old_pgrp	0x000000a4
+#define AOFF_task_tty_old_pgrp	0x000000ac
 #define ASIZ_task_tty_old_pgrp	0x00000004
-#define AOFF_task_session	0x000000a8
+#define AOFF_task_session	0x000000b0
 #define ASIZ_task_session	0x00000004
-#define AOFF_task_leader	0x000000ac
+#define AOFF_task_leader	0x000000b4
 #define ASIZ_task_leader	0x00000004
-#define AOFF_task_p_opptr	0x000000b0
+#define AOFF_task_p_opptr	0x000000b8
 #define ASIZ_task_p_opptr	0x00000008
-#define AOFF_task_p_pptr	0x000000b8
+#define AOFF_task_p_pptr	0x000000c0
 #define ASIZ_task_p_pptr	0x00000008
-#define AOFF_task_p_cptr	0x000000c0
+#define AOFF_task_p_cptr	0x000000c8
 #define ASIZ_task_p_cptr	0x00000008
-#define AOFF_task_p_ysptr	0x000000c8
+#define AOFF_task_p_ysptr	0x000000d0
 #define ASIZ_task_p_ysptr	0x00000008
-#define AOFF_task_p_osptr	0x000000d0
+#define AOFF_task_p_osptr	0x000000d8
 #define ASIZ_task_p_osptr	0x00000008
-#define AOFF_task_pidhash_next	0x000000d8
+#define AOFF_task_pidhash_next	0x000000e0
 #define ASIZ_task_pidhash_next	0x00000008
-#define AOFF_task_pidhash_pprev	0x000000e0
+#define AOFF_task_pidhash_pprev	0x000000e8
 #define ASIZ_task_pidhash_pprev	0x00000008
-#define AOFF_task_tarray_ptr	0x000000e8
+#define AOFF_task_tarray_ptr	0x000000f0
 #define ASIZ_task_tarray_ptr	0x00000008
-#define AOFF_task_wait_chldexit	0x000000f0
+#define AOFF_task_wait_chldexit	0x000000f8
 #define ASIZ_task_wait_chldexit	0x00000008
-#define AOFF_task_vfork_sem	0x000000f8
+#define AOFF_task_vfork_sem	0x00000100
 #define ASIZ_task_vfork_sem	0x00000008
-#define AOFF_task_policy	0x00000100
+#define AOFF_task_policy	0x00000108
 #define ASIZ_task_policy	0x00000008
-#define AOFF_task_rt_priority	0x00000108
+#define AOFF_task_rt_priority	0x00000110
 #define ASIZ_task_rt_priority	0x00000008
-#define AOFF_task_it_real_value	0x00000110
+#define AOFF_task_it_real_value	0x00000118
 #define ASIZ_task_it_real_value	0x00000008
-#define AOFF_task_it_prof_value	0x00000118
+#define AOFF_task_it_prof_value	0x00000120
 #define ASIZ_task_it_prof_value	0x00000008
-#define AOFF_task_it_virt_value	0x00000120
+#define AOFF_task_it_virt_value	0x00000128
 #define ASIZ_task_it_virt_value	0x00000008
-#define AOFF_task_it_real_incr	0x00000128
+#define AOFF_task_it_real_incr	0x00000130
 #define ASIZ_task_it_real_incr	0x00000008
-#define AOFF_task_it_prof_incr	0x00000130
+#define AOFF_task_it_prof_incr	0x00000138
 #define ASIZ_task_it_prof_incr	0x00000008
-#define AOFF_task_it_virt_incr	0x00000138
+#define AOFF_task_it_virt_incr	0x00000140
 #define ASIZ_task_it_virt_incr	0x00000008
-#define AOFF_task_real_timer	0x00000140
+#define AOFF_task_real_timer	0x00000148
 #define ASIZ_task_real_timer	0x00000028
-#define AOFF_task_times	0x00000168
+#define AOFF_task_times	0x00000170
 #define ASIZ_task_times	0x00000020
-#define AOFF_task_start_time	0x00000188
+#define AOFF_task_start_time	0x00000190
 #define ASIZ_task_start_time	0x00000008
-#define AOFF_task_per_cpu_utime	0x00000190
+#define AOFF_task_per_cpu_utime	0x00000198
 #define ASIZ_task_per_cpu_utime	0x00000008
-#define AOFF_task_min_flt	0x000001a0
+#define AOFF_task_min_flt	0x000001a8
 #define ASIZ_task_min_flt	0x00000008
-#define AOFF_task_maj_flt	0x000001a8
+#define AOFF_task_maj_flt	0x000001b0
 #define ASIZ_task_maj_flt	0x00000008
-#define AOFF_task_nswap	0x000001b0
+#define AOFF_task_nswap	0x000001b8
 #define ASIZ_task_nswap	0x00000008
-#define AOFF_task_cmin_flt	0x000001b8
+#define AOFF_task_cmin_flt	0x000001c0
 #define ASIZ_task_cmin_flt	0x00000008
-#define AOFF_task_cmaj_flt	0x000001c0
+#define AOFF_task_cmaj_flt	0x000001c8
 #define ASIZ_task_cmaj_flt	0x00000008
-#define AOFF_task_cnswap	0x000001c8
+#define AOFF_task_cnswap	0x000001d0
 #define ASIZ_task_cnswap	0x00000008
-#define AOFF_task_uid	0x000001d4
+#define AOFF_task_uid	0x000001dc
 #define ASIZ_task_uid	0x00000004
-#define AOFF_task_euid	0x000001d8
+#define AOFF_task_euid	0x000001e0
 #define ASIZ_task_euid	0x00000004
-#define AOFF_task_suid	0x000001dc
+#define AOFF_task_suid	0x000001e4
 #define ASIZ_task_suid	0x00000004
-#define AOFF_task_fsuid	0x000001e0
+#define AOFF_task_fsuid	0x000001e8
 #define ASIZ_task_fsuid	0x00000004
-#define AOFF_task_gid	0x000001e4
+#define AOFF_task_gid	0x000001ec
 #define ASIZ_task_gid	0x00000004
-#define AOFF_task_egid	0x000001e8
+#define AOFF_task_egid	0x000001f0
 #define ASIZ_task_egid	0x00000004
-#define AOFF_task_sgid	0x000001ec
+#define AOFF_task_sgid	0x000001f4
 #define ASIZ_task_sgid	0x00000004
-#define AOFF_task_fsgid	0x000001f0
+#define AOFF_task_fsgid	0x000001f8
 #define ASIZ_task_fsgid	0x00000004
-#define AOFF_task_ngroups	0x000001f4
+#define AOFF_task_ngroups	0x000001fc
 #define ASIZ_task_ngroups	0x00000004
-#define AOFF_task_groups	0x000001f8
+#define AOFF_task_groups	0x00000200
 #define ASIZ_task_groups	0x00000080
-#define AOFF_task_cap_effective	0x00000278
+#define AOFF_task_cap_effective	0x00000280
 #define ASIZ_task_cap_effective	0x00000004
-#define AOFF_task_cap_inheritable	0x0000027c
+#define AOFF_task_cap_inheritable	0x00000284
 #define ASIZ_task_cap_inheritable	0x00000004
-#define AOFF_task_cap_permitted	0x00000280
+#define AOFF_task_cap_permitted	0x00000288
 #define ASIZ_task_cap_permitted	0x00000004
-#define AOFF_task_user	0x00000288
+#define AOFF_task_user	0x00000290
 #define ASIZ_task_user	0x00000008
-#define AOFF_task_rlim	0x00000290
+#define AOFF_task_rlim	0x00000298
 #define ASIZ_task_rlim	0x000000a0
-#define AOFF_task_used_math	0x00000330
+#define AOFF_task_used_math	0x00000338
 #define ASIZ_task_used_math	0x00000002
-#define AOFF_task_comm	0x00000332
+#define AOFF_task_comm	0x0000033a
 #define ASIZ_task_comm	0x00000010
-#define AOFF_task_link_count	0x00000344
+#define AOFF_task_link_count	0x0000034c
 #define ASIZ_task_link_count	0x00000004
-#define AOFF_task_tty	0x00000348
+#define AOFF_task_tty	0x00000350
 #define ASIZ_task_tty	0x00000008
-#define AOFF_task_semundo	0x00000350
+#define AOFF_task_semundo	0x00000358
 #define ASIZ_task_semundo	0x00000008
-#define AOFF_task_semsleeping	0x00000358
+#define AOFF_task_semsleeping	0x00000360
 #define ASIZ_task_semsleeping	0x00000008
-#define AOFF_task_tss	0x00000360
+#define AOFF_task_tss	0x00000370
 #define ASIZ_task_tss	0x00000470
-#define AOFF_task_fs	0x000007d0
+#define AOFF_task_fs	0x000007e0
 #define ASIZ_task_fs	0x00000008
-#define AOFF_task_files	0x000007d8
+#define AOFF_task_files	0x000007e8
 #define ASIZ_task_files	0x00000008
-#define AOFF_task_mm	0x000007e0
+#define AOFF_task_mm	0x000007f0
 #define ASIZ_task_mm	0x00000008
-#define AOFF_task_sigmask_lock	0x000007e8
+#define AOFF_task_local_pages	0x000007f8
+#define ASIZ_task_local_pages	0x00000010
+#define AOFF_task_allocation_order	0x00000808
+#define ASIZ_task_allocation_order	0x00000004
+#define AOFF_task_nr_local_pages	0x0000080c
+#define ASIZ_task_nr_local_pages	0x00000004
+#define AOFF_task_fs_locks	0x00000810
+#define ASIZ_task_fs_locks	0x00000004
+#define AOFF_task_sigmask_lock	0x00000814
 #define ASIZ_task_sigmask_lock	0x00000001
-#define AOFF_task_sig	0x000007f0
+#define AOFF_task_sig	0x00000818
 #define ASIZ_task_sig	0x00000008
-#define AOFF_task_signal	0x000007f8
+#define AOFF_task_signal	0x00000820
 #define ASIZ_task_signal	0x00000008
-#define AOFF_task_blocked	0x00000800
+#define AOFF_task_blocked	0x00000828
 #define ASIZ_task_blocked	0x00000008
-#define AOFF_task_sigqueue	0x00000808
+#define AOFF_task_sigqueue	0x00000830
 #define ASIZ_task_sigqueue	0x00000008
-#define AOFF_task_sigqueue_tail	0x00000810
+#define AOFF_task_sigqueue_tail	0x00000838
 #define ASIZ_task_sigqueue_tail	0x00000008
-#define AOFF_task_sas_ss_sp	0x00000818
+#define AOFF_task_sas_ss_sp	0x00000840
 #define ASIZ_task_sas_ss_sp	0x00000008
-#define AOFF_task_sas_ss_size	0x00000820
+#define AOFF_task_sas_ss_size	0x00000848
 #define ASIZ_task_sas_ss_size	0x00000008
-#define AOFF_task_parent_exec_id	0x00000828
+#define AOFF_task_parent_exec_id	0x00000850
 #define ASIZ_task_parent_exec_id	0x00000004
-#define AOFF_task_self_exec_id	0x0000082c
+#define AOFF_task_self_exec_id	0x00000854
 #define ASIZ_task_self_exec_id	0x00000004
-#define AOFF_task_oom_kill_try	0x00000830
+#define AOFF_task_oom_kill_try	0x00000858
 #define ASIZ_task_oom_kill_try	0x00000004
-#define ASIZ_task	0x00000840
+#define ASIZ_task	0x00000860
 #define AOFF_mm_mmap	0x00000000
 #define ASIZ_mm_mmap	0x00000008
 #define AOFF_mm_mmap_avl	0x00000008
@@ -332,155 +342,165 @@
 #define ASIZ_task_next_run	0x00000008
 #define AOFF_task_prev_run	0x00000070
 #define ASIZ_task_prev_run	0x00000008
-#define AOFF_task_binfmt	0x00000078
+#define AOFF_task_task_exclusive	0x00000078
+#define ASIZ_task_task_exclusive	0x00000004
+#define AOFF_task_binfmt	0x00000080
 #define ASIZ_task_binfmt	0x00000008
-#define AOFF_task_exit_code	0x00000080
+#define AOFF_task_exit_code	0x00000088
 #define ASIZ_task_exit_code	0x00000004
-#define AOFF_task_exit_signal	0x00000084
+#define AOFF_task_exit_signal	0x0000008c
 #define ASIZ_task_exit_signal	0x00000004
-#define AOFF_task_pdeath_signal	0x00000088
+#define AOFF_task_pdeath_signal	0x00000090
 #define ASIZ_task_pdeath_signal	0x00000004
-#define AOFF_task_personality	0x00000090
+#define AOFF_task_personality	0x00000098
 #define ASIZ_task_personality	0x00000008
-#define AOFF_task_pid	0x0000009c
+#define AOFF_task_pid	0x000000a4
 #define ASIZ_task_pid	0x00000004
-#define AOFF_task_pgrp	0x000000a0
+#define AOFF_task_pgrp	0x000000a8
 #define ASIZ_task_pgrp	0x00000004
-#define AOFF_task_tty_old_pgrp	0x000000a4
+#define AOFF_task_tty_old_pgrp	0x000000ac
 #define ASIZ_task_tty_old_pgrp	0x00000004
-#define AOFF_task_session	0x000000a8
+#define AOFF_task_session	0x000000b0
 #define ASIZ_task_session	0x00000004
-#define AOFF_task_leader	0x000000ac
+#define AOFF_task_leader	0x000000b4
 #define ASIZ_task_leader	0x00000004
-#define AOFF_task_p_opptr	0x000000b0
+#define AOFF_task_p_opptr	0x000000b8
 #define ASIZ_task_p_opptr	0x00000008
-#define AOFF_task_p_pptr	0x000000b8
+#define AOFF_task_p_pptr	0x000000c0
 #define ASIZ_task_p_pptr	0x00000008
-#define AOFF_task_p_cptr	0x000000c0
+#define AOFF_task_p_cptr	0x000000c8
 #define ASIZ_task_p_cptr	0x00000008
-#define AOFF_task_p_ysptr	0x000000c8
+#define AOFF_task_p_ysptr	0x000000d0
 #define ASIZ_task_p_ysptr	0x00000008
-#define AOFF_task_p_osptr	0x000000d0
+#define AOFF_task_p_osptr	0x000000d8
 #define ASIZ_task_p_osptr	0x00000008
-#define AOFF_task_pidhash_next	0x000000d8
+#define AOFF_task_pidhash_next	0x000000e0
 #define ASIZ_task_pidhash_next	0x00000008
-#define AOFF_task_pidhash_pprev	0x000000e0
+#define AOFF_task_pidhash_pprev	0x000000e8
 #define ASIZ_task_pidhash_pprev	0x00000008
-#define AOFF_task_tarray_ptr	0x000000e8
+#define AOFF_task_tarray_ptr	0x000000f0
 #define ASIZ_task_tarray_ptr	0x00000008
-#define AOFF_task_wait_chldexit	0x000000f0
+#define AOFF_task_wait_chldexit	0x000000f8
 #define ASIZ_task_wait_chldexit	0x00000008
-#define AOFF_task_vfork_sem	0x000000f8
+#define AOFF_task_vfork_sem	0x00000100
 #define ASIZ_task_vfork_sem	0x00000008
-#define AOFF_task_policy	0x00000100
+#define AOFF_task_policy	0x00000108
 #define ASIZ_task_policy	0x00000008
-#define AOFF_task_rt_priority	0x00000108
+#define AOFF_task_rt_priority	0x00000110
 #define ASIZ_task_rt_priority	0x00000008
-#define AOFF_task_it_real_value	0x00000110
+#define AOFF_task_it_real_value	0x00000118
 #define ASIZ_task_it_real_value	0x00000008
-#define AOFF_task_it_prof_value	0x00000118
+#define AOFF_task_it_prof_value	0x00000120
 #define ASIZ_task_it_prof_value	0x00000008
-#define AOFF_task_it_virt_value	0x00000120
+#define AOFF_task_it_virt_value	0x00000128
 #define ASIZ_task_it_virt_value	0x00000008
-#define AOFF_task_it_real_incr	0x00000128
+#define AOFF_task_it_real_incr	0x00000130
 #define ASIZ_task_it_real_incr	0x00000008
-#define AOFF_task_it_prof_incr	0x00000130
+#define AOFF_task_it_prof_incr	0x00000138
 #define ASIZ_task_it_prof_incr	0x00000008
-#define AOFF_task_it_virt_incr	0x00000138
+#define AOFF_task_it_virt_incr	0x00000140
 #define ASIZ_task_it_virt_incr	0x00000008
-#define AOFF_task_real_timer	0x00000140
+#define AOFF_task_real_timer	0x00000148
 #define ASIZ_task_real_timer	0x00000028
-#define AOFF_task_times	0x00000168
+#define AOFF_task_times	0x00000170
 #define ASIZ_task_times	0x00000020
-#define AOFF_task_start_time	0x00000188
+#define AOFF_task_start_time	0x00000190
 #define ASIZ_task_start_time	0x00000008
-#define AOFF_task_per_cpu_utime	0x00000190
+#define AOFF_task_per_cpu_utime	0x00000198
 #define ASIZ_task_per_cpu_utime	0x00000100
-#define AOFF_task_min_flt	0x00000390
+#define AOFF_task_min_flt	0x00000398
 #define ASIZ_task_min_flt	0x00000008
-#define AOFF_task_maj_flt	0x00000398
+#define AOFF_task_maj_flt	0x000003a0
 #define ASIZ_task_maj_flt	0x00000008
-#define AOFF_task_nswap	0x000003a0
+#define AOFF_task_nswap	0x000003a8
 #define ASIZ_task_nswap	0x00000008
-#define AOFF_task_cmin_flt	0x000003a8
+#define AOFF_task_cmin_flt	0x000003b0
 #define ASIZ_task_cmin_flt	0x00000008
-#define AOFF_task_cmaj_flt	0x000003b0
+#define AOFF_task_cmaj_flt	0x000003b8
 #define ASIZ_task_cmaj_flt	0x00000008
-#define AOFF_task_cnswap	0x000003b8
+#define AOFF_task_cnswap	0x000003c0
 #define ASIZ_task_cnswap	0x00000008
-#define AOFF_task_uid	0x000003c4
+#define AOFF_task_uid	0x000003cc
 #define ASIZ_task_uid	0x00000004
-#define AOFF_task_euid	0x000003c8
+#define AOFF_task_euid	0x000003d0
 #define ASIZ_task_euid	0x00000004
-#define AOFF_task_suid	0x000003cc
+#define AOFF_task_suid	0x000003d4
 #define ASIZ_task_suid	0x00000004
-#define AOFF_task_fsuid	0x000003d0
+#define AOFF_task_fsuid	0x000003d8
 #define ASIZ_task_fsuid	0x00000004
-#define AOFF_task_gid	0x000003d4
+#define AOFF_task_gid	0x000003dc
 #define ASIZ_task_gid	0x00000004
-#define AOFF_task_egid	0x000003d8
+#define AOFF_task_egid	0x000003e0
 #define ASIZ_task_egid	0x00000004
-#define AOFF_task_sgid	0x000003dc
+#define AOFF_task_sgid	0x000003e4
 #define ASIZ_task_sgid	0x00000004
-#define AOFF_task_fsgid	0x000003e0
+#define AOFF_task_fsgid	0x000003e8
 #define ASIZ_task_fsgid	0x00000004
-#define AOFF_task_ngroups	0x000003e4
+#define AOFF_task_ngroups	0x000003ec
 #define ASIZ_task_ngroups	0x00000004
-#define AOFF_task_groups	0x000003e8
+#define AOFF_task_groups	0x000003f0
 #define ASIZ_task_groups	0x00000080
-#define AOFF_task_cap_effective	0x00000468
+#define AOFF_task_cap_effective	0x00000470
 #define ASIZ_task_cap_effective	0x00000004
-#define AOFF_task_cap_inheritable	0x0000046c
+#define AOFF_task_cap_inheritable	0x00000474
 #define ASIZ_task_cap_inheritable	0x00000004
-#define AOFF_task_cap_permitted	0x00000470
+#define AOFF_task_cap_permitted	0x00000478
 #define ASIZ_task_cap_permitted	0x00000004
-#define AOFF_task_user	0x00000478
+#define AOFF_task_user	0x00000480
 #define ASIZ_task_user	0x00000008
-#define AOFF_task_rlim	0x00000480
+#define AOFF_task_rlim	0x00000488
 #define ASIZ_task_rlim	0x000000a0
-#define AOFF_task_used_math	0x00000520
+#define AOFF_task_used_math	0x00000528
 #define ASIZ_task_used_math	0x00000002
-#define AOFF_task_comm	0x00000522
+#define AOFF_task_comm	0x0000052a
 #define ASIZ_task_comm	0x00000010
-#define AOFF_task_link_count	0x00000534
+#define AOFF_task_link_count	0x0000053c
 #define ASIZ_task_link_count	0x00000004
-#define AOFF_task_tty	0x00000538
+#define AOFF_task_tty	0x00000540
 #define ASIZ_task_tty	0x00000008
-#define AOFF_task_semundo	0x00000540
+#define AOFF_task_semundo	0x00000548
 #define ASIZ_task_semundo	0x00000008
-#define AOFF_task_semsleeping	0x00000548
+#define AOFF_task_semsleeping	0x00000550
 #define ASIZ_task_semsleeping	0x00000008
-#define AOFF_task_tss	0x00000550
+#define AOFF_task_tss	0x00000560
 #define ASIZ_task_tss	0x00000470
-#define AOFF_task_fs	0x000009c0
+#define AOFF_task_fs	0x000009d0
 #define ASIZ_task_fs	0x00000008
-#define AOFF_task_files	0x000009c8
+#define AOFF_task_files	0x000009d8
 #define ASIZ_task_files	0x00000008
-#define AOFF_task_mm	0x000009d0
+#define AOFF_task_mm	0x000009e0
 #define ASIZ_task_mm	0x00000008
-#define AOFF_task_sigmask_lock	0x000009d8
+#define AOFF_task_local_pages	0x000009e8
+#define ASIZ_task_local_pages	0x00000010
+#define AOFF_task_allocation_order	0x000009f8
+#define ASIZ_task_allocation_order	0x00000004
+#define AOFF_task_nr_local_pages	0x000009fc
+#define ASIZ_task_nr_local_pages	0x00000004
+#define AOFF_task_fs_locks	0x00000a00
+#define ASIZ_task_fs_locks	0x00000004
+#define AOFF_task_sigmask_lock	0x00000a04
 #define ASIZ_task_sigmask_lock	0x00000001
-#define AOFF_task_sig	0x000009e0
+#define AOFF_task_sig	0x00000a08
 #define ASIZ_task_sig	0x00000008
-#define AOFF_task_signal	0x000009e8
+#define AOFF_task_signal	0x00000a10
 #define ASIZ_task_signal	0x00000008
-#define AOFF_task_blocked	0x000009f0
+#define AOFF_task_blocked	0x00000a18
 #define ASIZ_task_blocked	0x00000008
-#define AOFF_task_sigqueue	0x000009f8
+#define AOFF_task_sigqueue	0x00000a20
 #define ASIZ_task_sigqueue	0x00000008
-#define AOFF_task_sigqueue_tail	0x00000a00
+#define AOFF_task_sigqueue_tail	0x00000a28
 #define ASIZ_task_sigqueue_tail	0x00000008
-#define AOFF_task_sas_ss_sp	0x00000a08
+#define AOFF_task_sas_ss_sp	0x00000a30
 #define ASIZ_task_sas_ss_sp	0x00000008
-#define AOFF_task_sas_ss_size	0x00000a10
+#define AOFF_task_sas_ss_size	0x00000a38
 #define ASIZ_task_sas_ss_size	0x00000008
-#define AOFF_task_parent_exec_id	0x00000a18
+#define AOFF_task_parent_exec_id	0x00000a40
 #define ASIZ_task_parent_exec_id	0x00000004
-#define AOFF_task_self_exec_id	0x00000a1c
+#define AOFF_task_self_exec_id	0x00000a44
 #define ASIZ_task_self_exec_id	0x00000004
-#define AOFF_task_oom_kill_try	0x00000a20
+#define AOFF_task_oom_kill_try	0x00000a48
 #define ASIZ_task_oom_kill_try	0x00000004
-#define ASIZ_task	0x00000a30
+#define ASIZ_task	0x00000a50
 #define AOFF_mm_mmap	0x00000000
 #define ASIZ_mm_mmap	0x00000008
 #define AOFF_mm_mmap_avl	0x00000008
@@ -622,155 +642,165 @@
 #define ASIZ_task_next_run	0x00000008
 #define AOFF_task_prev_run	0x00000070
 #define ASIZ_task_prev_run	0x00000008
-#define AOFF_task_binfmt	0x00000078
+#define AOFF_task_task_exclusive	0x00000078
+#define ASIZ_task_task_exclusive	0x00000004
+#define AOFF_task_binfmt	0x00000080
 #define ASIZ_task_binfmt	0x00000008
-#define AOFF_task_exit_code	0x00000080
+#define AOFF_task_exit_code	0x00000088
 #define ASIZ_task_exit_code	0x00000004
-#define AOFF_task_exit_signal	0x00000084
+#define AOFF_task_exit_signal	0x0000008c
 #define ASIZ_task_exit_signal	0x00000004
-#define AOFF_task_pdeath_signal	0x00000088
+#define AOFF_task_pdeath_signal	0x00000090
 #define ASIZ_task_pdeath_signal	0x00000004
-#define AOFF_task_personality	0x00000090
+#define AOFF_task_personality	0x00000098
 #define ASIZ_task_personality	0x00000008
-#define AOFF_task_pid	0x0000009c
+#define AOFF_task_pid	0x000000a4
 #define ASIZ_task_pid	0x00000004
-#define AOFF_task_pgrp	0x000000a0
+#define AOFF_task_pgrp	0x000000a8
 #define ASIZ_task_pgrp	0x00000004
-#define AOFF_task_tty_old_pgrp	0x000000a4
+#define AOFF_task_tty_old_pgrp	0x000000ac
 #define ASIZ_task_tty_old_pgrp	0x00000004
-#define AOFF_task_session	0x000000a8
+#define AOFF_task_session	0x000000b0
 #define ASIZ_task_session	0x00000004
-#define AOFF_task_leader	0x000000ac
+#define AOFF_task_leader	0x000000b4
 #define ASIZ_task_leader	0x00000004
-#define AOFF_task_p_opptr	0x000000b0
+#define AOFF_task_p_opptr	0x000000b8
 #define ASIZ_task_p_opptr	0x00000008
-#define AOFF_task_p_pptr	0x000000b8
+#define AOFF_task_p_pptr	0x000000c0
 #define ASIZ_task_p_pptr	0x00000008
-#define AOFF_task_p_cptr	0x000000c0
+#define AOFF_task_p_cptr	0x000000c8
 #define ASIZ_task_p_cptr	0x00000008
-#define AOFF_task_p_ysptr	0x000000c8
+#define AOFF_task_p_ysptr	0x000000d0
 #define ASIZ_task_p_ysptr	0x00000008
-#define AOFF_task_p_osptr	0x000000d0
+#define AOFF_task_p_osptr	0x000000d8
 #define ASIZ_task_p_osptr	0x00000008
-#define AOFF_task_pidhash_next	0x000000d8
+#define AOFF_task_pidhash_next	0x000000e0
 #define ASIZ_task_pidhash_next	0x00000008
-#define AOFF_task_pidhash_pprev	0x000000e0
+#define AOFF_task_pidhash_pprev	0x000000e8
 #define ASIZ_task_pidhash_pprev	0x00000008
-#define AOFF_task_tarray_ptr	0x000000e8
+#define AOFF_task_tarray_ptr	0x000000f0
 #define ASIZ_task_tarray_ptr	0x00000008
-#define AOFF_task_wait_chldexit	0x000000f0
+#define AOFF_task_wait_chldexit	0x000000f8
 #define ASIZ_task_wait_chldexit	0x00000008
-#define AOFF_task_vfork_sem	0x000000f8
+#define AOFF_task_vfork_sem	0x00000100
 #define ASIZ_task_vfork_sem	0x00000008
-#define AOFF_task_policy	0x00000100
+#define AOFF_task_policy	0x00000108
 #define ASIZ_task_policy	0x00000008
-#define AOFF_task_rt_priority	0x00000108
+#define AOFF_task_rt_priority	0x00000110
 #define ASIZ_task_rt_priority	0x00000008
-#define AOFF_task_it_real_value	0x00000110
+#define AOFF_task_it_real_value	0x00000118
 #define ASIZ_task_it_real_value	0x00000008
-#define AOFF_task_it_prof_value	0x00000118
+#define AOFF_task_it_prof_value	0x00000120
 #define ASIZ_task_it_prof_value	0x00000008
-#define AOFF_task_it_virt_value	0x00000120
+#define AOFF_task_it_virt_value	0x00000128
 #define ASIZ_task_it_virt_value	0x00000008
-#define AOFF_task_it_real_incr	0x00000128
+#define AOFF_task_it_real_incr	0x00000130
 #define ASIZ_task_it_real_incr	0x00000008
-#define AOFF_task_it_prof_incr	0x00000130
+#define AOFF_task_it_prof_incr	0x00000138
 #define ASIZ_task_it_prof_incr	0x00000008
-#define AOFF_task_it_virt_incr	0x00000138
+#define AOFF_task_it_virt_incr	0x00000140
 #define ASIZ_task_it_virt_incr	0x00000008
-#define AOFF_task_real_timer	0x00000140
+#define AOFF_task_real_timer	0x00000148
 #define ASIZ_task_real_timer	0x00000028
-#define AOFF_task_times	0x00000168
+#define AOFF_task_times	0x00000170
 #define ASIZ_task_times	0x00000020
-#define AOFF_task_start_time	0x00000188
+#define AOFF_task_start_time	0x00000190
 #define ASIZ_task_start_time	0x00000008
-#define AOFF_task_per_cpu_utime	0x00000190
+#define AOFF_task_per_cpu_utime	0x00000198
 #define ASIZ_task_per_cpu_utime	0x00000100
-#define AOFF_task_min_flt	0x00000390
+#define AOFF_task_min_flt	0x00000398
 #define ASIZ_task_min_flt	0x00000008
-#define AOFF_task_maj_flt	0x00000398
+#define AOFF_task_maj_flt	0x000003a0
 #define ASIZ_task_maj_flt	0x00000008
-#define AOFF_task_nswap	0x000003a0
+#define AOFF_task_nswap	0x000003a8
 #define ASIZ_task_nswap	0x00000008
-#define AOFF_task_cmin_flt	0x000003a8
+#define AOFF_task_cmin_flt	0x000003b0
 #define ASIZ_task_cmin_flt	0x00000008
-#define AOFF_task_cmaj_flt	0x000003b0
+#define AOFF_task_cmaj_flt	0x000003b8
 #define ASIZ_task_cmaj_flt	0x00000008
-#define AOFF_task_cnswap	0x000003b8
+#define AOFF_task_cnswap	0x000003c0
 #define ASIZ_task_cnswap	0x00000008
-#define AOFF_task_uid	0x000003c4
+#define AOFF_task_uid	0x000003cc
 #define ASIZ_task_uid	0x00000004
-#define AOFF_task_euid	0x000003c8
+#define AOFF_task_euid	0x000003d0
 #define ASIZ_task_euid	0x00000004
-#define AOFF_task_suid	0x000003cc
+#define AOFF_task_suid	0x000003d4
 #define ASIZ_task_suid	0x00000004
-#define AOFF_task_fsuid	0x000003d0
+#define AOFF_task_fsuid	0x000003d8
 #define ASIZ_task_fsuid	0x00000004
-#define AOFF_task_gid	0x000003d4
+#define AOFF_task_gid	0x000003dc
 #define ASIZ_task_gid	0x00000004
-#define AOFF_task_egid	0x000003d8
+#define AOFF_task_egid	0x000003e0
 #define ASIZ_task_egid	0x00000004
-#define AOFF_task_sgid	0x000003dc
+#define AOFF_task_sgid	0x000003e4
 #define ASIZ_task_sgid	0x00000004
-#define AOFF_task_fsgid	0x000003e0
+#define AOFF_task_fsgid	0x000003e8
 #define ASIZ_task_fsgid	0x00000004
-#define AOFF_task_ngroups	0x000003e4
+#define AOFF_task_ngroups	0x000003ec
 #define ASIZ_task_ngroups	0x00000004
-#define AOFF_task_groups	0x000003e8
+#define AOFF_task_groups	0x000003f0
 #define ASIZ_task_groups	0x00000080
-#define AOFF_task_cap_effective	0x00000468
+#define AOFF_task_cap_effective	0x00000470
 #define ASIZ_task_cap_effective	0x00000004
-#define AOFF_task_cap_inheritable	0x0000046c
+#define AOFF_task_cap_inheritable	0x00000474
 #define ASIZ_task_cap_inheritable	0x00000004
-#define AOFF_task_cap_permitted	0x00000470
+#define AOFF_task_cap_permitted	0x00000478
 #define ASIZ_task_cap_permitted	0x00000004
-#define AOFF_task_user	0x00000478
+#define AOFF_task_user	0x00000480
 #define ASIZ_task_user	0x00000008
-#define AOFF_task_rlim	0x00000480
+#define AOFF_task_rlim	0x00000488
 #define ASIZ_task_rlim	0x000000a0
-#define AOFF_task_used_math	0x00000520
+#define AOFF_task_used_math	0x00000528
 #define ASIZ_task_used_math	0x00000002
-#define AOFF_task_comm	0x00000522
+#define AOFF_task_comm	0x0000052a
 #define ASIZ_task_comm	0x00000010
-#define AOFF_task_link_count	0x00000534
+#define AOFF_task_link_count	0x0000053c
 #define ASIZ_task_link_count	0x00000004
-#define AOFF_task_tty	0x00000538
+#define AOFF_task_tty	0x00000540
 #define ASIZ_task_tty	0x00000008
-#define AOFF_task_semundo	0x00000540
+#define AOFF_task_semundo	0x00000548
 #define ASIZ_task_semundo	0x00000008
-#define AOFF_task_semsleeping	0x00000548
+#define AOFF_task_semsleeping	0x00000550
 #define ASIZ_task_semsleeping	0x00000008
-#define AOFF_task_tss	0x00000550
+#define AOFF_task_tss	0x00000560
 #define ASIZ_task_tss	0x00000470
-#define AOFF_task_fs	0x000009c0
+#define AOFF_task_fs	0x000009d0
 #define ASIZ_task_fs	0x00000008
-#define AOFF_task_files	0x000009c8
+#define AOFF_task_files	0x000009d8
 #define ASIZ_task_files	0x00000008
-#define AOFF_task_mm	0x000009d0
+#define AOFF_task_mm	0x000009e0
 #define ASIZ_task_mm	0x00000008
-#define AOFF_task_sigmask_lock	0x000009d8
+#define AOFF_task_local_pages	0x000009e8
+#define ASIZ_task_local_pages	0x00000010
+#define AOFF_task_allocation_order	0x000009f8
+#define ASIZ_task_allocation_order	0x00000004
+#define AOFF_task_nr_local_pages	0x000009fc
+#define ASIZ_task_nr_local_pages	0x00000004
+#define AOFF_task_fs_locks	0x00000a00
+#define ASIZ_task_fs_locks	0x00000004
+#define AOFF_task_sigmask_lock	0x00000a04
 #define ASIZ_task_sigmask_lock	0x0000000c
-#define AOFF_task_sig	0x000009e8
+#define AOFF_task_sig	0x00000a10
 #define ASIZ_task_sig	0x00000008
-#define AOFF_task_signal	0x000009f0
+#define AOFF_task_signal	0x00000a18
 #define ASIZ_task_signal	0x00000008
-#define AOFF_task_blocked	0x000009f8
+#define AOFF_task_blocked	0x00000a20
 #define ASIZ_task_blocked	0x00000008
-#define AOFF_task_sigqueue	0x00000a00
+#define AOFF_task_sigqueue	0x00000a28
 #define ASIZ_task_sigqueue	0x00000008
-#define AOFF_task_sigqueue_tail	0x00000a08
+#define AOFF_task_sigqueue_tail	0x00000a30
 #define ASIZ_task_sigqueue_tail	0x00000008
-#define AOFF_task_sas_ss_sp	0x00000a10
+#define AOFF_task_sas_ss_sp	0x00000a38
 #define ASIZ_task_sas_ss_sp	0x00000008
-#define AOFF_task_sas_ss_size	0x00000a18
+#define AOFF_task_sas_ss_size	0x00000a40
 #define ASIZ_task_sas_ss_size	0x00000008
-#define AOFF_task_parent_exec_id	0x00000a20
+#define AOFF_task_parent_exec_id	0x00000a48
 #define ASIZ_task_parent_exec_id	0x00000004
-#define AOFF_task_self_exec_id	0x00000a24
+#define AOFF_task_self_exec_id	0x00000a4c
 #define ASIZ_task_self_exec_id	0x00000004
-#define AOFF_task_oom_kill_try	0x00000a28
+#define AOFF_task_oom_kill_try	0x00000a50
 #define ASIZ_task_oom_kill_try	0x00000004
-#define ASIZ_task	0x00000a30
+#define ASIZ_task	0x00000a60
 #define AOFF_mm_mmap	0x00000000
 #define ASIZ_mm_mmap	0x00000008
 #define AOFF_mm_mmap_avl	0x00000008
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc64/page.h linux.19p18/include/asm-sparc64/page.h
--- linux.vanilla/include/asm-sparc64/page.h	Fri Apr 21 12:46:50 2000
+++ linux.19p18/include/asm-sparc64/page.h	Tue Feb 20 13:28:55 2001
@@ -1,4 +1,4 @@
-/* $Id: page.h,v 1.24 1998/10/20 03:09:16 jj Exp $ */
+/* $Id: page.h,v 1.24.2.1 2001/02/20 04:21:45 davem Exp $ */
 
 #ifndef _SPARC64_PAGE_H
 #define _SPARC64_PAGE_H
@@ -17,6 +17,8 @@
 #ifdef __KERNEL__
 
 #ifndef __ASSEMBLY__
+
+#define BUG()		__builtin_trap()
 
 extern void clear_page(unsigned long page);
 extern void copy_page(unsigned long to, unsigned long from);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc64/pgtable.h linux.19p18/include/asm-sparc64/pgtable.h
--- linux.vanilla/include/asm-sparc64/pgtable.h	Fri Apr 21 12:46:51 2000
+++ linux.19p18/include/asm-sparc64/pgtable.h	Tue Jan  9 11:57:27 2001
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.103.2.3 2000/02/27 04:44:47 davem Exp $
+/* $Id: pgtable.h,v 1.103.2.4 2000/12/11 12:31:06 anton Exp $
  * pgtable.h: SpitFire page table operations.
  *
  * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -171,9 +171,15 @@
 #define flush_cache_range(mm, start, end)	flushw_user()
 #define flush_cache_page(vma, page)		flushw_user()
 
-/* These operations are unnecessary on the SpitFire since D-CACHE is write-through. */
-#define flush_icache_range(start, end)		do { } while (0)
+/* This is unnecessary on the SpitFire since D-CACHE is write-through. */
 #define flush_page_to_ram(page)			do { } while (0)
+
+/* 
+ * icache doesnt snoop local stores and we don't use block commit stores
+ * (which invalidate icache lines) during module load, so we need this.
+ */
+extern void flush_icache_range(unsigned long start, unsigned long end);
+
 extern void flush_dcache_page(unsigned long page);
 
 extern void __flush_dcache_range(unsigned long start, unsigned long end);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc64/siginfo.h linux.19p18/include/asm-sparc64/siginfo.h
--- linux.vanilla/include/asm-sparc64/siginfo.h	Fri Apr 21 12:46:51 2000
+++ linux.19p18/include/asm-sparc64/siginfo.h	Tue Feb 27 21:59:16 2001
@@ -152,8 +152,8 @@
 #define SI_ASYNCIO	-4	/* sent by AIO completion */
 #define SI_SIGIO	-5	/* sent by queued SIGIO */
 
-#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0)
-#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0)
+#define SI_FROMUSER(siptr)	((siptr)->si_code <= 0 && (siptr)->si_code != SI_SIGIO)
+#define SI_FROMKERNEL(siptr)	((siptr)->si_code > 0 || (siptr)->si_code == SI_SIGIO)
 
 /*
  * SIGILL si_codes
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc64/uaccess.h linux.19p18/include/asm-sparc64/uaccess.h
--- linux.vanilla/include/asm-sparc64/uaccess.h	Fri Apr 21 12:46:52 2000
+++ linux.19p18/include/asm-sparc64/uaccess.h	Tue Feb 27 16:30:14 2001
@@ -357,10 +357,7 @@
 #define strncpy_from_user(dest,src,count) \
 	__strncpy_from_user((unsigned long)(dest), (unsigned long)(src), (int)(count))
 
-extern int __strlen_user(const char *);
 extern int __strnlen_user(const char *, long len);
-
-#define strlen_user __strlen_user
 #define strnlen_user __strnlen_user
 
 #endif  /* __ASSEMBLY__ */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc64/unistd.h linux.19p18/include/asm-sparc64/unistd.h
--- linux.vanilla/include/asm-sparc64/unistd.h	Fri Apr 21 12:46:52 2000
+++ linux.19p18/include/asm-sparc64/unistd.h	Wed Feb  7 09:45:39 2001
@@ -1,4 +1,4 @@
-/* $Id: unistd.h,v 1.28 1999/04/07 17:14:19 davem Exp $ */
+/* $Id: unistd.h,v 1.28.2.2 2001/01/11 19:12:11 davem Exp $ */
 #ifndef _SPARC64_UNISTD_H
 #define _SPARC64_UNISTD_H
 
@@ -59,7 +59,7 @@
 #define __NR_dup                 41 /* Common                                      */
 #define __NR_pipe                42 /* Common                                      */
 #define __NR_times               43 /* Implemented via getrusage() in SunOS        */
-/* #define __NR_profil           44    Common                                      */
+/* #define __NR_getuid32         44    Linux Sparc32 Specific                      */
 #define __NR_umount2             45 /* Linux Specific                              */
 #define __NR_setgid              46 /* Implemented via setregid() in SunOS         */
 #define __NR_getgid              47 /* Common                                      */
@@ -169,8 +169,8 @@
 /* #define __NR_getmsg          151    SunOS Specific                              */
 /* #define __NR_putmsg          152    SunOS Specific                              */
 #define __NR_poll               153 /* Common                                      */
-/* #define __NR_ni_syscall      154    ENOSYS under SunOS                          */
-/* #define __NR_nfssvc          155    SunOS Specific                              */
+/* #define __NR_getdents64      154    Linux Sparc32 Specific                      */
+/* #define __NR_fcntl64         155    Linux Sparc32 Specific                      */
 /* #define __NR_getdirentries   156    SunOS Specific                              */
 #define __NR_statfs             157 /* Common                                      */
 #define __NR_fstatfs            158 /* Common                                      */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/asm-sparc64/watchdog.h linux.19p18/include/asm-sparc64/watchdog.h
--- linux.vanilla/include/asm-sparc64/watchdog.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/include/asm-sparc64/watchdog.h	Wed Feb  7 09:45:39 2001
@@ -0,0 +1,31 @@
+/* $Id: watchdog.h,v 1.1.2.1 2001/01/26 22:26:07 davem Exp $
+ *
+ * watchdog - Driver interface for the hardware watchdog timers
+ * present on Sun Microsystems boardsets
+ *
+ * Copyright (c) 2000 Eric Brower <ebrower@usa.net>
+ *
+ */
+
+#ifndef _SPARC64_WATCHDOG_H
+#define _SPARC64_WATCHDOG_H
+
+#include <linux/watchdog.h>
+
+/* Solaris compatibility ioctls--
+ * Ref. <linux/watchdog.h> for standard linux watchdog ioctls
+ */
+#define WIOCSTART _IO (WATCHDOG_IOCTL_BASE, 10)		/* Start Timer		*/
+#define WIOCSTOP  _IO (WATCHDOG_IOCTL_BASE, 11)		/* Stop Timer		*/
+#define WIOCGSTAT _IOR(WATCHDOG_IOCTL_BASE, 12, int)/* Get Timer Status	*/
+
+/* Status flags from WIOCGSTAT ioctl
+ */
+#define WD_FREERUN	0x01	/* timer is running, interrupts disabled	*/
+#define WD_EXPIRED	0x02	/* timer has expired						*/
+#define WD_RUNNING	0x04	/* timer is running, interrupts enabled		*/
+#define WD_STOPPED	0x08	/* timer has not been started				*/
+#define WD_SERVICED 0x10	/* timer interrupt was serviced				*/
+
+#endif /* ifndef _SPARC64_WATCHDOG_H */
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/agp_backend.h linux.19p18/include/linux/agp_backend.h
--- linux.vanilla/include/linux/agp_backend.h	Mon Dec 11 22:13:07 2000
+++ linux.19p18/include/linux/agp_backend.h	Wed Dec 13 21:32:45 2000
@@ -45,6 +45,7 @@
 	INTEL_BX,
 	INTEL_GX,
 	INTEL_I810,
+	INTEL_I815,
 	INTEL_I840,
 	VIA_GENERIC,
 	VIA_VP3,
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/apm_bios.h linux.19p18/include/linux/apm_bios.h
--- linux.vanilla/include/linux/apm_bios.h	Mon Dec 11 22:13:07 2000
+++ linux.19p18/include/linux/apm_bios.h	Wed Feb  7 09:42:47 2001
@@ -38,7 +38,7 @@
 	unsigned short	dseg_len;
 };
 
-				/* Results of APM Installation Check */
+/* Results of APM Installation Check */
 #define APM_16_BIT_SUPPORT	0x0001
 #define APM_32_BIT_SUPPORT	0x0002
 #define APM_IDLE_SLOWS_CLOCK	0x0004
@@ -46,6 +46,15 @@
 #define APM_BIOS_DISENGAGED     0x0010
 
 /*
+ * Data for APM that is persistant across module unload/load
+ */
+struct apm_info {
+	struct apm_bios_info	bios;
+	unsigned short		connection_version;
+	int			get_power_status_broken;
+};
+
+/*
  * The APM function codes
  */
 #define	APM_FUNC_INST_CHECK	0x5300
@@ -91,9 +100,9 @@
 #define	APM_FUNC_TIMER_GET	2
 
 /*
- * in init/main.c
+ * in arch/i386/kernel/setup.c
  */
-extern struct apm_bios_info	apm_bios_info;
+extern struct apm_info	apm_info;
 
 extern int		apm_register_callback(int (*callback)(apm_event_t));
 extern void		apm_unregister_callback(int (*callback)(apm_event_t));
@@ -176,7 +185,7 @@
 /*
  * This is the "All Devices" ID communicated to the BIOS
  */
-#define APM_DEVICE_BALL		((apm_bios_info.version > 0x0100) ? \
+#define APM_DEVICE_BALL		((apm_info.connection_version > 0x0100) ? \
 				 APM_DEVICE_ALL : APM_DEVICE_OLD_ALL)
 #endif
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/binfmts.h linux.19p18/include/linux/binfmts.h
--- linux.vanilla/include/linux/binfmts.h	Fri Apr 21 23:10:16 2000
+++ linux.19p18/include/linux/binfmts.h	Sat Mar  3 22:33:06 2001
@@ -28,6 +28,8 @@
 	int argc, envc;
 	char * filename;	/* Name of binary */
 	unsigned long loader, exec;
+	int dumpable;
+	int priv_change;
 };
 
 /*
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/blk.h linux.19p18/include/linux/blk.h
--- linux.vanilla/include/linux/blk.h	Sun Jun 11 21:44:23 2000
+++ linux.19p18/include/linux/blk.h	Sat Mar  3 22:39:07 2001
@@ -193,6 +193,14 @@
 #define DEVICE_ON(device)
 #define DEVICE_OFF(device)
 
+#elif (MAJOR_NR == OSST_MAJOR)
+
+#define DEVICE_NAME "onstream" 
+#define DEVICE_INTR do_osst
+#define DEVICE_NR(device) (MINOR(device) & 0x7f) 
+#define DEVICE_ON(device) 
+#define DEVICE_OFF(device) 
+
 #elif (MAJOR_NR == SCSI_CDROM_MAJOR)
 
 #define DEVICE_NAME "CD-ROM"
@@ -389,7 +397,7 @@
 #define LOCAL_END_REQUEST
 #define DEVICE_NAME "dasd"
 #define DEVICE_REQUEST do_dasd_request
-#define DEVICE_NR(device) (MINOR(device) >> PARTN_BITS)
+#define DEVICE_NR(device) (MINOR(device) >> DASD_PARTN_BITS)
 #define DEVICE_ON(device) 
 #define DEVICE_OFF(device)
 
@@ -412,7 +420,7 @@
 
 #endif /* MAJOR_NR == whatever */
 
-#if (MAJOR_NR != SCSI_TAPE_MAJOR)
+#if (MAJOR_NR != SCSI_TAPE_MAJOR) && (MAJOR_NR != OSST_MAJOR)
 #if !defined(IDE_DRIVER)
 
 #ifndef CURRENT
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/capi.h linux.19p18/include/linux/capi.h
--- linux.vanilla/include/linux/capi.h	Mon Dec 11 22:13:07 2000
+++ linux.19p18/include/linux/capi.h	Wed Feb 14 14:49:17 2001
@@ -114,4 +114,18 @@
 	__u16 errcode;
 } capi_ioctl_struct;
 
+/*
+ * Middleware extension
+ */
+
+#define CAPIFLAG_HIGHJACKING	0x0001
+
+#define CAPI_GET_FLAGS		_IOR('C',0x23, unsigned)
+#define CAPI_SET_FLAGS		_IOR('C',0x24, unsigned)
+#define CAPI_CLR_FLAGS		_IOR('C',0x25, unsigned)
+
+#define CAPI_NCCI_OPENCOUNT	_IOR('C',0x26, unsigned)
+
+#define CAPI_NCCI_GETUNIT	_IOR('C',0x27, unsigned)
+
 #endif				/* __LINUX_CAPI_H__ */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/cdrom.h linux.19p18/include/linux/cdrom.h
--- linux.vanilla/include/linux/cdrom.h	Sat Sep  9 18:42:50 2000
+++ linux.19p18/include/linux/cdrom.h	Sat Mar 10 23:10:20 2001
@@ -528,10 +528,12 @@
 	__u32 end_sector_l0;
 };
 
+#define DVD_LAYERS	4
+
 struct dvd_physical {
 	__u8 type;
 	__u8 layer_num;
-	struct dvd_layer layer[4];
+	struct dvd_layer layer[DVD_LAYERS];
 };
 
 struct dvd_copyright {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/dcache.h linux.19p18/include/linux/dcache.h
--- linux.vanilla/include/linux/dcache.h	Mon Dec 11 22:13:07 2000
+++ linux.19p18/include/linux/dcache.h	Wed Jan  3 13:50:15 2001
@@ -106,6 +106,10 @@
 					 * If this dentry points to a directory, then
 					 * s_nfsd_free_path semaphore will be down
 					 */
+#define	DCACHE_REFERENCED 0x0008	/* This dentry is been recently
+					 * referenced so try to keep it in
+					 * cache.
+					 */
 
 /*
  * d_drop() unhashes the entry from the parent
@@ -149,7 +153,7 @@
 /* dcache memory management */
 extern void shrink_dcache_memory(int, unsigned int);
 extern void check_dcache_memory(void);
-extern void free_inode_memory(int);	/* defined in fs/inode.c */
+extern void free_inode_memory(void);	/* defined in fs/inode.c */
 
 /* only used at mount-time */
 extern struct dentry * d_alloc_root(struct inode * root_inode, struct dentry * old_root);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/elf.h linux.19p18/include/linux/elf.h
--- linux.vanilla/include/linux/elf.h	Fri Apr 21 23:11:49 2000
+++ linux.19p18/include/linux/elf.h	Mon Feb 19 18:34:53 2001
@@ -68,6 +68,8 @@
 
 #define EM_SPARCV9     43	/* SPARC v9 64-bit */
 
+#define EM_S390        22	/* IBM S/390 */
+
 /*
  * This is an interim value that we will use until the committee comes
  * up with a final number.
@@ -75,9 +77,9 @@
 #define EM_ALPHA	0x9026
 
 /*
- * This is an interim value for S390 architecture
+ * This is the old interim value for S/390 architecture
  */
-#define EM_S390         0xA390
+#define EM_S390_OLD     0xA390
 
 /* This is the info that is needed to parse the dynamic section of the file */
 #define DT_NULL		0
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/fs.h linux.19p18/include/linux/fs.h
--- linux.vanilla/include/linux/fs.h	Mon Dec 11 22:13:07 2000
+++ linux.19p18/include/linux/fs.h	Sun Feb 25 23:23:30 2001
@@ -47,7 +47,12 @@
 
 /* And dynamically-tunable limits and defaults: */
 extern int max_inodes;
-extern int max_files, nr_files, nr_free_files;
+struct files_stat_struct {
+	int nr_files;		/* read only */
+	int nr_free_files;	/* read only */
+	int max_files;		/* tunable */
+};
+extern struct files_stat_struct files_stat; /* fs/file_table.c */
 extern int max_super_blocks, nr_super_blocks;
 
 #define NR_FILE  4096	/* this can well be larger on a larger system */
@@ -185,6 +190,7 @@
 #define BH_Lock		2	/* 1 if the buffer is locked */
 #define BH_Req		3	/* 0 if the buffer has been invalidated */
 #define BH_Protected	6	/* 1 if the buffer is protected */
+#define BH_Wait_IO	7	/* 1 if we should throttle on this buffer */
 
 /*
  * Try to keep the most commonly used fields in single cache lines (16
@@ -777,7 +783,7 @@
 
 extern void refile_buffer(struct buffer_head * buf);
 extern void set_writetime(struct buffer_head * buf, int flag);
-extern int try_to_free_buffers(struct page *, int wait);
+extern int try_to_free_buffers(struct page *, int);
 
 extern int nr_buffers;
 extern long buffermem;
@@ -786,15 +792,25 @@
 #define BUF_CLEAN	0
 #define BUF_LOCKED	1	/* Buffers scheduled for write */
 #define BUF_DIRTY	2	/* Dirty buffers, not yet scheduled for write */
-#define NR_LIST		3
+#define BUF_PROTECTED	3	/* Ramdisk persistent storage */
+#define NR_LIST		4
 
 void mark_buffer_uptodate(struct buffer_head * bh, int on);
 
+extern inline void mark_buffer_protected(struct buffer_head * bh)
+{
+	if (!test_and_set_bit(BH_Protected, &bh->b_state)) {
+		if (bh->b_list != BUF_PROTECTED)
+			refile_buffer(bh);
+	}
+}
+
 extern inline void mark_buffer_clean(struct buffer_head * bh)
 {
 	if (test_and_clear_bit(BH_Dirty, &bh->b_state)) {
 		if (bh->b_list == BUF_DIRTY)
 			refile_buffer(bh);
+		clear_bit(BH_Wait_IO, &bh->b_state);
 	}
 }
 
@@ -935,6 +951,9 @@
 extern void inode_setattr(struct inode *, struct iattr *);
 
 extern __u32 inode_generation_count;
+
+#define fs_down(sem)	do { current->fs_locks++; down(sem); } while (0)
+#define fs_up(sem)	do { up(sem); current->fs_locks--; } while (0)
 
 #endif /* __KERNEL__ */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/hysdn_if.h linux.19p18/include/linux/hysdn_if.h
--- linux.vanilla/include/linux/hysdn_if.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/include/linux/hysdn_if.h	Tue Feb 13 18:49:43 2001
@@ -0,0 +1,49 @@
+/* $Id: hysdn_if.h,v 1.1 2000/02/10 19:47:50 werner Exp $
+
+ * Linux driver for HYSDN cards, ioctl definitions shared by hynetmgr and driver.
+ * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH
+ *
+ * Copyright 1999  by Werner Cornelius (werner@titro.de)
+ *
+ * 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, 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.
+ *
+ * $Log: hysdn_if.h,v $
+ * Revision 1.1  2000/02/10 19:47:50  werner
+ *
+ * Initial release
+ *
+ *
+ */
+
+/****************/
+/* error values */
+/****************/
+#define ERR_NONE             0 /* no error occured */
+#define ERR_ALREADY_BOOT  1000 /* we are already booting */
+#define EPOF_BAD_MAGIC    1001 /* bad magic in POF header */
+#define ERR_BOARD_DPRAM   1002 /* board DPRAM failed */
+#define EPOF_INTERNAL     1003 /* internal POF handler error */
+#define EPOF_BAD_IMG_SIZE 1004 /* POF boot image size invalid */
+#define ERR_BOOTIMG_FAIL  1005 /* 1. stage boot image did not start */
+#define ERR_BOOTSEQ_FAIL  1006 /* 2. stage boot seq handshake timeout */
+#define ERR_POF_TIMEOUT   1007 /* timeout waiting for card pof ready */
+#define ERR_NOT_BOOTED    1008 /* operation only allowed when booted */
+#define ERR_CONF_LONG     1009 /* conf line is to long */ 
+#define ERR_INV_CHAN      1010 /* invalid channel number */ 
+#define ERR_ASYNC_TIME    1011 /* timeout sending async data */ 
+
+
+
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/interrupt.h linux.19p18/include/linux/interrupt.h
--- linux.vanilla/include/linux/interrupt.h	Fri Apr 21 23:10:16 2000
+++ linux.19p18/include/linux/interrupt.h	Thu Dec 21 22:50:30 2000
@@ -5,6 +5,7 @@
 #include <linux/kernel.h>
 #include <asm/bitops.h>
 #include <asm/atomic.h>
+#include <asm/ptrace.h>
 
 struct irqaction {
 	void (*handler)(int, void *, struct pt_regs *);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/isdn.h linux.19p18/include/linux/isdn.h
--- linux.vanilla/include/linux/isdn.h	Mon Dec 11 22:13:07 2000
+++ linux.19p18/include/linux/isdn.h	Sat Mar  3 22:59:11 2001
@@ -1,4 +1,4 @@
-/* $Id: isdn.h,v 1.107 2000/09/10 20:29:18 detabc Exp $
+/* $Id: isdn.h,v 1.111.6.3 2001/02/10 14:44:10 kai Exp $
 
  * Main header for the Linux ISDN subsystem (linklevel).
  *
@@ -66,9 +66,7 @@
 #undef CONFIG_ISDN_WITH_ABC_CH_EXTINUSE
 #undef CONFIG_ISDN_WITH_ABC_CONN_ERROR
 #undef CONFIG_ISDN_WITH_ABC_RAWIPCOMPRESS
-#undef CONFIG_ISDN_WITH_ABC_FRAME_LIMIT
-#undef CONFIG_ISDN_WITH_ABC_IPV4_RW_SOCKADDR 
-#undef CONFIG_ISDN_WITH_ABC_IPV4_RWUDP_SOCKADDR 
+#undef CONFIG_ISDN_WITH_ABC_IPTABLES_NETFILTER
 
 
 /* New ioctl-codes */
@@ -198,7 +196,7 @@
 #include <asm/io.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/timer.h>
 #include <linux/wait.h>
 #include <linux/tty.h>
@@ -320,7 +318,7 @@
 typedef struct isdn_net_local_s {
   ulong                  magic;
   char                   name[10];     /* Name of device                   */
-  struct enet_statistics stats;        /* Ethernet Statistics              */
+  struct net_device_stats stats;       /* Ethernet Statistics              */
   int                    isdn_device;  /* Index to isdn-device             */
   int                    isdn_channel; /* Index to isdn-channel            */
   int			 ppp_slot;     /* PPPD device slot number          */
@@ -368,7 +366,6 @@
   ulong                  sqfull_stamp; /* Start-Time of overload           */
   ulong                  slavedelay;   /* Dynamic bundling delaytime       */
   int                    triggercps;   /* BogoCPS needed for trigger slave */
-  struct device      *srobin;      /* Ptr to Master device for slaves  */
   isdn_net_phone         *phone[2];    /* List of remote-phonenumbers      */
 				       /* phone[0] = Incoming Numbers      */
 				       /* phone[1] = Outgoing Numbers      */
@@ -378,9 +375,15 @@
   struct isdn_net_local_s *next;       /* Ptr to next link in bundle       */
   struct isdn_net_local_s *last;       /* Ptr to last link in bundle       */
   struct isdn_net_dev_s  *netdev;      /* Ptr to netdev                    */
-  struct sk_buff         *first_skb;   /* Ptr to skb that triggers dialing */
-  struct sk_buff *volatile sav_skb;    /* Ptr to skb, rejected by LL-driver*/
+  struct sk_buff_head    super_tx_queue; /* List of supervisory frames to  */
+	                               /* be transmitted asap              */
+  atomic_t frame_cnt;                  /* number of frames currently       */
+                        	       /* queued in HL driver              */    
                                        /* Ptr to orig. hard_header_cache   */
+  spinlock_t             xmit_lock;    /* used to protect the xmit path of */
+                                       /* a particular channel (including  */
+                                       /* the frame_cnt                    */
+
   int                    (*org_hhc)(
 				    struct neighbour *neigh,
 				    struct hh_cache *hh);
@@ -400,13 +403,17 @@
   int  cisco_loop;                     /* Loop counter for Cisco-SLARP     */
   ulong cisco_myseq;                   /* Local keepalive seq. for Cisco   */
   ulong cisco_yourseq;                 /* Remote keepalive seq. for Cisco  */
+  struct tq_struct tqueue;
 } isdn_net_local;
 
 /* the interface itself */
 typedef struct isdn_net_dev_s {
   isdn_net_local *local;
-  isdn_net_local *queue;
-  void           *next;                /* Pointer to next isdn-interface   */
+  isdn_net_local *queue;               /* circular list of all bundled
+					  channels, which are currently
+					  online                           */
+  spinlock_t queue_lock;               /* lock to protect queue            */
+  void *next;                          /* Pointer to next isdn-interface   */
   struct device dev;               /* interface to upper levels        */
 #ifdef CONFIG_ISDN_PPP
   ippp_bundle * pb;		/* pointer to the common bundle structure
@@ -531,8 +538,7 @@
   atemu                 emu;             /* AT-emulator data               */
   struct termios	normal_termios;  /* For saving termios structs     */
   struct termios	callout_termios;
-  struct wait_queue	*open_wait;
-  struct wait_queue	*close_wait;
+  wait_queue_head_t	open_wait, close_wait;
   struct semaphore      write_sem;
 } modem_info;
 
@@ -583,23 +589,6 @@
 	char *private;
 } infostruct;
 
-typedef struct isdn_module {
-	struct isdn_module *prev;
-	struct isdn_module *next;
-	char *name;
-	int (*get_free_channel)(int, int, int, int, int);
-	int (*free_channel)(int, int, int);
-	int (*status_callback)(isdn_ctrl *);
-	int (*command)(isdn_ctrl *);
-	int (*receive_callback)(int, int, struct sk_buff *);
-	int (*writebuf_skb)(int, int, int, struct sk_buff *);
-	int (*net_start_xmit)(struct sk_buff *, struct device *);
-	int (*net_receive)(struct device *, struct sk_buff *);
-	int (*net_open)(struct device *);
-	int (*net_close)(struct device *);
-	int priority;
-} isdn_module;
-
 #define DRV_FLAG_RUNNING 1
 #define DRV_FLAG_REJBUS  2
 #define DRV_FLAG_LOADED  4
@@ -610,7 +599,7 @@
 	ulong               flags;            /* Misc driver Flags                */
 	int                 locks;            /* Number of locks for this driver  */
 	int                 channels;         /* Number of channels               */
-	struct wait_queue  *st_waitq;         /* Wait-Queue for status-read's     */
+	wait_queue_head_t   st_waitq;         /* Wait-Queue for status-read's     */
 	int                 maxbufsize;       /* Maximum Buffersize supported     */
 	unsigned long       pktcount;         /* Until now: unused                */
 	int                 stavail;          /* Chars avail on Status-device     */
@@ -621,8 +610,8 @@
 	unsigned long      DLEflag;           /* Flags: Insert DLE at next read   */
 #endif
 	struct sk_buff_head *rpqueue;         /* Pointers to start of Rcv-Queue   */
-	struct wait_queue  **rcv_waitq;       /* Wait-Queues for B-Channel-Reads  */
-	struct wait_queue  **snd_waitq;       /* Wait-Queue for B-Channel-Send's  */
+	wait_queue_head_t  *rcv_waitq;       /* Wait-Queues for B-Channel-Reads  */
+	wait_queue_head_t  *snd_waitq;       /* Wait-Queue for B-Channel-Send's  */
 	char               msn2eaz[10][ISDN_MSNLEN];  /* Mapping-Table MSN->EAZ   */
 } driver;
 
@@ -638,7 +627,7 @@
 	/*  see ISDN_TIMER_..defines  */
 	int               global_flags;
 	infostruct        *infochain;                /* List of open info-devs.    */
-	struct wait_queue *info_waitq;               /* Wait-Queue for isdninfo    */
+	wait_queue_head_t info_waitq;               /* Wait-Queue for isdninfo    */
 	struct timer_list timer;		       /* Misc.-function Timer       */
 	int               chanmap[ISDN_MAX_CHANNELS];/* Map minor->device-channel  */
 	int               drvmap[ISDN_MAX_CHANNELS]; /* Map minor->driver-index    */
@@ -659,43 +648,14 @@
 	atomic_t          v110use[ISDN_MAX_CHANNELS];/* Usage-Semaphore for stream */
 	isdn_v110_stream  *v110[ISDN_MAX_CHANNELS];  /* V.110 private data         */
 	struct semaphore  sem;                       /* serialize list access*/
-	isdn_module       *modules;
 	unsigned long     global_features;
 } isdn_dev;
 
 extern isdn_dev *dev;
 
 
-
 /* Utility-Macros */
 #define MIN(a,b) ((a<b)?a:b)
 #define MAX(a,b) ((a>b)?a:b)
-/*
- * Tell upper layers that the network device is ready to xmit more frames.
- */
-static void __inline__ netif_wake_queue(struct device * dev)
-{
-	dev->tbusy = 0;
-	mark_bh(NET_BH);
-}
-
-/*
- * called during net_device open()
- */
-static void __inline__ netif_start_queue(struct device * dev)
-{
-	dev->tbusy = 0;
-	/* actually, we never use the interrupt flag at all */
-	dev->interrupt = 0;
-	dev->start = 1;
-}
-
-/*
- * Ask upper layers to temporarily cease passing us more xmit frames.
- */
-static void __inline__ netif_stop_queue(struct device * dev)
-{
-	dev->tbusy = 1;
-}
 #endif /* __KERNEL__ */
 #endif /* isdn_h */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/isdn_compat.h linux.19p18/include/linux/isdn_compat.h
--- linux.vanilla/include/linux/isdn_compat.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/include/linux/isdn_compat.h	Sat Mar  3 22:59:11 2001
@@ -0,0 +1,81 @@
+/* Compatibility for various Linux kernel versions */
+
+#ifndef _LINUX_ISDN_COMPAT_H
+#define _LINUX_ISDN_COMPAT_H
+
+#ifdef __KERNEL__
+
+
+#include <linux/pci.h>
+#ifdef __powerpc__
+static inline int pci_enable_device(struct pci_dev *dev)
+{
+	u16 cmd;
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_IO | PCI_COMMAND_SERR;
+	cmd &= ~PCI_COMMAND_FAST_BACK;
+	pci_write_config_word(dev, PCI_COMMAND, cmd);
+	return(0);
+}
+#else
+static inline int pci_enable_device(struct pci_dev *dev)
+{
+	return 0;
+}
+#endif /* __powerpc__ */
+
+#define PCI_ANY_ID (~0)
+
+/* as this is included multiple times, we make it inline */
+
+static inline struct pci_dev * pci_find_subsys(unsigned int vendor, unsigned int device,
+					unsigned int ss_vendor, unsigned int ss_device,
+					struct pci_dev *from)
+{
+	unsigned short subsystem_vendor, subsystem_device;
+
+	while ((from = pci_find_device(vendor, device, from))) {
+		pci_read_config_word(from, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor);
+		pci_read_config_word(from, PCI_SUBSYSTEM_ID, &subsystem_device);
+		if ((ss_vendor == PCI_ANY_ID || subsystem_vendor == ss_vendor) &&
+		    (ss_device == PCI_ANY_ID || subsystem_device == ss_device))
+			return from;
+	}
+	return NULL;
+}
+
+#include <linux/netdevice.h>
+
+/*
+ * Tell upper layers that the network device is ready to xmit more frames.
+ */
+static void __inline__ netif_wake_queue(struct device * dev)
+{
+	dev->tbusy = 0;
+	mark_bh(NET_BH);
+}
+
+/*
+ * called during net_device open()
+ */
+static void __inline__ netif_start_queue(struct device * dev)
+{
+	dev->tbusy = 0;
+	/* actually, we never use the interrupt flag at all */
+	dev->interrupt = 0;
+	dev->start = 1;
+}
+
+/*
+ * Ask upper layers to temporarily cease passing us more xmit frames.
+ */
+static void __inline__ netif_stop_queue(struct device * dev)
+{
+	dev->tbusy = 1;
+}
+
+
+
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_ISDN_COMPAT_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/isdn_ppp.h linux.19p18/include/linux/isdn_ppp.h
--- linux.vanilla/include/linux/isdn_ppp.h	Sun Jun 11 21:44:23 2000
+++ linux.19p18/include/linux/isdn_ppp.h	Tue Feb 13 18:50:53 2001
@@ -30,8 +30,8 @@
 #define PPPIOCGIFNAME      _IOR('t',136, char [IFNAMSIZ] )
 
 #define PPP_MP          0x003d
-#define PPP_LINK_COMP   0x00fb
-#define PPP_LINK_CCP    0x80fb
+#define PPP_COMPFRAG    0x00fb
+#define PPP_CCPFRAG     0x80fb
 
 #define SC_MP_PROT       0x00000200
 #define SC_REJ_MP_PROT   0x00000400
@@ -68,8 +68,6 @@
 
 #ifdef __KERNEL__
 
-#include <asm/spinlock.h>
-
 /*
  * We need a way for the decompressor to influence the generation of CCP
  * Reset-Requests in a variety of ways. The decompressor is already returning
@@ -203,7 +201,7 @@
   struct ippp_buf_queue rq[NUM_RCV_BUFFS]; /* packet queue for isdn_ppp_read() */
   struct ippp_buf_queue *first;  /* pointer to (current) first packet */
   struct ippp_buf_queue *last;   /* pointer to (current) last used packet in queue */
-  struct wait_queue *wq;
+  wait_queue_head_t wq;
   struct task_struct *tk;
   unsigned int mpppcfg;
   unsigned int pppcfg;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/isdnif.h linux.19p18/include/linux/isdnif.h
--- linux.vanilla/include/linux/isdnif.h	Mon Dec 11 22:13:07 2000
+++ linux.19p18/include/linux/isdnif.h	Sat Mar  3 22:59:11 2001
@@ -1,4 +1,4 @@
-/* $Id: isdnif.h,v 1.35 2000/06/16 13:19:38 keil Exp $
+/* $Id: isdnif.h,v 1.37 2000/11/19 17:01:54 kai Exp $
 
  * Linux ISDN subsystem
  *
@@ -53,6 +53,7 @@
 #define ISDN_PROTO_L2_V11038 9   /* V.110 bitrate adaption 38400 Baud */
 #define ISDN_PROTO_L2_MODEM  10  /* Analog Modem on Board */
 #define ISDN_PROTO_L2_FAX    11  /* Fax Group 2/3         */
+#define ISDN_PROTO_L2_HDLC_56K 12   /* HDLC 56k                          */
 #define ISDN_PROTO_L2_MAX    15  /* Max. 16 Protocols                 */
 
 /*
@@ -135,6 +136,20 @@
 /* STAT_INVOKE_BRD callback. The ll_id is set to 0, the other fields */
 /* are supplied by the network and not by the HL.                    */   
 /*********************************************************************/
+
+/*****************/
+/* NI1 commands */ 
+/*****************/
+#define NI1_CMD_INVOKE       ((0x00 << 8) | ISDN_PTYPE_NI1)   /* invoke a supplementary service */
+#define NI1_CMD_INVOKE_ABORT ((0x01 << 8) | ISDN_PTYPE_NI1)   /* abort a invoke cmd */
+
+/*******************************/
+/* NI1 Status callback values */
+/*******************************/
+#define NI1_STAT_INVOKE_RES  ((0x80 << 8) | ISDN_PTYPE_NI1)   /* Result for invocation */
+#define NI1_STAT_INVOKE_ERR  ((0x81 << 8) | ISDN_PTYPE_NI1)   /* Error Return for invocation */
+#define NI1_STAT_INVOKE_BRD  ((0x82 << 8) | ISDN_PTYPE_NI1)   /* Deliver invoke broadcast info */
+
 typedef struct
   { ulong ll_id; /* ID supplied by LL when executing    */
 		 /* a command and returned by HL for    */
@@ -150,7 +165,7 @@
                  /* error value when error callback     */
     int datalen; /* length of cmd or stat data          */
     u_char *data;/* pointer to data delivered or send   */
-  } dss1_cmd_stat;
+  } isdn_cmd_stat;
 
 /*
  * Commands from linklevel to lowlevel
@@ -239,6 +254,7 @@
 #define ISDN_FEATURE_L2_V11038  (0x0001 << ISDN_PROTO_L2_V11038)
 #define ISDN_FEATURE_L2_MODEM   (0x0001 << ISDN_PROTO_L2_MODEM)
 #define ISDN_FEATURE_L2_FAX	(0x0001 << ISDN_PROTO_L2_FAX)
+#define ISDN_FEATURE_L2_HDLC_56K (0x0001 << ISDN_PROTO_L2_HDLC_56K)
 
 #define ISDN_FEATURE_L2_MASK    (0x0FFFF) /* Max. 16 protocols */
 #define ISDN_FEATURE_L2_SHIFT   (0)
@@ -412,13 +428,16 @@
 		setup_parm setup;/* For SETUP msg			*/
 		capi_msg cmsg;	/* For CAPI like messages		*/
 		char display[85];/* display message data		*/ 
-		dss1_cmd_stat dss1_io; /* DSS1 IO-parameter/result	*/
+		isdn_cmd_stat isdn_io; /* ISDN IO-parameter/result	*/
 		aux_s aux;	/* for modem commands/indications	*/
 #ifdef CONFIG_ISDN_TTY_FAX
 		T30_s	*fax;	/* Pointer to ttys fax struct		*/
 #endif
 	} parm;
 } isdn_ctrl;
+
+#define dss1_io    isdn_io
+#define ni1_io     isdn_io
 
 /*
  * The interface-struct itself (initialized at load-time of lowlevel-driver)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/iso_fs.h linux.19p18/include/linux/iso_fs.h
--- linux.vanilla/include/linux/iso_fs.h	Fri Apr 21 23:11:46 2000
+++ linux.19p18/include/linux/iso_fs.h	Wed Dec 13 21:58:21 2000
@@ -177,41 +177,22 @@
 
 extern int parse_rock_ridge_inode(struct iso_directory_record *, struct inode *);
 extern int get_rock_ridge_filename(struct iso_directory_record *, char *, struct inode *);
+extern int isofs_name_translate(struct iso_directory_record *, char *, struct inode *);
 
 extern char * get_rock_ridge_symlink(struct inode *);
-extern int find_rock_ridge_relocation(struct iso_directory_record *, struct inode *);
 
-int get_joliet_filename(struct iso_directory_record *, struct inode *, unsigned char *);
+extern int find_rock_ridge_relocation(struct iso_directory_record *, struct inode *);
+int get_joliet_filename(struct iso_directory_record *, unsigned char *, struct inode *);
 int get_acorn_filename(struct iso_directory_record *, char *, struct inode *);
 
-/* The stuff that follows may be totally unneeded. I have not checked to see 
- which prototypes we are still using.  */
-
-extern int isofs_open(struct inode * inode, struct file * filp);
-extern void isofs_release(struct inode * inode, struct file * filp);
 extern struct dentry *isofs_lookup(struct inode * dir, struct dentry *);
-extern unsigned long isofs_count_free_inodes(struct super_block *sb);
-extern int isofs_new_block(int dev);
-extern int isofs_free_block(int dev, int block);
 extern int isofs_bmap(struct inode *,int);
-
-extern void isofs_put_super(struct super_block *);
-extern struct super_block *isofs_read_super(struct super_block *,void *,int);
+extern struct buffer_head *isofs_bread(struct inode *, unsigned int, unsigned int);
 extern int init_iso9660_fs(void);
-extern void isofs_read_inode(struct inode *);
-extern void isofs_put_inode(struct inode *);
-extern int isofs_statfs(struct super_block *, struct statfs *, int);
-
-extern int isofs_lseek(struct inode *, struct file *, off_t, int);
-extern int isofs_read(struct inode *, struct file *, char *, int);
-extern int isofs_lookup_grandparent(struct inode *, int);
 
 extern struct inode_operations isofs_file_inode_operations;
 extern struct inode_operations isofs_dir_inode_operations;
 extern struct inode_operations isofs_symlink_inode_operations;
-extern struct inode_operations isofs_chrdev_inode_operations;
-extern struct inode_operations isofs_blkdev_inode_operations;
-extern struct inode_operations isofs_fifo_inode_operations;
 
 /* The following macros are used to check for memory leaks. */
 #ifdef LEAK_CHECK
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/kernelcapi.h linux.19p18/include/linux/kernelcapi.h
--- linux.vanilla/include/linux/kernelcapi.h	Fri Apr 21 12:46:59 2000
+++ linux.19p18/include/linux/kernelcapi.h	Wed Feb 14 14:28:52 2001
@@ -1,58 +1,17 @@
 /*
- * $Id: kernelcapi.h,v 1.5 2000/01/28 16:45:40 calle Exp $
+ * $Id: kernelcapi.h,v 1.8.6.2 2001/02/07 11:31:31 kai Exp $
  * 
  * Kernel CAPI 2.0 Interface for Linux
  * 
  * (c) Copyright 1997 by Carsten Paeth (calle@calle.in-berlin.de)
  * 
- * $Log: kernelcapi.h,v $
- * Revision 1.5  2000/01/28 16:45:40  calle
- * new manufacturer command KCAPI_CMD_ADDCARD (generic addcard),
- * will search named driver and call the add_card function if one exist.
- *
- * Revision 1.4  1999/09/10 17:24:19  calle
- * Changes for proposed standard for CAPI2.0:
- * - AK148 "Linux Exention"
- *
- * Revision 1.3  1999/07/01 15:26:56  calle
- * complete new version (I love it):
- * + new hardware independed "capi_driver" interface that will make it easy to:
- *   - support other controllers with CAPI-2.0 (i.e. USB Controller)
- *   - write a CAPI-2.0 for the passive cards
- *   - support serial link CAPI-2.0 boxes.
- * + wrote "capi_driver" for all supported cards.
- * + "capi_driver" (supported cards) now have to be configured with
- *   make menuconfig, in the past all supported cards where included
- *   at once.
- * + new and better informations in /proc/capi/
- * + new ioctl to switch trace of capi messages per controller
- *   using "avmcapictrl trace [contr] on|off|...."
- * + complete testcircle with all supported cards and also the
- *   PCMCIA cards (now patch for pcmcia-cs-3.0.13 needed) done.
- *
- * Revision 1.2  1999/06/21 15:24:26  calle
- * extend information in /proc.
- *
- * Revision 1.1  1997/03/04 21:27:33  calle
- * First version in isdn4linux
- *
- * Revision 2.2  1997/02/12 09:31:39  calle
- * new version
- *
- * Revision 1.1  1997/01/31 10:32:20  calle
- * Initial revision
- *
- * 
  */
+
 #ifndef __KERNELCAPI_H__
 #define __KERNELCAPI_H__
 
-#define CAPI_MAXAPPL	20	/*
-				   * maximum number of applications 
-				 */
-#define CAPI_MAXCONTR	10	/*
-				   * maximum number of controller 
-				 */
+#define CAPI_MAXAPPL	128	/* maximum number of applications  */
+#define CAPI_MAXCONTR	16	/* maximum number of controller    */
 #define CAPI_MAXDATAWINDOW	8
 
 
@@ -94,8 +53,8 @@
 	__u16 (*capi_put_message) (__u16 applid, struct sk_buff * msg);
 	__u16 (*capi_get_message) (__u16 applid, struct sk_buff ** msgp);
 	__u16 (*capi_set_signal) (__u16 applid,
-			      void (*signal) (__u16 applid, __u32 param),
-				  __u32 param);
+			      void (*signal) (__u16 applid, void *param),
+				  void *param);
 	__u16 (*capi_get_manufacturer) (__u32 contr, __u8 buf[CAPI_MANUFACTURER_LEN]);
 	__u16 (*capi_get_version) (__u32 contr, struct capi_version * verp);
 	 __u16(*capi_get_serial) (__u32 contr, __u8 serial[CAPI_SERIAL_LEN]);
@@ -108,8 +67,15 @@
 
 };
 
-#define	KCI_CONTRUP	0
-#define	KCI_CONTRDOWN	1
+struct capi_ncciinfo {
+	__u16 applid;
+	__u32 ncci;
+};
+
+#define	KCI_CONTRUP	0	/* struct capi_profile */
+#define	KCI_CONTRDOWN	1	/* NULL */
+#define	KCI_NCCIUP	2	/* struct capi_ncciinfo */
+#define	KCI_NCCIDOWN	3	/* struct capi_ncciinfo */
 
 struct capi_interface_user {
 	char name[20];
@@ -147,6 +113,47 @@
 #define CAPI_MSGNOTINSTALLED 	          0x1109
 #define CAPI_MSGCTRLERNOTSUPPORTEXTEQUIP  0x110a
 #define CAPI_MSGCTRLERONLYSUPPORTEXTEQUIP 0x110b
+
+typedef enum {
+        CapiMessageNotSupportedInCurrentState = 0x2001,
+        CapiIllContrPlciNcci                  = 0x2002,
+        CapiNoPlciAvailable                   = 0x2003,
+        CapiNoNcciAvailable                   = 0x2004,
+        CapiNoListenResourcesAvailable        = 0x2005,
+        CapiNoFaxResourcesAvailable           = 0x2006,
+        CapiIllMessageParmCoding              = 0x2007,
+} RESOURCE_CODING_PROBLEM;
+
+typedef enum {
+        CapiB1ProtocolNotSupported                      = 0x3001,
+        CapiB2ProtocolNotSupported                      = 0x3002,
+        CapiB3ProtocolNotSupported                      = 0x3003,
+        CapiB1ProtocolParameterNotSupported             = 0x3004,
+        CapiB2ProtocolParameterNotSupported             = 0x3005,
+        CapiB3ProtocolParameterNotSupported             = 0x3006,
+        CapiBProtocolCombinationNotSupported            = 0x3007,
+        CapiNcpiNotSupported                            = 0x3008,
+        CapiCipValueUnknown                             = 0x3009,
+        CapiFlagsNotSupported                           = 0x300a,
+        CapiFacilityNotSupported                        = 0x300b,
+        CapiDataLengthNotSupportedByCurrentProtocol     = 0x300c,
+        CapiResetProcedureNotSupportedByCurrentProtocol = 0x300d,
+        CapiTeiAssignmentFailed                         = 0x300e,
+} REQUESTED_SERVICES_PROBLEM;
+
+typedef enum {
+	CapiSuccess                                     = 0x0000,
+	CapiSupplementaryServiceNotSupported            = 0x300e,
+	CapiRequestNotAllowedInThisState                = 0x3010,
+} SUPPLEMENTARY_SERVICE_INFO;
+
+typedef enum {
+	CapiProtocolErrorLayer1                         = 0x3301,
+	CapiProtocolErrorLayer2                         = 0x3302,
+	CapiProtocolErrorLayer3                         = 0x3303,
+	CapiTimeOut                                     = 0x3303, // SuppServiceReason
+	CapiCallGivenToOtherApplication                 = 0x3304,
+} CAPI_REASON;
 
 #endif				/* __KERNEL__ */
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/lockd/nlm.h linux.19p18/include/linux/lockd/nlm.h
--- linux.vanilla/include/linux/lockd/nlm.h	Mon Dec 11 22:13:07 2000
+++ linux.19p18/include/linux/lockd/nlm.h	Mon Feb 12 14:51:59 2001
@@ -45,10 +45,10 @@
 #define NLMPROC_CANCEL_RES	13
 #define NLMPROC_UNLOCK_RES	14
 #define NLMPROC_GRANTED_RES	15
+#define NLMPROC_NSM_NOTIFY	16		/* statd callback */
 #define NLMPROC_SHARE		20
 #define NLMPROC_UNSHARE		21
 #define NLMPROC_NM_LOCK		22
 #define NLMPROC_FREE_ALL	23
-#define NLMPROC_NSM_NOTIFY	24		/* statd callback */
 
 #endif /* LINUX_LOCKD_NLM_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/locks.h linux.19p18/include/linux/locks.h
--- linux.vanilla/include/linux/locks.h	Fri Apr 21 23:10:16 2000
+++ linux.19p18/include/linux/locks.h	Sat Mar  3 22:39:07 2001
@@ -50,10 +50,12 @@
 	if (sb->s_lock)
 		__wait_on_super(sb);
 	sb->s_lock = 1;
+	current->fs_locks++;
 }
 
 extern inline void unlock_super(struct super_block * sb)
 {
+	current->fs_locks--;
 	sb->s_lock = 0;
 	wake_up(&sb->s_wait);
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/major.h linux.19p18/include/linux/major.h
--- linux.vanilla/include/linux/major.h	Mon Dec 11 22:13:07 2000
+++ linux.19p18/include/linux/major.h	Wed Dec 13 21:31:48 2000
@@ -133,6 +133,8 @@
 #define MSR_MAJOR 202
 #define CPUID_MAJOR 203
 
+#define OSST_MAJOR	206	/* OnStream-SCx0 SCSI tape */
+
 /*
  * Tests for SCSI devices.
  */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/mc146818rtc.h linux.19p18/include/linux/mc146818rtc.h
--- linux.vanilla/include/linux/mc146818rtc.h	Mon Dec 11 22:13:07 2000
+++ linux.19p18/include/linux/mc146818rtc.h	Sat Mar  3 22:39:27 2001
@@ -11,6 +11,7 @@
 #ifndef _MC146818RTC_H
 #define _MC146818RTC_H
 #include <asm/io.h>
+#include <linux/rtc.h>
 
 #ifndef RTC_PORT
 #define RTC_PORT(x)	(0x70 + (x))
@@ -26,7 +27,9 @@
 outb_p((val),RTC_PORT(1)); \
 })
 
+#ifdef __KERNEL__
 extern spinlock_t rtc_lock;	/* You must hold this lock to use CMOS_* ops */
+#endif
 
 /**********************************************************************
  * register summary
@@ -107,45 +110,5 @@
 #ifndef BIN_TO_BCD
 #define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
 #endif
-
-/*
- * The struct used to pass data via the following ioctl. Similar to the
- * struct tm in <time.h>, but it needs to be here so that the kernel 
- * source is self contained, allowing cross-compiles, etc. etc.
- */
-
-struct rtc_time {
-	int tm_sec;
-	int tm_min;
-	int tm_hour;
-	int tm_mday;
-	int tm_mon;
-	int tm_year;
-	int tm_wday;
-	int tm_yday;
-	int tm_isdst;
-};
-
-/*
- * ioctl calls that are permitted to the /dev/rtc interface, if 
- * CONFIG_RTC was enabled.
- */
-
-#define RTC_AIE_ON	_IO('p', 0x01)	/* Alarm int. enable on		*/
-#define RTC_AIE_OFF	_IO('p', 0x02)	/* ... off			*/
-#define RTC_UIE_ON	_IO('p', 0x03)	/* Update int. enable on	*/
-#define RTC_UIE_OFF	_IO('p', 0x04)	/* ... off			*/
-#define RTC_PIE_ON	_IO('p', 0x05)	/* Periodic int. enable on	*/
-#define RTC_PIE_OFF	_IO('p', 0x06)	/* ... off			*/
-
-#define RTC_ALM_SET	_IOW('p', 0x07, struct rtc_time) /* Set alarm time  */
-#define RTC_ALM_READ	_IOR('p', 0x08, struct rtc_time) /* Read alarm time */
-#define RTC_RD_TIME	_IOR('p', 0x09, struct rtc_time) /* Read RTC time   */
-#define RTC_SET_TIME	_IOW('p', 0x0a, struct rtc_time) /* Set RTC time    */
-#define RTC_IRQP_READ	_IOR('p', 0x0b, unsigned long)	 /* Read IRQ rate   */
-#define RTC_IRQP_SET	_IOW('p', 0x0c, unsigned long)	 /* Set IRQ rate    */
-#define RTC_EPOCH_READ	_IOR('p', 0x0d, unsigned long)	 /* Read epoch      */
-#define RTC_EPOCH_SET	_IOW('p', 0x0e, unsigned long)	 /* Set epoch       */
-
 
 #endif /* _MC146818RTC_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/miscdevice.h linux.19p18/include/linux/miscdevice.h
--- linux.vanilla/include/linux/miscdevice.h	Fri Apr 21 12:46:59 2000
+++ linux.19p18/include/linux/miscdevice.h	Wed Dec 13 21:50:26 2000
@@ -17,6 +17,7 @@
 #define SUN_OPENPROM_MINOR 139
 #define NVRAM_MINOR 144
 #define I2O_MINOR 166
+#define MICROCODE_MINOR 184
 #define MISC_DYNAMIC_MINOR 255
 
 #define SGI_GRAPHICS_MINOR   146
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/mtio.h linux.19p18/include/linux/mtio.h
--- linux.vanilla/include/linux/mtio.h	Fri Apr 21 23:10:54 2000
+++ linux.19p18/include/linux/mtio.h	Wed Dec 13 21:31:48 2000
@@ -105,6 +105,8 @@
 #define MT_ISEVEREX_FT40A	0x32	/* Everex FT40A (QIC-40) */
 #define MT_ISDDS1		0x51	/* DDS device without partitions */
 #define MT_ISDDS2		0x52	/* DDS device with partitions */
+#define MT_ISONSTREAM_SC        0x61	/* OnStream SCSI tape drives (SC-x0)
+					   and SCSI emulated (DI, DP, USB) */
 #define MT_ISSCSI1		0x71	/* Generic ANSI SCSI-1 tape unit */
 #define MT_ISSCSI2		0x72	/* Generic ANSI SCSI-2 tape unit */
 
@@ -134,6 +136,7 @@
 	{MT_ISWT5099EEN24,	"Wangtek 5099-een24, 60MB"}, \
 	{MT_ISTEAC_MT2ST,	"Teac MT-2ST 155mb data cassette drive"}, \
 	{MT_ISEVEREX_FT40A,	"Everex FT40A, QIC-40"}, \
+	{MT_ISONSTREAM_SC,      "OnStream SC-, DI-, DP-, or USB tape drive"}, \
 	{MT_ISSCSI1,		"Generic SCSI-1 tape"}, \
 	{MT_ISSCSI2,		"Generic SCSI-2 tape"}, \
 	{0, NULL} \
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/nfs.h linux.19p18/include/linux/nfs.h
--- linux.vanilla/include/linux/nfs.h	Mon Dec 11 22:13:07 2000
+++ linux.19p18/include/linux/nfs.h	Thu Feb  1 15:41:23 2001
@@ -94,8 +94,8 @@
  */
 #define NFS_MAXFHSIZE		64
 struct nfs_fh {
-	unsigned short		size;
-	unsigned char		data[NFS_MAXFHSIZE];
+	unsigned int		size;
+	unsigned int		data[NFS_MAXFHSIZE / sizeof(unsigned int)];
 };
 
 enum nfs3_stable_how {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/nfs3.h linux.19p18/include/linux/nfs3.h
--- linux.vanilla/include/linux/nfs3.h	Mon Dec 11 22:13:07 2000
+++ linux.19p18/include/linux/nfs3.h	Thu Feb  1 15:09:19 2001
@@ -58,6 +58,11 @@
 	NF3BAD  = 8
 };
 
+struct nfs3_fh {
+	unsigned short		size;
+	unsigned char		data[NFS3_FHSIZE];
+};
+
 #define NFS3_VERSION		3
 #define NFS3PROC_NULL		0
 #define NFS3PROC_GETATTR	1
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/nfs_fs.h linux.19p18/include/linux/nfs_fs.h
--- linux.vanilla/include/linux/nfs_fs.h	Mon Dec 11 22:13:07 2000
+++ linux.19p18/include/linux/nfs_fs.h	Sat Mar  3 22:39:19 2001
@@ -54,8 +54,7 @@
 /*
  * Convenience macros
  */
-#define NFS_FH(dentry)			((struct nfs_fh *) ((dentry)->d_fsdata))
-#define NFS_DSERVER(dentry)		(&(dentry)->d_sb->u.nfs_sb.s_server)
+#define NFS_FH(inode)			(&(inode)->u.nfs_i.fh)
 #define NFS_SERVER(inode)		(&(inode)->i_sb->u.nfs_sb.s_server)
 #define NFS_CLIENT(inode)		(NFS_SERVER(inode)->client)
 #define NFS_PROTO(inode)		(NFS_SERVER(inode)->rpc_ops)
@@ -84,12 +83,11 @@
 
 #define NFS_FLAGS(inode)		((inode)->u.nfs_i.flags)
 #define NFS_REVALIDATING(inode)		(NFS_FLAGS(inode) & NFS_INO_REVALIDATING)
+#define NFS_STALE(inode)		(NFS_FLAGS(inode) & NFS_INO_STALE)
 
 #define NFS_FILEID(inode)	((inode)->u.nfs_i.fileid)
 #define NFS_FSID(inode)		((inode)->u.nfs_i.fsid)
 
-#define NFS_FILE(file)		((struct nfs_file *)(file)->private_data)
-
 /* Inode Flags */
 #define NFS_USE_READDIRPLUS(inode)	((NFS_FLAGS(inode) & NFS_INO_ADVISE_RDPLUS) ? 1 : 0)
 
@@ -114,24 +112,6 @@
 #define FLUSH_STABLE		4	/* commit to stable storage */
 
 
-/*
- * Structure for file->private_data;
- */
-struct nfs_file {
-	unsigned long		magic;		/* Magic number */
-	struct rpc_cred*	cred;		/* RPC Credentials */
-};
-
-static inline int
-nfs_check_file(struct file *file)
-{
-	if (NFS_FILE(file)->magic != NFS_FILE_MAGIC) {
-		printk(KERN_ERR "NFS: corrupt file structure!\n");
-		return 0;
-	}
-	return 1;
-}
-
 static inline
 unsigned long nfs_page_offset(struct page *page)
 {
@@ -147,6 +127,8 @@
 /*
  * linux/fs/nfs/inode.c
  */
+extern int nfs_inode_is_stale(struct inode *, struct nfs_fh *,
+			       struct nfs_fattr *);
 extern struct inode *nfs_fhget(struct dentry *, struct nfs_fh *,
 			       struct nfs_fattr *);
 extern struct super_block *nfs_read_super(struct super_block *, void *, int);
@@ -155,7 +137,7 @@
 extern int	nfs_revalidate(struct dentry *);
 extern int	nfs_open(struct inode *, struct file *);
 extern int	nfs_release(struct inode *, struct file *);
-extern int	__nfs_revalidate_inode(struct dentry *);
+extern int	__nfs_revalidate_inode(struct nfs_server *, struct inode *);
 extern int	nfs_refresh_inode(struct inode *, struct nfs_fattr *);
 extern int	nfs_wait_on_inode(struct inode *, int flag);
 extern void	nfs_unlock_inode(struct inode *);
@@ -286,19 +268,18 @@
  * linux/fs/mount_clnt.c
  * (Used only by nfsroot module)
  */
-extern int  nfs_mount(struct sockaddr_in *, char *, struct nfs_fh *);
-extern int  nfs3_mount(struct sockaddr_in *, char *, struct nfs_fh *);
+extern int  nfs_mount(struct sockaddr_in *, char *, struct nfs3_fh *);
+extern int  nfs3_mount(struct sockaddr_in *, char *, struct nfs3_fh *);
 
 /*
  * inline functions
  */
 static inline int
-nfs_revalidate_inode(struct dentry *dentry)
+nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
 {
-	struct inode *inode = dentry->d_inode;
 	if (time_before(jiffies,NFS_READTIME(inode)+NFS_ATTRTIMEO(inode)))
 		return 0;
-	return __nfs_revalidate_inode(dentry);
+	return __nfs_revalidate_inode(server, inode);
 }
 
 static inline off_t
@@ -325,11 +306,7 @@
 static __inline__ struct rpc_cred *
 nfs_file_cred(struct file *file)
 {
-	if (!NFS_FILE(file) || !nfs_check_file(file)) {
-		printk("nfs_file_cred: invalid file!\n");
-		return NULL;
-	}
-	return NFS_FILE(file)->cred;
+	return (struct rpc_cred *)(file->private_data);
 }
 
 /* NFS root */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/nfs_fs_i.h linux.19p18/include/linux/nfs_fs_i.h
--- linux.vanilla/include/linux/nfs_fs_i.h	Mon Dec 11 22:13:07 2000
+++ linux.19p18/include/linux/nfs_fs_i.h	Mon Feb 12 14:51:59 2001
@@ -1,6 +1,7 @@
 #ifndef _NFS_FS_i
 #define _NFS_FS_I
 
+#include <linux/list.h>
 #include <linux/nfs.h>
 #include <linux/pipe_fs_i.h>
 
@@ -22,6 +23,11 @@
 	__u64 fileid;
 
 	/*
+	 * NFS file handle
+	 */
+	struct nfs_fh		fh;
+
+	/*
 	 * Various flags
 	 */
 	unsigned short		flags;
@@ -79,12 +85,10 @@
 /*
  * Legal inode flag values
  */
-#define NFS_INO_LOCKED          0x0001          /* locked for revalidation */
+#define NFS_INO_STALE		0x0001		/* We suspect inode is stale */
 #define NFS_INO_ADVISE_RDPLUS   0x0002          /* advise readdirplus */
 #define NFS_INO_REVALIDATING    0x0004          /* in nfs_revalidate() */
-#define NFS_INO_INVALIDATE      0x0008          /* zap cache on next occasion */
 #define NFS_IS_SNAPSHOT		0x0010		/* a snapshot file */
-#define NFS_INO_STALE		0x0020		/* We suspect inode is stale */
 #define NFS_INO_FLUSH		0x0040		/* inode is due for flushing */
 
 /*
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/nfs_mount.h linux.19p18/include/linux/nfs_mount.h
--- linux.vanilla/include/linux/nfs_mount.h	Mon Dec 11 22:13:07 2000
+++ linux.19p18/include/linux/nfs_mount.h	Thu Feb  1 15:09:19 2001
@@ -8,9 +8,9 @@
  *
  *  structure passed from user-space to kernel-space during an nfs mount
  */
-#include <linux/nfs.h>
+#include <linux/in.h>
 #include <linux/nfs2.h>
-#include <linux/nfs_fs.h>
+#include <linux/nfs3.h>
 
 /*
  * WARNING!  Do not delete or change the order of these fields.  If
@@ -42,7 +42,7 @@
 	char		hostname[256];		/* 1 */
 	int		namlen;			/* 2 */
 	unsigned int	bsize;			/* 3 */
-	struct nfs_fh	root;			/* 4 */
+	struct nfs3_fh	root;			/* 4 */
 };
 
 /* bits in the flags field */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/nfs_page.h linux.19p18/include/linux/nfs_page.h
--- linux.vanilla/include/linux/nfs_page.h	Mon Dec 11 22:13:07 2000
+++ linux.19p18/include/linux/nfs_page.h	Sat Mar  3 23:02:25 2001
@@ -26,7 +26,7 @@
 				wb_list,	/* Defines state of page: */
 				*wb_list_head;	/*      read/write/commit */
 	struct file		*wb_file;
-	struct dentry		*wb_dentry;
+	struct inode		*wb_inode;
 	struct rpc_cred		*wb_cred;
 	struct page		*wb_page;	/* page to read in/write out */
 	struct wait_queue	*wb_wait;	/* wait queue */
@@ -41,6 +41,7 @@
 #define NFS_WBACK_BUSY(req)	((req)->wb_flags & PG_BUSY)
 
 extern	struct nfs_page *nfs_create_request(struct file *file,
+					    struct inode *inode,
 					    struct page *page,
 					    unsigned int offset,
 					    unsigned int count);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/nfs_xdr.h linux.19p18/include/linux/nfs_xdr.h
--- linux.vanilla/include/linux/nfs_xdr.h	Mon Dec 11 22:13:07 2000
+++ linux.19p18/include/linux/nfs_xdr.h	Mon Feb 12 14:51:59 2001
@@ -321,48 +321,43 @@
 
 	int	(*getroot)(struct nfs_server *,
 			struct nfs_fh *, struct nfs_fattr *);
-	int	(*getattr)(struct dentry *, struct nfs_fattr *);
-	int	(*setattr)(struct dentry *, struct nfs_fattr *, struct iattr *);
-	int	(*lookup)(struct dentry *, struct nfs_fattr *, struct qstr *,
+	int	(*getattr)(struct inode *, struct nfs_fattr *);
+	int	(*setattr)(struct inode *, struct nfs_fattr *, struct iattr *);
+	int	(*lookup)(struct inode *, struct qstr *,
 			struct nfs_fh *, struct nfs_fattr *);
-	int	(*access)(struct dentry *, int fmode, struct nfs_fattr *, int);
-	int	(*readlink)(struct dentry *, struct nfs_fattr *,
-			void *buffer, unsigned int buflen);
-	int	(*read)(struct dentry *, struct nfs_fattr *,
-			struct rpc_cred *,
+	int	(*access)(struct inode *, int, int);
+	int	(*readlink)(struct inode *, void *buffer, unsigned int buflen);
+	int	(*read)(struct inode *, struct rpc_cred *,
+			struct nfs_fattr *,
 			int flags, unsigned long offset,
 			unsigned int count, void *buffer, int *eofp);
-	int	(*write)(struct dentry *, struct nfs_fattr *,
-			struct rpc_cred *,
+	int	(*write)(struct inode *, struct rpc_cred *,
+			struct nfs_fattr *,
 			int flags, unsigned long offset,
 			unsigned int count, void *buffer,
 			struct nfs_writeverf *verfp);
-	int	(*commit)(struct dentry *, struct nfs_fattr *,
+	int	(*commit)(struct inode *, struct nfs_fattr *,
 			struct rpc_cred *,
 			unsigned long, unsigned int);
-	int	(*create)(struct dentry *, struct nfs_fattr *,
-			struct qstr *, struct iattr *, int flags,
-			struct nfs_fh *, struct nfs_fattr *);
-	int	(*remove)(struct dentry *, struct nfs_fattr *, struct qstr *);
+	int	(*create)(struct inode *, struct qstr *, struct iattr *,
+			  int, struct nfs_fh *, struct nfs_fattr *);
+	int	(*remove)(struct inode *, struct qstr *);
 	int	(*unlink_setup)	(struct rpc_message *,
 			struct dentry *, struct qstr *);
 	void	(*unlink_done)	(struct dentry *, struct rpc_message *);
-	int	(*rename)(struct dentry *, struct nfs_fattr *, struct qstr *,
-			struct dentry *, struct nfs_fattr *, struct qstr *);
-	int	(*link)(struct dentry *, struct nfs_fattr *,
-			struct dentry *, struct nfs_fattr *, struct qstr *);
-	int	(*symlink)(struct dentry *, struct nfs_fattr *, struct qstr *,
-			struct qstr *, struct iattr *,
-			struct nfs_fh *, struct nfs_fattr *);
-	int	(*mkdir)(struct dentry *, struct nfs_fattr *, struct qstr *,
-			struct iattr *, struct nfs_fh *, struct nfs_fattr *);
-	int	(*rmdir)(struct dentry *, struct nfs_fattr *, struct qstr *);
-	int	(*readdir)(struct dentry *, struct nfs_fattr *,
-			struct rpc_cred *,
-			__u64 cookie, void *, unsigned int size, int plus);
-	int	(*mknod)(struct dentry *, struct nfs_fattr *, struct qstr *,
-			struct iattr *, dev_t,
-			struct nfs_fh *, struct nfs_fattr *);
+	int	(*rename)(struct inode *, struct qstr *,
+			struct inode *, struct qstr *);
+	int	(*link)(struct inode *, struct inode *, struct qstr *);
+	int	(*symlink)(struct inode *, struct qstr *, struct qstr *,
+			   struct iattr *, struct nfs_fh *,
+			   struct nfs_fattr *);
+	int	(*mkdir)(struct inode *, struct qstr *,	struct iattr *,
+			 struct nfs_fh *, struct nfs_fattr *);
+	int	(*rmdir)(struct inode *, struct qstr *);
+	int	(*readdir)(struct inode *, struct rpc_cred *,
+			__u64, void *, unsigned int, int);
+	int	(*mknod)(struct inode *, struct qstr *,	struct iattr *,
+			 dev_t,	struct nfs_fh *, struct nfs_fattr *);
 	int	(*statfs)(struct nfs_server *, struct nfs_fh *,
 			struct nfs_fsinfo *);
 	__u32 *	(*decode_dirent)(__u32 *, struct nfs_entry *, int plus);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/nfsd/nfsd.h linux.19p18/include/linux/nfsd/nfsd.h
--- linux.vanilla/include/linux/nfsd/nfsd.h	Mon Dec 11 22:13:07 2000
+++ linux.19p18/include/linux/nfsd/nfsd.h	Sun Feb 25 23:41:39 2001
@@ -100,7 +100,7 @@
 int		nfsd_read(struct svc_rqst *, struct svc_fh *,
 				loff_t, char *, unsigned long *);
 int		nfsd_write(struct svc_rqst *, struct svc_fh *,
-				loff_t, char *, unsigned long, int);
+				loff_t, char *, unsigned long, int *);
 int		nfsd_readlink(struct svc_rqst *, struct svc_fh *,
 				char *, int *);
 int		nfsd_symlink(struct svc_rqst *, struct svc_fh *,
@@ -145,38 +145,41 @@
 #endif
 
 /*
- * These variables contain pre-xdr'ed values for faster operation.
- * FIXME: should be replaced by macros for big-endian machines.
+ * These macros provide pre-xdr'ed values for faster operation.
  */
-extern u32	nfs_ok,
-		nfserr_perm,
-		nfserr_noent,
-		nfserr_io,
-		nfserr_nxio,
-		nfserr_acces,
-		nfserr_exist,
-		nfserr_xdev,
-		nfserr_nodev,
-		nfserr_notdir,
-		nfserr_isdir,
-		nfserr_inval,
-		nfserr_fbig,
-		nfserr_nospc,
-		nfserr_rofs,
-		nfserr_mlink,
-		nfserr_nametoolong,
-		nfserr_notempty,
-		nfserr_dquot,
-		nfserr_stale,
-		nfserr_remote,
-		nfserr_badhandle,
-		nfserr_notsync,
-		nfserr_badcookie,
-		nfserr_notsupp,
-		nfserr_toosmall,
-		nfserr_serverfault,
-		nfserr_badtype,
-		nfserr_jukebox;
+#define	nfs_ok			__constant_htonl(NFS_OK)
+#define	nfserr_perm		__constant_htonl(NFSERR_PERM)
+#define	nfserr_noent		__constant_htonl(NFSERR_NOENT)
+#define	nfserr_io		__constant_htonl(NFSERR_IO)
+#define	nfserr_nxio		__constant_htonl(NFSERR_NXIO)
+#define	nfserr_acces		__constant_htonl(NFSERR_ACCES)
+#define	nfserr_exist		__constant_htonl(NFSERR_EXIST)
+#define	nfserr_xdev		__constant_htonl(NFSERR_XDEV)
+#define	nfserr_nodev		__constant_htonl(NFSERR_NODEV)
+#define	nfserr_notdir		__constant_htonl(NFSERR_NOTDIR)
+#define	nfserr_isdir		__constant_htonl(NFSERR_ISDIR)
+#define	nfserr_inval		__constant_htonl(NFSERR_INVAL)
+#define	nfserr_fbig		__constant_htonl(NFSERR_FBIG)
+#define	nfserr_nospc		__constant_htonl(NFSERR_NOSPC)
+#define	nfserr_rofs		__constant_htonl(NFSERR_ROFS)
+#define	nfserr_mlink		__constant_htonl(NFSERR_MLINK)
+#define	nfserr_opnotsupp	__constant_htonl(NFSERR_OPNOTSUPP)
+#define	nfserr_nametoolong	__constant_htonl(NFSERR_NAMETOOLONG)
+#define	nfserr_notempty		__constant_htonl(NFSERR_NOTEMPTY)
+#define	nfserr_dquot		__constant_htonl(NFSERR_DQUOT)
+#define	nfserr_stale		__constant_htonl(NFSERR_STALE)
+#define	nfserr_remote		__constant_htonl(NFSERR_REMOTE)
+#define	nfserr_badhandle	__constant_htonl(NFSERR_BADHANDLE)
+#define	nfserr_notsync		__constant_htonl(NFSERR_NOTSYNC)
+#define	nfserr_badcookie	__constant_htonl(NFSERR_BADCOOKIE)
+#define	nfserr_notsupp		__constant_htonl(NFSERR_NOTSUPP)
+#define	nfserr_toosmall		__constant_htonl(NFSERR_TOOSMALL)
+#define	nfserr_serverfault	__constant_htonl(NFSERR_SERVERFAULT)
+#define	nfserr_badtype		__constant_htonl(NFSERR_BADTYPE)
+#define	nfserr_jukebox		__constant_htonl(NFSERR_JUKEBOX)
+
+/* Check for dir entries '.' and '..' */
+#define isdotent(n, l)	(l < 3 && n[0] == '.' && (l == 1 || n[1] == '.'))
 
 /*
  * Time of server startup
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/nfsd/nfsfh.h linux.19p18/include/linux/nfsd/nfsfh.h
--- linux.vanilla/include/linux/nfsd/nfsfh.h	Mon Dec 11 22:13:07 2000
+++ linux.19p18/include/linux/nfsd/nfsfh.h	Sun Feb 25 23:25:28 2001
@@ -30,7 +30,7 @@
  * ino/dev of the exported inode.
  */
 struct nfs_fhbase {
-	struct dentry *	fb_dentry;	/* dentry cookie */
+	__u32		fb_dcookie;	/* dentry cookie */
 	__u32		fb_ino;		/* our inode number */
 	__u32		fb_dirino;	/* dir inode number */
 	__u32		fb_dev;		/* our device */
@@ -45,7 +45,7 @@
 	__u8			fh_cookie[NFS_FH_PADDING];
 };
 
-#define fh_dcookie		fh_base.fb_dentry
+#define fh_dcookie		fh_base.fb_dcookie
 #define fh_ino			fh_base.fb_ino
 #define fh_dirino		fh_base.fb_dirino
 #define fh_dev			fh_base.fb_dev
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/nfsd/xdr3.h linux.19p18/include/linux/nfsd/xdr3.h
--- linux.vanilla/include/linux/nfsd/xdr3.h	Mon Dec 11 22:13:07 2000
+++ linux.19p18/include/linux/nfsd/xdr3.h	Sun Feb 25 23:42:50 2001
@@ -296,19 +296,5 @@
 int nfs3svc_encode_entry_plus(struct readdir_cd *, const char *name,
 				int namlen, off_t offset, ino_t ino);
 
-#ifdef __KERNEL__
-
-/*
- * This is needed in nfs_readdir for encoding NFS3 directory cookies.
- */
-static inline u32 *
-enc64(u32 *p, u64 val)
-{
-	*p++ = htonl(val >> 32);
-	*p++ = htonl(val & 0xffffffff);
-	return p;
-}
-
-#endif /* __KERNEL__ */
 
 #endif /* _LINUX_NFSD_XDR3_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/nls.h linux.19p18/include/linux/nls.h
--- linux.vanilla/include/linux/nls.h	Mon Dec 11 22:13:07 2000
+++ linux.19p18/include/linux/nls.h	Wed Jan  3 01:05:05 2001
@@ -60,3 +60,4 @@
 extern int init_nls_cp949(void);
 extern int init_nls_cp950(void);
 extern int init_nls_koi8_r(void);
+extern int init_nls_koi8_ru(void);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/pci.h linux.19p18/include/linux/pci.h
--- linux.vanilla/include/linux/pci.h	Mon Dec 11 22:13:07 2000
+++ linux.19p18/include/linux/pci.h	Sat Dec 30 19:30:07 2000
@@ -307,6 +307,15 @@
  * (and according to card ID within vendor). Send all updates to
  * <linux-pcisupport@cck.uni-kl.de>.
  */
+#define PCI_VENDOR_ID_DYNALINK          0x0675
+#define PCI_DEVICE_ID_DYNALINK_IS64PH   0x1702
+
+#define PCI_VENDOR_ID_BERKOM		        0x0871
+#define PCI_DEVICE_ID_BERKOM_A1T	        0xFFA1
+#define PCI_DEVICE_ID_BERKOM_T_CONCEPT          0xFFA2
+#define PCI_DEVICE_ID_BERKOM_A4T	        0xFFA4
+#define PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO      0xFFA8
+
 #define PCI_VENDOR_ID_COMPAQ		0x0e11
 #define PCI_DEVICE_ID_COMPAQ_TOKENRING	0x0508
 #define PCI_DEVICE_ID_COMPAQ_1280	0x3033
@@ -477,6 +486,10 @@
 #define PCI_DEVICE_ID_CT_65554		0x00e4
 #define PCI_DEVICE_ID_CT_65555		0x00e5
 
+#define PCI_DEVICE_ID_PLX_R685		0x1030
+#define PCI_DEVICE_ID_PLX_DJINN_ITOO    0x1151
+#define PCI_DEVICE_ID_PLX_R753          0x1152
+
 #define PCI_VENDOR_ID_MIRO		0x1031
 #define PCI_DEVICE_ID_MIRO_36050	0x5601
 
@@ -515,6 +528,9 @@
 #define PCI_DEVICE_ID_PCTECH_SAMURAI_1	0x3010
 #define PCI_DEVICE_ID_PCTECH_SAMURAI_IDE 0x3020
 
+#define PCI_VENDOR_ID_ASUSTEK		0x1043
+#define PCI_DEVICE_ID_ASUSTEK_0675	0x0675
+
 #define PCI_VENDOR_ID_DPT               0x1044   
 #define PCI_DEVICE_ID_DPT               0xa400  
 
@@ -530,6 +546,10 @@
 #define PCI_DEVICE_ID_OPTI_82C861	0xc861
 #define PCI_DEVICE_ID_OPTI_82C825	0xd568
 
+#define PCI_VENDOR_ID_ELSA		0x1048
+#define PCI_DEVICE_ID_ELSA_MICROLINK	0x1000
+#define PCI_DEVICE_ID_ELSA_QS3000	0x3000
+
 #define PCI_VENDOR_ID_SGS		0x104a
 #define PCI_DEVICE_ID_SGS_2000		0x0008
 #define PCI_DEVICE_ID_SGS_1764		0x0009
@@ -554,6 +574,10 @@
 /* Winbond have two vendor IDs! See 0x10ad as well */
 #define PCI_VENDOR_ID_WINBOND2		0x1050
 #define PCI_DEVICE_ID_WINBOND2_89C940	0x0940
+#define PCI_DEVICE_ID_WINBOND2_6692	0x6692
+
+#define PCI_VENDOR_ID_ANIGMA		0x1051
+#define PCI_DEVICE_ID_ANIGMA_MC145575	0x0100
 
 #define PCI_VENDOR_ID_MOTOROLA		0x1057
 #define PCI_VENDOR_ID_MOTOROLA_OOPS	0x1507
@@ -873,6 +897,17 @@
 #define PCI_DEVICE_ID_PHILIPS_SAA7145	0x7145
 #define PCI_DEVICE_ID_PHILIPS_SAA7146	0x7146
 
+#define PCI_VENDOR_ID_EICON		0x1133
+#define PCI_DEVICE_ID_EICON_DIVA20PRO	0xe001
+#define PCI_DEVICE_ID_EICON_DIVA20	0xe002
+#define PCI_DEVICE_ID_EICON_DIVA20PRO_U	0xe003
+#define PCI_DEVICE_ID_EICON_DIVA20_U	0xe004
+#define PCI_DEVICE_ID_EICON_DIVA201	0xe005
+#define PCI_DEVICE_ID_EICON_MAESTRA	0xe010
+#define PCI_DEVICE_ID_EICON_MAESTRAQ	0xe012
+#define PCI_DEVICE_ID_EICON_MAESTRAQ_U	0xe013
+#define PCI_DEVICE_ID_EICON_MAESTRAP	0xe014
+
 #define PCI_VENDOR_ID_CYCLONE		0x113c
 #define PCI_DEVICE_ID_CYCLONE_SDK	0x0001
 
@@ -899,6 +934,10 @@
 #define PCI_DEVICE_ID_DIGI_XRJ		0x0009
 #define PCI_DEVICE_ID_DIGI_EPCJ		0x000a
 #define PCI_DEVICE_ID_DIGI_XR_920	0x0027
+#define PCI_DEVICE_ID_DIGI_DF_M_IOM2_E	0x0070
+#define PCI_DEVICE_ID_DIGI_DF_M_E	0x0071
+#define PCI_DEVICE_ID_DIGI_DF_M_IOM2_A	0x0072
+#define PCI_DEVICE_ID_DIGI_DF_M_A	0x0073
 
 #define PCI_VENDOR_ID_MUTECH		0x1159
 #define PCI_DEVICE_ID_MUTECH_MV1000	0x0001
@@ -1023,6 +1062,9 @@
 
 #define PCI_VENDOR_ID_AVM		0x1244
 #define PCI_DEVICE_ID_AVM_A1		0x0a00
+#define PCI_DEVICE_ID_AVM_B1		0x0700
+#define PCI_DEVICE_ID_AVM_C4		0x0800
+#define PCI_DEVICE_ID_AVM_T1		0x1200
 
 #define PCI_VENDOR_ID_DIPIX		0x1246
 
@@ -1039,6 +1081,7 @@
 #define PCI_DEVICE_ID_OPTIBASE_VQUEST	0x2130
 
 #define PCI_VENDOR_ID_SATSAGEM		0x1267
+#define PCI_DEVICE_ID_SATSAGEM_NICCY	0x1016
 #define PCI_DEVICE_ID_SATSAGEM_PCR2101	0x5352
 #define PCI_DEVICE_ID_SATSAGEM_TELSATTURBO 0x5a4b
 
@@ -1082,9 +1125,32 @@
 #define PCI_DEVICE_ID_SIIG_2S1P_20x_650	0x2061
 #define PCI_DEVICE_ID_SIIG_2S1P_20x_850	0x2062
 
+#define PCI_VENDOR_ID_HYPERCOPE		0x1365
+#define PCI_DEVICE_ID_HYPERCOPE_PLX	0x9050
+#define PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO     0x0104
+#define PCI_SUBDEVICE_ID_HYPERCOPE_ERGO         0x0106
+#define PCI_SUBDEVICE_ID_HYPERCOPE_METRO        0x0107
+#define PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2       0x0108
+#define PCI_SUBDEVICE_ID_HYPERCOPE_PLEXUS       0x0109
+
 #define PCI_VENDOR_ID_NETGEAR		0x1385
 #define PCI_DEVICE_ID_NETGEAR_GA620	0x620a
 
+#define PCI_VENDOR_ID_CCD		0x1397
+#define PCI_DEVICE_ID_CCD_2BD0	        0x2BD0
+#define PCI_DEVICE_ID_CCD_B000	        0xB000
+#define PCI_DEVICE_ID_CCD_B006	        0xB006
+#define PCI_DEVICE_ID_CCD_B007	        0xB007
+#define PCI_DEVICE_ID_CCD_B008	        0xB008
+#define PCI_DEVICE_ID_CCD_B009	        0xB009
+#define PCI_DEVICE_ID_CCD_B00A	        0xB00A
+#define PCI_DEVICE_ID_CCD_B00B	        0xB00B
+#define PCI_DEVICE_ID_CCD_B00C	        0xB00C
+#define PCI_DEVICE_ID_CCD_B100	        0xB100
+
+#define PCI_VENDOR_ID_ABOCOM		0x13D1
+#define PCI_DEVICE_ID_ABOCOM_2BD1       0x2BD1
+
 #define PCI_VENDOR_ID_LAVA		0x1407
 #define PCI_DEVICE_ID_LAVA_PARALLEL	0x8000
 #define PCI_DEVICE_ID_LAVA_DUAL_PAR_A	0x8002 /* The Lava Dual Parallel is */
@@ -1102,6 +1168,9 @@
 #define PCI_VENDOR_ID_AFAVLAB		0x14db
 #define PCI_DEVICE_ID_AFAVLAB_TK9902	0x2120
 
+#define PCI_VENDOR_ID_ZOLTRIX		0x15b0
+#define PCI_DEVICE_ID_ZOLTRIX_2BD0	0x2BD0
+
 #define PCI_VENDOR_ID_SYMPHONY		0x1c1c
 #define PCI_DEVICE_ID_SYMPHONY_101	0x0001
 
@@ -1258,6 +1327,7 @@
 
 #define PCI_VENDOR_ID_TIGERJET		0xe159
 #define PCI_DEVICE_ID_TIGERJET_300	0x0001
+#define PCI_DEVICE_ID_TIGERJET_100	0x0002
 
 #define PCI_VENDOR_ID_ARK		0xedd8
 #define PCI_DEVICE_ID_ARK_STING		0xa091
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/rtc.h linux.19p18/include/linux/rtc.h
--- linux.vanilla/include/linux/rtc.h	Thu Jan  1 01:00:00 1970
+++ linux.19p18/include/linux/rtc.h	Tue Jan  9 12:14:00 2001
@@ -0,0 +1,43 @@
+#ifndef _LINUX_RTC_H
+#define _LINUX_RTC_H_
+
+
+/*
+ * The struct used to pass data via the following ioctl. Similar to the
+ * struct tm in <time.h>, but it needs to be here so that the kernel 
+ * source is self contained, allowing cross-compiles, etc. etc.
+ */
+
+struct rtc_time {
+	int tm_sec;
+	int tm_min;
+	int tm_hour;
+	int tm_mday;
+	int tm_mon;
+	int tm_year;
+	int tm_wday;
+	int tm_yday;
+	int tm_isdst;
+};
+
+/*
+ * ioctls that are permitted to the /dev/rtc interface.
+ */
+
+#define RTC_AIE_ON	_IO('p', 0x01)	/* Alarm int. enable on		*/
+#define RTC_AIE_OFF	_IO('p', 0x02)	/* ... off			*/
+#define RTC_UIE_ON	_IO('p', 0x03)	/* Update int. enable on	*/
+#define RTC_UIE_OFF	_IO('p', 0x04)	/* ... off			*/
+#define RTC_PIE_ON	_IO('p', 0x05)	/* Periodic int. enable on	*/
+#define RTC_PIE_OFF	_IO('p', 0x06)	/* ... off			*/
+
+#define RTC_ALM_SET	_IOW('p', 0x07, struct rtc_time) /* Set alarm time  */
+#define RTC_ALM_READ	_IOR('p', 0x08, struct rtc_time) /* Read alarm time */
+#define RTC_RD_TIME	_IOR('p', 0x09, struct rtc_time) /* Read RTC time   */
+#define RTC_SET_TIME	_IOW('p', 0x0a, struct rtc_time) /* Set RTC time    */
+#define RTC_IRQP_READ	_IOR('p', 0x0b, unsigned long)	 /* Read IRQ rate   */
+#define RTC_IRQP_SET	_IOW('p', 0x0c, unsigned long)	 /* Set IRQ rate    */
+#define RTC_EPOCH_READ	_IOR('p', 0x0d, unsigned long)	 /* Read epoch      */
+#define RTC_EPOCH_SET	_IOW('p', 0x0e, unsigned long)	 /* Set epoch       */
+
+#endif /* _LINUX_RTC_H_ */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/sched.h linux.19p18/include/linux/sched.h
--- linux.vanilla/include/linux/sched.h	Mon Dec 11 22:13:07 2000
+++ linux.19p18/include/linux/sched.h	Sat Mar  3 22:39:06 2001
@@ -79,6 +79,7 @@
 #define TASK_ZOMBIE		4
 #define TASK_STOPPED		8
 #define TASK_SWAPPING		16
+#define TASK_EXCLUSIVE		32
 
 /*
  * Scheduling policies
@@ -119,6 +120,11 @@
 extern signed long FASTCALL(schedule_timeout(signed long timeout));
 asmlinkage void schedule(void);
 
+extern int schedule_task(struct tq_struct *task);
+extern void flush_scheduled_tasks(void);
+extern int start_context_thread(void);
+extern int current_is_keventd(void);
+
 /*
  * The default fd array needs to be at least BITS_PER_LONG,
  * as this is the granularity returned by copy_fdset().
@@ -180,7 +186,11 @@
 	atomic_t count;
 	int map_count;				/* number of VMAs */
 	struct semaphore mmap_sem;
+#ifdef __alpha__
+	unsigned long context[NR_CPUS];
+#else
 	unsigned long context;
+#endif
 	unsigned long start_code, end_code, start_data, end_data;
 	unsigned long start_brk, brk, start_stack;
 	unsigned long arg_start, arg_end, env_start, env_end;
@@ -196,12 +206,18 @@
 	void * segments;
 };
 
+#ifdef __alpha__
+#define CONTEXT_INIT	{ 0, }
+#else
+#define CONTEXT_INIT	0
+#endif
+
 #define INIT_MM {					\
 		&init_mmap, NULL, NULL,			\
 		swapper_pg_dir, 			\
 		ATOMIC_INIT(1), 1,			\
 		MUTEX,					\
-		0,					\
+		CONTEXT_INIT,				\
 		0, 0, 0, 0,				\
 		0, 0, 0, 				\
 		0, 0, 0, 0,				\
@@ -251,13 +267,14 @@
 	struct task_struct *next_task, *prev_task;
 	struct task_struct *next_run,  *prev_run;
 
+	unsigned int task_exclusive;	/* task wants wake-one semantics in __wake_up() */
 /* task state */
 	struct linux_binfmt *binfmt;
 	int exit_code, exit_signal;
 	int pdeath_signal;  /*  The signal sent when the parent dies  */
 	/* ??? */
 	unsigned long personality;
-	int dumpable:1;
+	unsigned int dumpable:1;
 	int did_exec:1;
 	pid_t pid;
 	pid_t pgrp;
@@ -317,6 +334,9 @@
 	struct files_struct *files;
 /* memory management info */
 	struct mm_struct *mm;
+	struct list_head local_pages;
+	int allocation_order, nr_local_pages;
+	int fs_locks;
 
 /* signal handlers */
 	spinlock_t sigmask_lock;	/* Protects signal and blocked */
@@ -349,6 +369,7 @@
 #define PF_SIGNALED	0x00000400	/* killed by a signal */
 #define PF_MEMALLOC	0x00000800	/* Allocating memory */
 #define PF_VFORK	0x00001000	/* Wake up parent in mm_release */
+#define PF_FREE_PAGES	0x00002000	/* The current-> */
 
 #define PF_USEDFPU	0x00100000	/* task used FPU this quantum (SMP) */
 #define PF_DTRACE	0x00200000	/* delayed trace (used on m68k, i386) */
@@ -370,6 +391,7 @@
 /* counter */	DEF_PRIORITY,DEF_PRIORITY,0, \
 /* SMP */	0,0,0,-1, \
 /* schedlink */	&init_task,&init_task, &init_task, &init_task, \
+/* task_exclusive */ 0, \
 /* binfmt */	NULL, \
 /* ec,brk... */	0,0,0,0,0,0, \
 /* pid etc.. */	0,0,0,0,0, \
@@ -397,7 +419,7 @@
 /* tss */	INIT_TSS, \
 /* fs */	&init_fs, \
 /* files */	&init_files, \
-/* mm */	&init_mm, \
+/* mm */	&init_mm, { &init_task.local_pages, &init_task.local_pages}, 0, 0, 0, \
 /* signals */	SPIN_LOCK_UNLOCKED, &init_signals, {{0}}, {{0}}, NULL, &init_task.sigqueue, 0, 0, \
 /* exec cts */	0,0, \
 /* oom */	0, \
@@ -496,8 +518,15 @@
 						    signed long timeout));
 extern void FASTCALL(wake_up_process(struct task_struct * tsk));
 
-#define wake_up(x)			__wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE)
-#define wake_up_interruptible(x)	__wake_up((x),TASK_INTERRUPTIBLE)
+#define wake_up(x)			__wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE | TASK_EXCLUSIVE)
+#define wake_up_interruptible(x)	__wake_up((x),TASK_INTERRUPTIBLE | TASK_EXCLUSIVE)
+
+#define __set_task_state(tsk, state_value)	do { (tsk)->state = state_value; } while (0)
+#ifdef __SMP__
+#define set_task_state(tsk, state_value)	do { __set_task_state(tsk, state_value); mb(); } while (0)
+#else
+#define set_task_state(tsk, state_value)	__set_task_state(tsk, state_value)
+#endif
 
 #define __set_current_state(state_value)	do { current->state = state_value; } while (0)
 #ifdef __SMP__
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/sunrpc/clnt.h linux.19p18/include/linux/sunrpc/clnt.h
--- linux.vanilla/include/linux/sunrpc/clnt.h	Mon Dec 11 22:13:08 2000
+++ linux.19p18/include/linux/sunrpc/clnt.h	Sat Mar  3 23:01:26 2001
@@ -111,6 +111,8 @@
 void		rpc_release_client(struct rpc_clnt *);
 void		rpc_getport(struct rpc_task *, struct rpc_clnt *);
 int		rpc_register(u32, u32, int, unsigned short, int *);
+u32 *		rpc_call_header(struct rpc_task *task);
+u32 *		rpc_call_verify(struct rpc_task *task);
 
 void		rpc_call_setup(struct rpc_task *, struct rpc_message *, int);
 
@@ -143,6 +145,11 @@
  * Helper function for NFSroot support
  */
 int		rpc_getport_external(struct sockaddr_in *, __u32, __u32, int);
+
+/*
+ * Ping function
+ */
+void		rpc_ping(struct rpc_task *task);
 
 #endif /* __KERNEL__ */
 #endif /* _LINUX_SUNRPC_CLNT_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/sunrpc/sched.h linux.19p18/include/linux/sunrpc/sched.h
--- linux.vanilla/include/linux/sunrpc/sched.h	Mon Dec 11 22:13:08 2000
+++ linux.19p18/include/linux/sunrpc/sched.h	Sun Feb 25 23:23:44 2001
@@ -45,7 +45,7 @@
 	struct rpc_task *	tk_parent;	/* parent task */
 	struct rpc_clnt *	tk_client;	/* RPC client */
 	struct rpc_rqst *	tk_rqstp;	/* RPC request */
-	volatile int		tk_status;	/* result of last operation */
+	int			tk_status;	/* result of last operation */
 	struct rpc_wait_queue *	tk_rpcwait;	/* RPC wait queue we're on */
 
 	/*
@@ -81,8 +81,7 @@
 	unsigned int		tk_lock;	/* Task lock counter */
 	unsigned char		tk_active   : 1,/* Task has been activated */
 				tk_wakeup   : 1;/* Task waiting to wake up */
-	volatile unsigned char	tk_running  : 1,/* Task is running */
-				tk_sleeping : 1;/* Task is truly asleep */
+	unsigned int		tk_runstate;	/* Task run status */
 #ifdef RPC_DEBUG
 	unsigned int		tk_pid;		/* debugging aid */
 #endif
@@ -112,10 +111,20 @@
 #define RPC_IS_SWAPPER(t)	((t)->tk_flags & RPC_TASK_SWAPPER)
 #define RPC_DO_ROOTOVERRIDE(t)	((t)->tk_flags & RPC_TASK_ROOTCREDS)
 #define RPC_ASSASSINATED(t)	((t)->tk_flags & RPC_TASK_KILLED)
-#define RPC_IS_RUNNING(t)	((t)->tk_running)
-#define RPC_IS_SLEEPING(t)	((t)->tk_sleeping)
 #define RPC_IS_ACTIVATED(t)	((t)->tk_active)
 #define RPC_DO_CALLBACK(t)	((t)->tk_callback != NULL)
+
+#define RPC_TASK_SLEEPING	0
+#define RPC_TASK_RUNNING	1
+#define RPC_IS_SLEEPING(t)	(test_bit(RPC_TASK_SLEEPING, &(t)->tk_runstate))
+#define RPC_IS_RUNNING(t)	(test_bit(RPC_TASK_RUNNING, &(t)->tk_runstate))
+
+#define rpc_set_running(t)	(set_bit(RPC_TASK_RUNNING, &(t)->tk_runstate))
+#define rpc_clear_running(t)	(clear_bit(RPC_TASK_RUNNING, &(t)->tk_runstate))
+
+#define rpc_set_sleeping(t)	(set_bit(RPC_TASK_SLEEPING, &(t)->tk_runstate))
+
+#define rpc_clear_sleeping(t)	(clear_bit(RPC_TASK_SLEEPING, &(t)->tk_runstate))
 
 /*
  * RPC synchronization objects
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/sunrpc/xprt.h linux.19p18/include/linux/sunrpc/xprt.h
--- linux.vanilla/include/linux/sunrpc/xprt.h	Mon Dec 11 22:13:08 2000
+++ linux.19p18/include/linux/sunrpc/xprt.h	Sun Feb 25 23:41:34 2001
@@ -41,12 +41,14 @@
  * Come Linux 2.3, we'll handle fragments directly.
  */
 #define RPC_MAXCONG		16
-#define RPC_MAXREQS		(RPC_MAXCONG + 1)
+#define RPC_MAXREQS		(RPC_MAXCONG + 2)
 #define RPC_CWNDSCALE		256
 #define RPC_MAXCWND		(RPC_MAXCONG * RPC_CWNDSCALE)
 #define RPC_INITCWND		RPC_CWNDSCALE
 #define RPCXPRT_CONGESTED(xprt) \
 	((xprt)->cong >= (xprt)->cwnd)
+#define RPCXPRT_SUPERCONGESTED(xprt) \
+				((xprt)->cwnd < 2*RPC_CWNDSCALE)
 
 /* Default timeout values */
 #define RPC_MAX_UDP_TIMEOUT	(60*HZ)
@@ -98,7 +100,7 @@
 	struct rpc_task *	rq_task;	/* RPC task data */
 	__u32			rq_xid;		/* request XID */
 	struct rpc_rqst *	rq_next;	/* free list */
-	volatile unsigned char	rq_received : 1;/* receive completed */
+	unsigned char		rq_received : 1;/* receive completed */
 
 	/*
 	 * For authentication (e.g. auth_des)
@@ -138,10 +140,10 @@
 	struct rpc_wait_queue	pending;	/* requests in flight */
 	struct rpc_wait_queue	backlog;	/* waiting for slot */
 	struct rpc_wait_queue	reconn;		/* waiting for reconnect */
+	struct rpc_wait_queue	pingwait;	/* waiting on ping() */
 	struct rpc_rqst *	free;		/* free slots */
 	struct rpc_rqst		slot[RPC_MAXREQS];
-	volatile unsigned char	connected   : 1,/* TCP: connected */
-				write_space : 1;/* TCP: can send */
+	unsigned int		sockstate;	/* Socket state */
 	unsigned char		nocong	    : 1,/* no congestion control */
 				stream      : 1,/* TCP */
 				shutdown    : 1,/* being shut down */
@@ -185,12 +187,14 @@
 					unsigned long);
 
 int			xprt_reserve(struct rpc_task *);
+int			xprt_ping_reserve(struct rpc_task *);
 int			xprt_down_transmit(struct rpc_task *);
 void			xprt_transmit(struct rpc_task *);
 void			xprt_up_transmit(struct rpc_task *);
 void			xprt_receive(struct rpc_task *);
 int			xprt_adjust_timeout(struct rpc_timeout *);
 void			xprt_release(struct rpc_task *);
+void			xprt_ping_release(struct rpc_task *);
 void			xprt_reconnect(struct rpc_task *);
 void			__rpciod_tcp_dispatcher(void);
 
@@ -209,23 +213,30 @@
 		__rpciod_tcp_dispatcher();
 }
 
-static inline
-int xprt_connected(struct rpc_xprt *xprt)
-{
-	return xprt->connected;
-}
+#define	XPRT_WSPACE	0
+#define XPRT_CONNECT	1
+#define XPRT_PING	2
+#define XPRT_NORESPOND	3
+
+#define xprt_wspace(xp)			(test_bit(XPRT_WSPACE, &(xp)->sockstate))
+#define xprt_test_and_set_wspace(xp)	(test_and_set_bit(XPRT_WSPACE, &(xp)->sockstate))
+#define xprt_clear_wspace(xp)		(clear_bit(XPRT_WSPACE, &(xp)->sockstate))
+
+#define xprt_connected(xp)		(!(xp)->stream || test_bit(XPRT_CONNECT, &(xp)->sockstate))
+#define xprt_set_connected(xp)		(set_bit(XPRT_CONNECT, &(xp)->sockstate))
+#define xprt_test_and_set_connected(xp)	(test_and_set_bit(XPRT_CONNECT, &(xp)->sockstate))
+#define xprt_clear_connected(xp)	(clear_bit(XPRT_CONNECT, &(xp)->sockstate))
+
+#define xprt_pinging(xp)		(test_bit(XPRT_PING, &(xp)->sockstate))
+#define xprt_set_pinging(xp)		(set_bit(XPRT_PING, &(xp)->sockstate))
+#define xprt_test_and_set_pinging(xp)	(test_and_set_bit(XPRT_PING, &(xp)->sockstate))
+#define xprt_clear_pinging(xp)		(clear_bit(XPRT_PING, &(xp)->sockstate))
+
+#define xprt_norespond(xp)		(test_bit(XPRT_NORESPOND, &(xp)->sockstate))
+#define xprt_test_and_set_norespond(xp)	(test_and_set_bit(XPRT_NORESPOND, &(xp)->sockstate))
+#define xprt_clear_norespond(xp)	(clear_bit(XPRT_NORESPOND, &(xp)->sockstate))
 
-static inline
-void xprt_set_connected(struct rpc_xprt *xprt)
-{
-	xprt->connected = 1;
-}
 
-static inline
-void xprt_clear_connected(struct rpc_xprt *xprt)
-{
-	xprt->connected = 0;
-}
 
 #endif /* __KERNEL__*/
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/synclink.h linux.19p18/include/linux/synclink.h
--- linux.vanilla/include/linux/synclink.h	Fri Apr 21 12:47:01 2000
+++ linux.19p18/include/linux/synclink.h	Tue Dec 19 02:09:27 2000
@@ -1,9 +1,9 @@
 /*
  * SyncLink Multiprotocol Serial Adapter Driver
  *
- * ==FILEDATE 19990810==
+ * $Id: synclink.h,v 2.2 2000/11/08 17:08:30 paul Exp $
  *
- * Copyright (C) 1998 by Microgate Corporation
+ * Copyright (C) 1998-2000 by Microgate Corporation
  * 
  * Redistribution of this file is permitted under 
  * the terms of the GNU Public License (GPL)
@@ -11,6 +11,7 @@
 
 #ifndef _SYNCLINK_H_
 #define _SYNCLINK_H_
+#define SYNCLINK_H_VERSION 2.2
 
 #define BOOLEAN int
 #define TRUE 1
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/sysctl.h linux.19p18/include/linux/sysctl.h
--- linux.vanilla/include/linux/sysctl.h	Mon Dec 11 22:13:08 2000
+++ linux.19p18/include/linux/sysctl.h	Wed Feb  7 10:03:24 2001
@@ -30,7 +30,7 @@
 
 struct __sysctl_args {
 	int *name;
-	int nlen;
+	unsigned nlen;
 	void *oldval;
 	size_t *oldlenp;
 	void *newval;
@@ -465,7 +465,7 @@
 
 typedef struct ctl_table ctl_table;
 
-typedef int ctl_handler (ctl_table *table, int *name, int nlen,
+typedef int ctl_handler (ctl_table *table, int *name, unsigned nlen,
 			 void *oldval, size_t *oldlenp,
 			 void *newval, size_t newlen, 
 			 void **context);
@@ -484,12 +484,12 @@
 extern int proc_dointvec_jiffies(ctl_table *, int, struct file *,
 				 void *, size_t *);
 
-extern int do_sysctl (int *name, int nlen,
+extern int do_sysctl (int *name, unsigned nlen,
 		      void *oldval, size_t *oldlenp,
 		      void *newval, size_t newlen);
 
 extern int do_sysctl_strategy (ctl_table *table, 
-			       int *name, int nlen,
+			       int *name, unsigned nlen,
 			       void *oldval, size_t *oldlenp,
 			       void *newval, size_t newlen, void ** context);
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/tqueue.h linux.19p18/include/linux/tqueue.h
--- linux.vanilla/include/linux/tqueue.h	Fri Apr 21 23:10:16 2000
+++ linux.19p18/include/linux/tqueue.h	Sun Feb 25 23:13:19 2001
@@ -50,6 +50,7 @@
 typedef struct tq_struct * task_queue;
 
 #define DECLARE_TASK_QUEUE(q)  task_queue q = NULL
+#define TQ_ACTIVE(q)           ((q) != NULL)
 
 extern task_queue tq_timer, tq_immediate, tq_scheduler, tq_disk;
 
@@ -78,19 +79,24 @@
 extern spinlock_t tqueue_lock;
 
 /*
- * queue_task
+ * Queue a task on a tq.  Return non-zero if it was successfully
+ * added.
  */
-extern __inline__ void queue_task(struct tq_struct *bh_pointer,
+extern __inline__ int queue_task(struct tq_struct *bh_pointer,
 			   task_queue *bh_list)
 {
+	int ret = 0;
 	if (!test_and_set_bit(0,&bh_pointer->sync)) {
 		unsigned long flags;
 		spin_lock_irqsave(&tqueue_lock, flags);
 		bh_pointer->next = *bh_list;
 		*bh_list = bh_pointer;
 		spin_unlock_irqrestore(&tqueue_lock, flags);
+		ret = 1;
 	}
+	return ret;
 }
+
 
 /*
  * Call all "bottom halfs" on a given list.
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/usb.h linux.19p18/include/linux/usb.h
--- linux.vanilla/include/linux/usb.h	Mon Dec 11 22:13:08 2000
+++ linux.19p18/include/linux/usb.h	Sat Mar 10 23:22:33 2001
@@ -29,6 +29,7 @@
 /*
  * USB recipients
  */
+#define USB_RECIP_MASK			0x1f
 #define USB_RECIP_DEVICE		0x00
 #define USB_RECIP_INTERFACE		0x01
 #define USB_RECIP_ENDPOINT		0x02
@@ -509,7 +510,7 @@
 	struct list_head inodes;
 };
 
-#define USB_MAXCHILDREN (8)	/* This is arbitrary */
+#define USB_MAXCHILDREN		(16)	/* This is arbitrary */
 
 struct usb_device {
 	int devnum;			/* Device number on USB bus */
@@ -554,6 +555,7 @@
 };
 
 extern struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum);
+extern struct usb_endpoint_descriptor *usb_epnum_to_ep_desc(struct usb_device *dev, unsigned epnum);
 
 extern int usb_register(struct usb_driver *);
 extern void usb_deregister(struct usb_driver *);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/usbdevice_fs.h linux.19p18/include/linux/usbdevice_fs.h
--- linux.vanilla/include/linux/usbdevice_fs.h	Mon Dec 11 22:13:08 2000
+++ linux.19p18/include/linux/usbdevice_fs.h	Sat Dec 30 20:00:54 2000
@@ -80,6 +80,7 @@
 
 #define USBDEVFS_URB_DISABLE_SPD           1
 #define USBDEVFS_URB_ISO_ASAP              2
+#define USBDEVFS_URB_QUEUE_BULK            0x10
 
 #define USBDEVFS_URB_TYPE_ISO		   0
 #define USBDEVFS_URB_TYPE_INTERRUPT	   1
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/wait.h linux.19p18/include/linux/wait.h
--- linux.vanilla/include/linux/wait.h	Mon Dec 11 22:13:08 2000
+++ linux.19p18/include/linux/wait.h	Sun Feb 25 23:13:19 2001
@@ -4,7 +4,8 @@
 #define WNOHANG		0x00000001
 #define WUNTRACED	0x00000002
 
-#define __WCLONE	0x80000000
+#define __WALL		0x40000000	/* Wait on all children, regardless of type */
+#define __WCLONE	0x80000000	/* Wait only on non-SIGCHLD children */ 
 
 #ifdef __KERNEL__
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/watchdog.h linux.19p18/include/linux/watchdog.h
--- linux.vanilla/include/linux/watchdog.h	Fri Apr 21 12:47:01 2000
+++ linux.19p18/include/linux/watchdog.h	Sat Dec 30 19:24:34 2000
@@ -6,14 +6,17 @@
  *
  */
 
+#ifndef _LINUX_WATCHDOG_H
+#define _LINUX_WATCHDOG_H
+
 #include <linux/ioctl.h>
 
 #define	WATCHDOG_IOCTL_BASE	'W'
 
 struct watchdog_info {
-	u32 options;		/* Options the card/driver supports */
-	u32 firmware_version;	/* Firmware version of the card */
-	u8  identity[32];	/* Identity of the board */
+	__u32 options;		/* Options the card/driver supports */
+	__u32 firmware_version;	/* Firmware version of the card */
+	__u8  identity[32];	/* Identity of the board */
 };
 
 #define	WDIOC_GETSUPPORT	_IOR(WATCHDOG_IOCTL_BASE, 0, struct watchdog_info)
@@ -38,3 +41,5 @@
 #define	WDIOS_DISABLECARD	0x0001	/* Turn off the watchdog timer */
 #define	WDIOS_ENABLECARD	0x0002	/* Turn on the watchdog timer */
 #define	WDIOS_TEMPPANIC		0x0004	/* Kernel panic on temperature trip */
+
+#endif  /* ifndef _LINUX_WATCHDOG_H */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/linux/wireless.h linux.19p18/include/linux/wireless.h
--- linux.vanilla/include/linux/wireless.h	Fri Apr 21 23:11:57 2000
+++ linux.19p18/include/linux/wireless.h	Thu Dec 21 22:59:22 2000
@@ -63,7 +63,7 @@
  * (there is some stuff that will be added in the future...)
  * I just plan to increment with each new version.
  */
-#define WIRELESS_EXT	9
+#define WIRELESS_EXT	10
 
 /*
  * Changes :
@@ -104,26 +104,33 @@
  *	- Change encoding to support larger tokens (>64 bits)
  *	- Updated iw_params (disable, flags) and use it for NWID
  *	- Extracted iw_point from iwreq for clarity
+ *
+ * V9 to V10
+ * ---------
+ *	- Add PM capability to range structure
+ *	- Add PM modifier : MAX/MIN/RELATIVE
+ *	- Add encoding option : IW_ENCODE_NOKEY
+ *	- Add TxPower ioctls (work like TxRate)
  */
 
 /* -------------------------- IOCTL LIST -------------------------- */
 
 /* Basic operations */
-#define SIOCSIWNAME	0x8B00		/* Unused ??? */
-#define SIOCGIWNAME	0x8B01		/* get name */
+#define SIOCSIWNAME	0x8B00		/* Unused */
+#define SIOCGIWNAME	0x8B01		/* get name == wireless protocol */
 #define SIOCSIWNWID	0x8B02		/* set network id (the cell) */
 #define SIOCGIWNWID	0x8B03		/* get network id */
-#define SIOCSIWFREQ	0x8B04		/* set channel/frequency */
-#define SIOCGIWFREQ	0x8B05		/* get channel/frequency */
+#define SIOCSIWFREQ	0x8B04		/* set channel/frequency (Hz) */
+#define SIOCGIWFREQ	0x8B05		/* get channel/frequency (Hz) */
 #define SIOCSIWMODE	0x8B06		/* set operation mode */
 #define SIOCGIWMODE	0x8B07		/* get operation mode */
-#define SIOCSIWSENS	0x8B08		/* set sensitivity */
-#define SIOCGIWSENS	0x8B09		/* get sensitivity */
+#define SIOCSIWSENS	0x8B08		/* set sensitivity (dBm) */
+#define SIOCGIWSENS	0x8B09		/* get sensitivity (dBm) */
 
 /* Informative stuff */
-#define SIOCSIWRANGE	0x8B0A		/* Unused ??? */
+#define SIOCSIWRANGE	0x8B0A		/* Unused */
 #define SIOCGIWRANGE	0x8B0B		/* Get range of parameters */
-#define SIOCSIWPRIV	0x8B0C		/* Unused ??? */
+#define SIOCSIWPRIV	0x8B0C		/* Unused */
 #define SIOCGIWPRIV	0x8B0D		/* get private ioctl interface info */
 
 /* Mobile IP support */
@@ -153,6 +160,8 @@
 #define SIOCGIWRTS	0x8B23		/* get RTS/CTS threshold (bytes) */
 #define SIOCSIWFRAG	0x8B24		/* set fragmentation thr (bytes) */
 #define SIOCGIWFRAG	0x8B25		/* get fragmentation thr (bytes) */
+#define SIOCSIWTXPOW	0x8B26		/* set transmit power (dBm) */
+#define SIOCGIWTXPOW	0x8B27		/* get transmit power (dBm) */
 
 /* Encoding stuff (scrambling, hardware security, WEP...) */
 #define SIOCSIWENCODE	0x8B2A		/* set encoding token & mode */
@@ -205,6 +214,9 @@
 /* Maximum bit rates in the range struct */
 #define IW_MAX_BITRATES		8
 
+/* Maximum tx powers in the range struct */
+#define IW_MAX_TXPOWER		8
+
 /* Maximum of address that you may set with SPY */
 #define IW_MAX_SPY		8
 
@@ -232,11 +244,13 @@
 
 /* Flags for encoding (along with the token) */
 #define IW_ENCODE_INDEX		0x00FF	/* Token index (if needed) */
-#define IW_ENCODE_FLAGS		0xF000	/* Flags defined below */
+#define IW_ENCODE_FLAGS		0xFF00	/* Flags defined below */
+#define IW_ENCODE_MODE		0xF000	/* Modes defined below */
 #define IW_ENCODE_DISABLED	0x8000	/* Encoding disabled */
 #define IW_ENCODE_ENABLED	0x0000	/* Encoding enabled */
 #define IW_ENCODE_RESTRICTED	0x4000	/* Refuse non-encoded packets */
 #define IW_ENCODE_OPEN		0x2000	/* Accept non-encoded packets */
+#define IW_ENCODE_NOKEY         0x0800  /* Key is write only, so not present */
 
 /* Power management flags available (along with the value, if any) */
 #define IW_POWER_ON		0x0000	/* No details... */
@@ -249,6 +263,14 @@
 #define IW_POWER_ALL_R		0x0300	/* Receive all messages though PM */
 #define IW_POWER_FORCE_S	0x0400	/* Force PM procedure for sending unicast */
 #define IW_POWER_REPEATER	0x0800	/* Repeat broadcast messages in PM period */
+#define IW_POWER_MODIFIER	0x000F	/* Modify a parameter */
+#define IW_POWER_MIN		0x0001	/* Value is a minimum  */
+#define IW_POWER_MAX		0x0002	/* Value is a maximum */
+#define IW_POWER_RELATIVE	0x0004	/* Value is not in seconds/ms/us */
+
+/* Transmit Power flags available */
+#define IW_TXPOW_DBM		0x0000	/* Value is in dBm */
+#define IW_TXPOW_MWATT		0x0001	/* Value is in mW */
 
 /****************************** TYPES ******************************/
 
@@ -359,6 +381,7 @@
 
 		struct iw_param	sens;		/* signal level threshold */
 		struct iw_param	bitrate;	/* default bit rate */
+		struct iw_param	txpower;	/* default transmit power */
 		struct iw_param	rts;		/* RTS threshold threshold */
 		struct iw_param	frag;		/* Fragmentation threshold */
 		__u32		mode;		/* Operation mode */
@@ -422,15 +445,23 @@
 	__s32		max_frag;	/* Maximal frag threshold */
 
 	/* Power Management duration & timeout */
-	__s32		min_pmd;	/* Minimal PM duration */
-	__s32		max_pmd;	/* Maximal PM duration */
+	__s32		min_pmp;	/* Minimal PM period */
+	__s32		max_pmp;	/* Maximal PM period */
 	__s32		min_pmt;	/* Minimal PM timeout */
 	__s32		max_pmt;	/* Maximal PM timeout */
+	__u16		pmp_flags;	/* How to decode max/min PM period */
+	__u16		pmt_flags;	/* How to decode max/min PM timeout */
+	__u16		pm_capa;	/* What PM options are supported */
 
 	/* Encoder stuff */
 	__u16	encoding_size[IW_MAX_ENCODING_SIZES];	/* Different token sizes */
 	__u8	num_encoding_sizes;	/* Number of entry in the list */
 	__u8	max_encoding_tokens;	/* Max number of tokens */
+
+	/* Transmit power */
+	__u16		txpower_capa;	/* What options are supported */
+	__u8		num_txpower;	/* Number of entries in the list */
+	__s32		txpower[IW_MAX_TXPOWER];	/* list, in bps */
 };
 
 /*
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/math-emu/op-2.h linux.19p18/include/math-emu/op-2.h
--- linux.vanilla/include/math-emu/op-2.h	Fri Apr 21 12:47:01 2000
+++ linux.19p18/include/math-emu/op-2.h	Sun Feb 25 23:19:53 2001
@@ -79,7 +79,7 @@
     else								\
       {									\
 	X##_f0 = (X##_f1 >> ((N) - _FP_W_TYPE_SIZE) |			\
-		  (((X##_f1 << (sz - (N))) | X##_f0) != 0));		\
+		(((X##_f1 << (2*_FP_W_TYPE_SIZE - (N))) | X##_f0) != 0)); \
 	X##_f1 = 0;							\
       }									\
   } while (0)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/net/ip.h linux.19p18/include/net/ip.h
--- linux.vanilla/include/net/ip.h	Mon Dec 11 22:13:08 2000
+++ linux.19p18/include/net/ip.h	Sat Mar  3 22:45:03 2001
@@ -172,7 +172,7 @@
 {
 	u16 check = iph->check;
 	check += __constant_htons(0x0100);
-	iph->check = check + (check>=0xFFFF);
+	iph->check = check + ((check>=0xFFFF) ? 1 : 0);
 	return --iph->ttl;
 }
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/include/net/ip_masq.h linux.19p18/include/net/ip_masq.h
--- linux.vanilla/include/net/ip_masq.h	Fri Apr 21 23:12:18 2000
+++ linux.19p18/include/net/ip_masq.h	Sat Mar  3 22:45:26 2001
@@ -31,6 +31,32 @@
 #define MASQUERADE_EXPIRE_TCP     15*60*HZ
 #define MASQUERADE_EXPIRE_TCP_FIN  2*60*HZ
 #define MASQUERADE_EXPIRE_UDP      5*60*HZ
+
+/*
+ *	Debugging stuff
+ */
+
+extern int ip_masq_get_debug_level(void);
+
+#ifdef CONFIG_IP_MASQ_DEBUG
+#define IP_MASQ_DEBUG(level, msg...) do { \
+	if (level <= ip_masq_get_debug_level()) \
+		printk(KERN_DEBUG "IP_MASQ:" ## msg); \
+	} while (0)
+#else	/* NO DEBUGGING at ALL */
+#define IP_MASQ_DEBUG(level, msg...) do { } while (0)
+#endif
+
+#define IP_MASQ_INFO(msg...) \
+	printk(KERN_INFO "IP_MASQ:" ## msg)
+
+#define IP_MASQ_ERR(msg...) \
+	printk(KERN_ERR "IP_MASQ:" ## msg)
+
+#define IP_MASQ_WARNING(msg...) \
+	printk(KERN_WARNING "IP_MASQ:" ## msg)
+
+
 /* 
  * ICMP can no longer be modified on the fly using an ioctl - this
  * define is the only way to change the timeouts 
@@ -164,7 +190,7 @@
 {
         struct ip_masq_app *next;
 	char *name;		/* name of application proxy */
-        unsigned type;          /* type = proto<<16 | port (host byte order)*/
+        unsigned type;          /* type = flags | proto<<16 | port (host byte order)*/
         int n_attach;
         int (*masq_init_1)      /* ip_masq initializer */
                 (struct ip_masq_app *, struct ip_masq *);
@@ -182,20 +208,60 @@
 extern int ip_masq_app_init(void);
 
 /*
- * 	ip_masq_app object registration functions (port: host byte order)
+ * 	ip_masq_app object registration functions: register_ip_masq_app_type()
+ * 	can be used if ip_masq_app has been previously initialized
+ * 	(port: host byte order)
  */
-extern int register_ip_masq_app(struct ip_masq_app *mapp, unsigned short proto, __u16 port);
+extern int register_ip_masq_app_type(struct ip_masq_app *mapp);
+extern int register_ip_masq_app(struct ip_masq_app *mapp, unsigned proto, __u16 port);
 extern int unregister_ip_masq_app(struct ip_masq_app *mapp);
 
 /*
+ * 	ip_masq_app flags[8bits] (ORed with protocol[8bits] ) 
+ */
+#define IP_MASQ_APP_OUTBOUND	0x01000000	/* dst port matched (in-out) */
+#define IP_MASQ_APP_INBOUND	0x02000000	/* src port matched (in-out) */
+#define IP_MASQ_APP_FWMARK	0x80000000	/* hook by (fwmark & 0xffff) */
+#define IP_MASQ_APP_FLAGS_MASK	0xff000000	/* mask for app flags */
+#define IP_MASQ_APP_PROTO_MASK	0x00ff0000	/* mask for proto value */
+#define IP_MASQ_APP_PORT_MASK	0x0000ffff	/* mask for port value */
+#define IP_MASQ_APP_FWMARK_MASK	0x00ffffff	/* mask for fwmark value (24bits only) */
+
+#define IP_MASQ_APP_TYPE_PP(flags, proto, port) ((flags)|((proto)<<16)|(port))
+#define IP_MASQ_APP_TYPE_FWMARK(flags, fwmark) ((flags)|(fwmark&0x00ffffff))
+#define IP_MASQ_APP_TYPE2PORT(type)        ( (type) & 0xffff )
+#define IP_MASQ_APP_TYPE2PROTO(type)       ( ((type)>>16) & 0x00ff )
+#define IP_MASQ_APP_TYPE2FWMARK(type)       ( (type) & 0x00ffffff )
+#define IP_MASQ_APP_TYPE2FLAGS(type)       ( (type) & 0xff000000 )
+
+/* Init functions for later register_ip_masq_app_type() */
+static __inline__ int ip_masq_app_init_proto_port(struct ip_masq_app* mapp, unsigned flags, unsigned proto, unsigned port) {
+        mapp->type = IP_MASQ_APP_TYPE_PP(flags, proto, port);
+	return 0;
+}
+static __inline__ int ip_masq_app_init_fwmark(struct ip_masq_app* mapp, unsigned flags, __u32 fwmark) {
+	if (fwmark&~(IP_MASQ_APP_FWMARK_MASK)) {
+		IP_MASQ_ERR("ip_masq_app_init_fwmark(): fwmark must be <= %d, sorry (shoot Juanjo)\n", IP_MASQ_APP_FWMARK_MASK);
+		return -EINVAL;
+	}
+        mapp->type = IP_MASQ_APP_TYPE_FWMARK(flags, fwmark);
+	return 0;
+}
+
+/*
  *	get ip_masq_app obj by proto,port(net_byte_order)
  */
-extern struct ip_masq_app * ip_masq_app_get(unsigned short proto, __u16 port);
+extern struct ip_masq_app * ip_masq_app_get_type(unsigned type);
+static __inline__ struct ip_masq_app * ip_masq_app_get(unsigned short proto, __u16 port) {
+        unsigned type = IP_MASQ_APP_TYPE_PP(0, proto, port);
+	return ip_masq_app_get_type(type);
+}
 
 /*
  *	ip_masq TO ip_masq_app (un)binding functions.
  */
 extern struct ip_masq_app * ip_masq_bind_app(struct ip_masq *ms);
+extern struct ip_masq_app * ip_masq_bind_app_fwmark(struct ip_masq *ms, __u32);
 extern int ip_masq_unbind_app(struct ip_masq *ms);
 
 /*
@@ -253,31 +319,6 @@
 /*
  *
  */
-
-/*
- *	Debugging stuff
- */
-
-extern int ip_masq_get_debug_level(void);
-
-#ifdef CONFIG_IP_MASQ_DEBUG
-#define IP_MASQ_DEBUG(level, msg...) do { \
-	if (level <= ip_masq_get_debug_level()) \
-		printk(KERN_DEBUG "IP_MASQ:" ## msg); \
-	} while (0)
-#else	/* NO DEBUGGING at ALL */
-#define IP_MASQ_DEBUG(level, msg...) do { } while (0)
-#endif
-
-#define IP_MASQ_INFO(msg...) \
-	printk(KERN_INFO "IP_MASQ:" ## msg)
-
-#define IP_MASQ_ERR(msg...) \
-	printk(KERN_ERR "IP_MASQ:" ## msg)
-
-#define IP_MASQ_WARNING(msg...) \
-	printk(KERN_WARNING "IP_MASQ:" ## msg)
-
 
 /*
  *	/proc/net entry
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/init/main.c linux.19p18/init/main.c
--- linux.vanilla/init/main.c	Mon Dec 11 22:13:08 2000
+++ linux.19p18/init/main.c	Sun Feb 25 23:13:19 2001
@@ -80,7 +80,6 @@
 extern int bdflush(void *);
 extern int kupdate(void *);
 extern int kswapd(void *);
-extern int kpiod(void *);
 extern void kswapd_setup(void);
 extern unsigned long init_IRQ( unsigned long);
 extern void init_modules(void);
@@ -204,9 +203,6 @@
 #ifdef CONFIG_MDISK
 extern void mdisk_setup(char *str, int *ints);
 #endif
-#ifdef CONFIG_DASD
-extern void dasd_setup(char *str, int *ints);
-#endif
 #ifdef CONFIG_BLK_DEV_XPRAM
 extern void xpram_setup(char *str, int *ints);
 #endif
@@ -216,6 +212,7 @@
 #endif
 extern void floppy_setup(char *str, int *ints);
 extern void st_setup(char *str, int *ints);
+extern void osst_setup(char *str, int *ints);
 extern void st0x_setup(char *str, int *ints);
 extern void advansys_setup(char *str, int *ints);
 extern void tmc8xx_setup(char *str, int *ints);
@@ -624,22 +621,22 @@
        { "dasdh", (DASD_MAJOR << MINORBITS) + (7 << 2) },
        { "dasdi", (DASD_MAJOR << MINORBITS) + (8 << 2) },
        { "dasdj", (DASD_MAJOR << MINORBITS) + (9 << 2) },
-       { "dasdk", (DASD_MAJOR << MINORBITS) + (11 << 2) },
-       { "dasdl", (DASD_MAJOR << MINORBITS) + (12 << 2) },
-       { "dasdm", (DASD_MAJOR << MINORBITS) + (13 << 2) },
-       { "dasdn", (DASD_MAJOR << MINORBITS) + (14 << 2) },
-       { "dasdo", (DASD_MAJOR << MINORBITS) + (15 << 2) },
-       { "dasdp", (DASD_MAJOR << MINORBITS) + (16 << 2) },
-       { "dasdq", (DASD_MAJOR << MINORBITS) + (17 << 2) },
-       { "dasdr", (DASD_MAJOR << MINORBITS) + (18 << 2) },
-       { "dasds", (DASD_MAJOR << MINORBITS) + (19 << 2) },
-       { "dasdt", (DASD_MAJOR << MINORBITS) + (20 << 2) },
-       { "dasdu", (DASD_MAJOR << MINORBITS) + (21 << 2) },
-       { "dasdv", (DASD_MAJOR << MINORBITS) + (22 << 2) },
-       { "dasdw", (DASD_MAJOR << MINORBITS) + (23 << 2) },
-       { "dasdx", (DASD_MAJOR << MINORBITS) + (24 << 2) },
-       { "dasdy", (DASD_MAJOR << MINORBITS) + (25 << 2) },
-       { "dasdz", (DASD_MAJOR << MINORBITS) + (26 << 2) },
+       { "dasdk", (DASD_MAJOR << MINORBITS) + (10 << 2) },
+       { "dasdl", (DASD_MAJOR << MINORBITS) + (11 << 2) },
+       { "dasdm", (DASD_MAJOR << MINORBITS) + (12 << 2) },
+       { "dasdn", (DASD_MAJOR << MINORBITS) + (13 << 2) },
+       { "dasdo", (DASD_MAJOR << MINORBITS) + (14 << 2) },
+       { "dasdp", (DASD_MAJOR << MINORBITS) + (15 << 2) },
+       { "dasdq", (DASD_MAJOR << MINORBITS) + (16 << 2) },
+       { "dasdr", (DASD_MAJOR << MINORBITS) + (17 << 2) },
+       { "dasds", (DASD_MAJOR << MINORBITS) + (18 << 2) },
+       { "dasdt", (DASD_MAJOR << MINORBITS) + (19 << 2) },
+       { "dasdu", (DASD_MAJOR << MINORBITS) + (20 << 2) },
+       { "dasdv", (DASD_MAJOR << MINORBITS) + (21 << 2) },
+       { "dasdw", (DASD_MAJOR << MINORBITS) + (22 << 2) },
+       { "dasdx", (DASD_MAJOR << MINORBITS) + (23 << 2) },
+       { "dasdy", (DASD_MAJOR << MINORBITS) + (24 << 2) },
+       { "dasdz", (DASD_MAJOR << MINORBITS) + (25 << 2) },
 #endif
 #ifdef CONFIG_BLK_DEV_XPRAM
        { "xpram0", (XPRAM_MAJOR << MINORBITS) },
@@ -841,6 +838,9 @@
 #ifdef CONFIG_CHR_DEV_ST
 	{ "st=", st_setup },
 #endif
+#ifdef CONFIG_CHR_DEV_OSST
+	{ "osst=", osst_setup },
+#endif
 #ifdef CONFIG_BUSMOUSE
 	{ "bmouse=", bmouse_setup },
 #endif
@@ -1108,9 +1108,6 @@
 #ifdef CONFIG_MDISK
         { "mdisk=", mdisk_setup },
 #endif
-#ifdef CONFIG_DASD
-        { "dasd=", dasd_setup },
-#endif
 #ifdef CONFIG_BLK_DEV_XPRAM
         { "xpram_parts=", xpram_setup },
 #endif
@@ -1580,7 +1577,6 @@
 	kernel_thread(kupdate, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
 	/* Start the background pageout daemon. */
 	kswapd_setup();
-	kernel_thread(kpiod, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
 	kernel_thread(kswapd, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
 
 #if CONFIG_AP1000
@@ -1598,6 +1594,9 @@
 	if (initrd_start && mount_initrd) root_mountflags &= ~MS_RDONLY;
 	else mount_initrd =0;
 #endif
+
+	/* Start the event daemon thread */
+	start_context_thread();
 
 	/* Set up devices .. */
 	device_setup();
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/ipc/shm.c linux.19p18/ipc/shm.c
--- linux.vanilla/ipc/shm.c	Sun Jun 11 21:44:23 2000
+++ linux.19p18/ipc/shm.c	Tue Feb 13 18:35:46 2001
@@ -337,6 +337,8 @@
 		if (current->euid == shp->u.shm_perm.uid ||
 		    current->euid == shp->u.shm_perm.cuid || 
 		    capable(CAP_SYS_ADMIN)) {
+			/* Do not find it any more */
+			shp->u.shm_perm.key = IPC_PRIVATE;
 			shp->u.shm_perm.mode |= SHM_DEST;
 			if (shp->u.shm_nattch <= 0)
 				killseg (id);
@@ -679,7 +681,7 @@
 }
 
 /*
- * Goes through counter = (shm_rss >> prio) present shm pages.
+ * Goes through counter = (shm_rss / prio) present shm pages.
  */
 static unsigned long swap_id = 0; /* currently being swapped */
 static unsigned long swap_idx = 0; /* next to swap */
@@ -693,7 +695,7 @@
 	int loop = 0;
 	int counter;
 	
-	counter = shm_rss >> prio;
+	counter = shm_rss / prio;
 	if (!counter || !(swap_nr = get_swap_page()))
 		return 0;
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/kernel/Makefile linux.19p18/kernel/Makefile
--- linux.vanilla/kernel/Makefile	Fri Apr 21 12:47:02 2000
+++ linux.19p18/kernel/Makefile	Sun Feb 25 23:13:19 2001
@@ -15,7 +15,7 @@
 	    module.o exit.o itimer.o info.o time.o softirq.o resource.o \
 	    sysctl.o acct.o capability.o
 
-OX_OBJS  += signal.o
+OX_OBJS  += context.o signal.o
 
 ifeq ($(CONFIG_KMOD),y)
 O_OBJS += kmod.o
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/kernel/context.c linux.19p18/kernel/context.c
--- linux.vanilla/kernel/context.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/kernel/context.c	Sun Feb 25 23:13:19 2001
@@ -0,0 +1,157 @@
+/*
+ * linux/kernel/context.c
+ *
+ * Mechanism for running arbitrary tasks in process context
+ *
+ * dwmw2@redhat.com:		Genesis
+ *
+ * andrewm@uow.edu.au:		2.4.0-test12
+ *	- Child reaping
+ *	- Support for tasks which re-add themselves
+ *	- flush_scheduled_tasks.
+ */
+
+#define __KERNEL_SYSCALLS__
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/unistd.h>
+#include <linux/signal.h>
+
+static DECLARE_TASK_QUEUE(tq_context);
+static DECLARE_WAIT_QUEUE_HEAD(context_task_wq);
+static DECLARE_WAIT_QUEUE_HEAD(context_task_done);
+static int keventd_running;
+static struct task_struct *keventd_task;
+
+static int need_keventd(const char *who)
+{
+	if (keventd_running == 0)
+		printk(KERN_ERR "%s(): keventd has not started\n", who);
+	return keventd_running;
+}
+	
+int current_is_keventd(void)
+{
+	int ret = 0;
+	if (need_keventd(__FUNCTION__))
+		ret = (current == keventd_task);
+	return ret;
+}
+
+/**
+ * schedule_task - schedule a function for subsequent execution in process context.
+ * @task: pointer to a &tq_struct which defines the function to be scheduled.
+ *
+ * May be called from interrupt context.  The scheduled function is run at some
+ * time in the near future by the keventd kernel thread.  If it can sleep, it
+ * should be designed to do so for the minimum possible time, as it will be
+ * stalling all other scheduled tasks.
+ *
+ * schedule_task() returns non-zero if the task was successfully scheduled.
+ * If @task is already residing on a task queue then schedule_task() fails
+ * to schedule your task and returns zero.
+ */
+int schedule_task(struct tq_struct *task)
+{
+	int ret;
+	need_keventd(__FUNCTION__);
+	ret = queue_task(task, &tq_context);
+	wake_up(&context_task_wq);
+	return ret;
+}
+
+static int context_thread(void *dummy)
+{
+	struct task_struct *curtask = current;
+	DECLARE_WAITQUEUE(wait, curtask);
+	struct k_sigaction sa;
+
+	daemonize();
+	strcpy(curtask->comm, "keventd");
+	keventd_running = 1;
+	keventd_task = curtask;
+
+	spin_lock_irq(&curtask->sigmask_lock);
+	siginitsetinv(&curtask->blocked, sigmask(SIGCHLD));
+	recalc_sigpending(curtask);
+	spin_unlock_irq(&curtask->sigmask_lock);
+
+	/* Install a handler so SIGCLD is delivered */
+	sa.sa.sa_handler = SIG_IGN;
+	sa.sa.sa_flags = 0;
+	siginitset(&sa.sa.sa_mask, sigmask(SIGCHLD));
+	do_sigaction(SIGCHLD, &sa, (struct k_sigaction *)0);
+
+	/*
+	 * If one of the functions on a task queue re-adds itself
+	 * to the task queue we call schedule() in state TASK_RUNNING
+	 */
+	for (;;) {
+		set_task_state(curtask, TASK_INTERRUPTIBLE);
+		add_wait_queue(&context_task_wq, &wait);
+		if (TQ_ACTIVE(tq_context))
+			set_task_state(curtask, TASK_RUNNING);
+		schedule();
+		remove_wait_queue(&context_task_wq, &wait);
+		run_task_queue(&tq_context);
+		wake_up(&context_task_done);
+		if (signal_pending(curtask)) {
+			while (waitpid(-1, (unsigned int *)0, __WALL|WNOHANG) > 0)
+				;
+			flush_signals(curtask);
+			recalc_sigpending(curtask);
+		}
+	}
+}
+
+/**
+ * flush_scheduled_tasks - ensure that any scheduled tasks have run to completion.
+ *
+ * Forces execution of the schedule_task() queue and blocks until its completion.
+ *
+ * If a kernel subsystem uses schedule_task() and wishes to flush any pending
+ * tasks, it should use this function.  This is typically used in driver shutdown
+ * handlers.
+ *
+ * The caller should hold no spinlocks and should hold no semaphores which could
+ * cause the scheduled tasks to block.
+ */
+static struct tq_struct dummy_task;
+
+void flush_scheduled_tasks(void)
+{
+	int count;
+	DECLARE_WAITQUEUE(wait, current);
+
+	/*
+	 * Do it twice. It's possible, albeit highly unlikely, that
+	 * the caller queued a task immediately before calling us,
+	 * and that the eventd thread was already past the run_task_queue()
+	 * but not yet into wake_up(), so it woke us up before completing
+	 * the caller's queued task or our new dummy task.
+	 */
+	add_wait_queue(&context_task_done, &wait);
+	for (count = 0; count < 2; count++) {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+
+		/* Queue a dummy task to make sure we get kicked */
+		schedule_task(&dummy_task);
+
+		/* Wait for it to complete */
+		schedule();
+	}
+	remove_wait_queue(&context_task_done, &wait);
+}
+	
+int start_context_thread(void)
+{
+	kernel_thread(context_thread, NULL, CLONE_FS | CLONE_FILES);
+	return 0;
+}
+
+EXPORT_SYMBOL(schedule_task);
+EXPORT_SYMBOL(flush_scheduled_tasks);
+
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/kernel/exit.c linux.19p18/kernel/exit.c
--- linux.vanilla/kernel/exit.c	Fri Apr 21 12:47:02 2000
+++ linux.19p18/kernel/exit.c	Sun Feb 25 23:13:19 2001
@@ -437,7 +437,7 @@
 	struct wait_queue wait = { current, NULL };
 	struct task_struct *p;
 
-	if (options & ~(WNOHANG|WUNTRACED|__WCLONE))
+	if (options & ~(WNOHANG|WUNTRACED|__WCLONE|__WALL))
 		return -EINVAL;
 
 	add_wait_queue(&current->wait_chldexit,&wait);
@@ -462,8 +462,13 @@
 			if (p->pgrp != -pid)
 				continue;
 		}
-		/* wait for cloned processes iff the __WCLONE flag is set */
-		if ((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0))
+		/* Wait for all children (clone and not) if __WALL is set;
+		 * otherwise, wait for clone children *only* if __WCLONE is
+		 * set; otherwise, wait for non-clone children *only*.  (Note:
+		 * A "clone" child here is one that reports to its parent
+		 * using a signal other than SIGCHLD.) */
+		if (((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0))
+		    && !(options & __WALL))
 			continue;
 		flag = 1;
 		switch (p->state) {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/kernel/fork.c linux.19p18/kernel/fork.c
--- linux.vanilla/kernel/fork.c	Fri Apr 21 12:47:02 2000
+++ linux.19p18/kernel/fork.c	Sat Dec 16 17:21:48 2000
@@ -665,6 +665,8 @@
 	p->lock_depth = -1;		/* -1 = no lock */
 	p->start_time = jiffies;
 
+	INIT_LIST_HEAD(&p->local_pages);
+
 	retval = -ENOMEM;
 	/* copy all the process information */
 	if (copy_files(clone_flags, p))
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/kernel/sched.c linux.19p18/kernel/sched.c
--- linux.vanilla/kernel/sched.c	Mon Dec 11 22:13:08 2000
+++ linux.19p18/kernel/sched.c	Wed Dec 13 22:21:20 2000
@@ -890,8 +890,9 @@
  */
 void __wake_up(struct wait_queue **q, unsigned int mode)
 {
-	struct task_struct *p;
+	struct task_struct *p, *best_exclusive;
 	struct wait_queue *head, *next;
+	unsigned int do_exclusive;
 
         if (!q)
 		goto out;
@@ -906,22 +907,23 @@
 	if (!next)
 		goto out_unlock;
 
+	best_exclusive = 0;
+	do_exclusive = mode & TASK_EXCLUSIVE;
 	while (next != head) {
 		p = next->task;
 		next = next->next;
 		if (p->state & mode) {
-			/*
-			 * We can drop the read-lock early if this
-			 * is the only/last process.
-			 */
-			if (next == head) {
-				read_unlock(&waitqueue_lock);
+			if (do_exclusive && p->task_exclusive) {
+				if (best_exclusive == NULL)
+					best_exclusive = p;
+			}
+			else {
 				wake_up_process(p);
-				goto out;
 			}
-			wake_up_process(p);
 		}
 	}
+	if (best_exclusive)
+		wake_up_process(best_exclusive);
 out_unlock:
 	read_unlock(&waitqueue_lock);
 out:
@@ -1943,7 +1945,7 @@
 		delay=(t.tv_nsec + 999) / 1000;
 		
 		if(delay>10000)
-			mdelay(delay);
+			mdelay((delay+999)/1000);
 		else
 			udelay(delay);
 		return 0;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/kernel/signal.c linux.19p18/kernel/signal.c
--- linux.vanilla/kernel/signal.c	Fri Apr 21 12:47:02 2000
+++ linux.19p18/kernel/signal.c	Tue Feb 27 21:59:16 2001
@@ -820,7 +820,7 @@
 
 	/* Not even root can pretend to send signals from the kernel.
 	   Nor can they impersonate a kill(), which adds source info.  */
-	if (info.si_code >= 0)
+	if (SI_FROMKERNEL(&info))
 		return -EPERM;
 	info.si_signo = sig;
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/kernel/sys.c linux.19p18/kernel/sys.c
--- linux.vanilla/kernel/sys.c	Mon Dec 11 22:13:08 2000
+++ linux.19p18/kernel/sys.c	Tue Feb 27 16:38:03 2001
@@ -381,14 +381,19 @@
 		else
 			return -EPERM;
 	}
+
+	lock_kernel();
+
 	if (euid != (uid_t) -1) {
 		if ((old_ruid == euid) ||
 		    (current->euid == euid) ||
 		    (current->suid == euid) ||
 		    capable(CAP_SETUID))
 			current->fsuid = current->euid = euid;
-		else
+		else {
+			unlock_kernel();
 			return -EPERM;
+		}
 	}
 	if (ruid != (uid_t) -1 ||
 	    (euid != (uid_t) -1 && euid != old_ruid))
@@ -407,6 +412,8 @@
 		current->uid = new_ruid;
 		alloc_uid(current);
 	}
+
+	unlock_kernel();
 	
 	if (!issecure(SECURE_NO_SETUID_FIXUP)) {
 		cap_emulate_setxuid(old_ruid, old_euid, old_suid);
@@ -433,14 +440,18 @@
 	int old_euid = current->euid;
 	int old_ruid, old_suid, new_ruid;
 
+	lock_kernel();
+
 	old_ruid = new_ruid = current->uid;
 	old_suid = current->suid;
 	if (capable(CAP_SETUID))
 		new_ruid = current->euid = current->suid = current->fsuid = uid;
 	else if ((uid == current->uid) || (uid == current->suid))
 		current->fsuid = current->euid = uid;
-	else
+	else {
+		unlock_kernel();
 		return -EPERM;
+	}
 
 	if (current->euid != old_euid)
 		current->dumpable = 0;
@@ -452,6 +463,8 @@
 		alloc_uid(current);
 	}
 
+	unlock_kernel();
+
 	if (!issecure(SECURE_NO_SETUID_FIXUP)) {
 		cap_emulate_setxuid(old_ruid, old_euid, old_suid);
 	}
@@ -481,6 +494,9 @@
 		    (suid != current->euid) && (suid != current->suid))
 			return -EPERM;
 	}
+
+	lock_kernel();
+
 	if (ruid != (uid_t) -1) {
 		/* See above commentary about NPROC rlimit issues here. */
 		free_uid(current);
@@ -496,6 +512,8 @@
 	if (suid != (uid_t) -1)
 		current->suid = suid;
 
+	unlock_kernel();
+
 	if (!issecure(SECURE_NO_SETUID_FIXUP)) {
 		cap_emulate_setxuid(old_ruid, old_euid, old_suid);
 	}
@@ -565,6 +583,8 @@
 {
 	int old_fsuid;
 
+	lock_kernel();
+
 	old_fsuid = current->fsuid;
 	if (uid == current->uid || uid == current->euid ||
 	    uid == current->suid || uid == current->fsuid || 
@@ -572,6 +592,8 @@
 		current->fsuid = uid;
 	if (current->fsuid != old_fsuid)
 		current->dumpable = 0;
+
+	unlock_kernel();
 
 	/* We emulate fsuid by essentially doing a scaled-down version
 	 * of what we did in setresuid and friends. However, we only
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/kernel/sysctl.c linux.19p18/kernel/sysctl.c
--- linux.vanilla/kernel/sysctl.c	Mon Dec 11 22:13:08 2000
+++ linux.19p18/kernel/sysctl.c	Wed Feb  7 10:03:24 2001
@@ -77,7 +77,7 @@
 
 extern int pgt_cache_water[];
 
-static int parse_table(int *, int, void *, size_t *, void *, size_t,
+static int parse_table(int *, unsigned, void *, size_t *, void *, size_t,
 		       ctl_table *, void **);
 static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
 		  void *buffer, size_t *lenp);
@@ -286,9 +286,9 @@
 	 0444, NULL, &proc_dointvec},
 	{FS_MAXINODE, "inode-max", &max_inodes, sizeof(int),
 	 0644, NULL, &proc_dointvec},
-	{FS_NRFILE, "file-nr", &nr_files, 3*sizeof(int),
+	{FS_NRFILE, "file-nr", &files_stat, 3*sizeof(int),
 	 0444, NULL, &proc_dointvec},
-	{FS_MAXFILE, "file-max", &max_files, sizeof(int),
+	{FS_MAXFILE, "file-max", &files_stat.max_files, sizeof(int),
 	 0644, NULL, &proc_dointvec},
 	{FS_NRSUPER, "super-nr", &nr_super_blocks, sizeof(int),
 	 0444, NULL, &proc_dointvec},
@@ -320,7 +320,7 @@
 }
 
 
-int do_sysctl (int *name, int nlen,
+int do_sysctl (int *name, unsigned nlen,
 	       void *oldval, size_t *oldlenp,
 	       void *newval, size_t newlen)
 {
@@ -330,10 +330,12 @@
 	
 	if (nlen == 0 || nlen >= CTL_MAXNAME)
 		return -ENOTDIR;
-	
-	if (oldval) 
-	{
-		int old_len;
+
+	if ((ssize_t)newlen < 0)
+		return -EINVAL;	
+
+	if (oldval) {
+		size_t old_len;
 		if (!oldlenp)
 			return -EFAULT;
 		if(get_user(old_len, oldlenp))
@@ -387,7 +389,7 @@
 	return test_perm(table->mode, op);
 }
 
-static int parse_table(int *name, int nlen,
+static int parse_table(int *name, unsigned nlen,
 		       void *oldval, size_t *oldlenp,
 		       void *newval, size_t newlen,
 		       ctl_table *table, void **context)
@@ -430,11 +432,12 @@
 
 /* Perform the actual read/write of a sysctl table entry. */
 int do_sysctl_strategy (ctl_table *table, 
-			int *name, int nlen,
+			int *name, unsigned nlen,
 			void *oldval, size_t *oldlenp,
 			void *newval, size_t newlen, void **context)
 {
-	int op = 0, rc, len;
+	int op = 0, rc;
+	size_t len;
 
 	if (oldval)
 		op |= 004;
@@ -642,7 +645,7 @@
 int proc_dostring(ctl_table *table, int write, struct file *filp,
 		  void *buffer, size_t *lenp)
 {
-	int len;
+	size_t len;
 	char *p, c;
 	
 	if (!table->data || !table->maxlen || !*lenp ||
@@ -710,7 +713,8 @@
 static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
 		  void *buffer, size_t *lenp, int conv, int op)
 {
-	int *i, vleft, first=1, len, left, neg, val;
+	int *i, neg, val;
+	size_t len, left, vleft, first=1;
 	#define TMPBUFLEN 20
 	char buf[TMPBUFLEN], *p;
 	
@@ -832,7 +836,8 @@
 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
 		  void *buffer, size_t *lenp)
 {
-	int *i, *min, *max, vleft, first=1, len, left, neg, val;
+	int *i, *min, *max, neg, val;
+	size_t len, left, vleft, first=1;
 	#define TMPBUFLEN 20
 	char buf[TMPBUFLEN], *p;
 	
@@ -974,11 +979,12 @@
  */
 
 /* The generic string strategy routine: */
-int sysctl_string(ctl_table *table, int *name, int nlen,
+int sysctl_string(ctl_table *table, int *name, unsigned nlen,
 		  void *oldval, size_t *oldlenp,
 		  void *newval, size_t newlen, void **context)
 {
-	int l, len;
+	unsigned l;
+	size_t len;
 	
 	if (!table->data || !table->maxlen) 
 		return -ENOTDIR;
@@ -1017,11 +1023,12 @@
  * are between the minimum and maximum values given in the arrays
  * table->extra1 and table->extra2, respectively.
  */
-int sysctl_intvec(ctl_table *table, int *name, int nlen,
+int sysctl_intvec(ctl_table *table, int *name, unsigned nlen,
 		void *oldval, size_t *oldlenp,
 		void *newval, size_t newlen, void **context)
 {
-	int i, length, *vec, *min, *max;
+	int *vec, *min, *max;
+	size_t i, length;
 
 	if (newval && newlen) {
 		if (newlen % sizeof(int) != 0)
@@ -1051,7 +1058,7 @@
 }
 
 /* Strategy function to convert jiffies to seconds */ 
-int sysctl_jiffies(ctl_table *table, int *name, int nlen,
+int sysctl_jiffies(ctl_table *table, int *name, unsigned nlen,
 		void *oldval, size_t *oldlenp,
 		void *newval, size_t newlen, void **context)
 {
@@ -1159,21 +1166,21 @@
 	return -ENOSYS;
 }
 
-int sysctl_string(ctl_table *table, int *name, int nlen,
+int sysctl_string(ctl_table *table, int *name, unsigned nlen,
 		  void *oldval, size_t *oldlenp,
 		  void *newval, size_t newlen, void **context)
 {
 	return -ENOSYS;
 }
 
-int sysctl_intvec(ctl_table *table, int *name, int nlen,
+int sysctl_intvec(ctl_table *table, int *name, unsigned nlen,
 		void *oldval, size_t *oldlenp,
 		void *newval, size_t newlen, void **context)
 {
 	return -ENOSYS;
 }
 
-int sysctl_jiffies(ctl_table *table, int *name, int nlen,
+int sysctl_jiffies(ctl_table *table, int *name, unsigned nlen,
 		void *oldval, size_t *oldlenp,
 		void *newval, size_t newlen, void **context)
 {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/mm/filemap.c linux.19p18/mm/filemap.c
--- linux.vanilla/mm/filemap.c	Mon Dec 11 22:13:08 2000
+++ linux.19p18/mm/filemap.c	Sat Dec 16 17:21:48 2000
@@ -19,7 +19,6 @@
 #include <linux/blkdev.h>
 #include <linux/file.h>
 #include <linux/swapctl.h>
-#include <linux/slab.h>
 #include <linux/init.h>
 
 #include <asm/pgtable.h>
@@ -36,25 +35,6 @@
 unsigned int page_hash_bits, page_hash_mask;
 struct page **page_hash_table;
 
-/* 
- * Define a request structure for outstanding page write requests
- * to the background page io daemon
- */
-
-struct pio_request 
-{
-	struct pio_request *	next;
-	struct file *		file;
-	unsigned long		offset;
-	unsigned long		page;
-};
-static struct pio_request *pio_first = NULL, **pio_last = &pio_first;
-static kmem_cache_t *pio_request_cache;
-static struct wait_queue *pio_wait = NULL;
-
-static inline void 
-make_pio_request(struct file *, unsigned long, unsigned long);
-
 static inline int sync_page(struct page *page)
 {
 	struct inode *inode = page->inode;
@@ -150,16 +130,21 @@
 	unsigned long limit = num_physpages;
 	struct page * page;
 	int count;
-	int nr_dirty = 0;
-	
+
 	/* Make sure we scan all pages twice at priority 0. */
-	count = (limit << 1) >> priority;
+	count = limit / priority;
 
  refresh_clock:
 	page = mem_map + clock;
 	do {
 		int referenced;
 
+		if (current->need_resched) {
+			current->state = TASK_RUNNING;
+			schedule();
+			goto refresh_clock;
+		}
+		
 		/* This works even in the presence of PageSkip because
 		 * the first two entries at the beginning of a hole will
 		 * be marked, not just the first.
@@ -176,6 +161,8 @@
 			clock = page - mem_map;
 		}
 		
+		count--;
+
 		/* We can't free pages unless there's just one user */
 		if (atomic_read(&page->count) != 1)
 			continue;
@@ -185,8 +172,10 @@
 		if (PageLocked(page))
 			continue;
 
-		if ((gfp_mask & __GFP_DMA) && !PageDMA(page))
+		if ((gfp_mask & __GFP_DMA) && !PageDMA(page)) {
+			count++;
 			continue;
+		}
 
 		/*
 		 * Is it a page swap page? If so, we want to
@@ -205,14 +194,6 @@
 
 		/* Is it a buffer page? */
 		if (page->buffers) {
-			/*
-			 * Wait for async IO to complete
-			 * at each 64 buffers
-			 */ 
-
-			int wait = ((gfp_mask & __GFP_IO) 
-				&& (!(nr_dirty++ % 64)));
-
 			if (buffer_under_min())
 				continue;
 			/*
@@ -220,10 +201,8 @@
 			 * throttling.
 			 */
 
-			if (!try_to_free_buffers(page, wait)) { 
-				if(--count < 0) break;
+			if (!try_to_free_buffers(page, gfp_mask))
 				goto refresh_clock;
-			}
 			return 1;
 		}
 
@@ -234,8 +213,7 @@
 			remove_inode_page(page);
 			return 1;
 		}
-
-	} while (--count > 0);
+	} while (count > 0);
 	return 0;
 }
 
@@ -302,7 +280,7 @@
 	struct page **hash)
 {
 	atomic_inc(&page->count);
-	page->flags = (page->flags & ~((1 << PG_uptodate) | (1 << PG_error))) | (1 << PG_referenced);
+	page->flags = page->flags & ~((1 << PG_uptodate) | (1 << PG_error) | (1 << PG_referenced));
 	page->offset = offset;
 	add_page_to_inode_queue(inode, page);
 	__add_page_to_hash_queue(page, hash);
@@ -881,12 +859,12 @@
 
 	if (size > count)
 		size = count;
-	down(&inode->i_sem);
+	fs_down(&inode->i_sem);
 	old_fs = get_fs();
 	set_fs(KERNEL_DS);
 	written = file->f_op->write(file, area, size, &file->f_pos);
 	set_fs(old_fs);
-	up(&inode->i_sem);
+	fs_up(&inode->i_sem);
 	if (written < 0) {
 		desc->error = written;
 		written = 0;
@@ -1163,8 +1141,7 @@
 
 static int filemap_write_page(struct vm_area_struct * vma,
 			      unsigned long offset,
-			      unsigned long page,
-			      int wait)
+			      unsigned long page)
 {
 	int result;
 	struct file * file;
@@ -1182,20 +1159,9 @@
 	 * and file could be released ... increment the count to be safe.
 	 */
 	file->f_count++;
-
-	/* 
-	 * If this is a swapping operation rather than msync(), then
-	 * leave the actual IO, and the restoration of the file count,
-	 * to the kpiod thread.  Just queue the request for now.
-	 */
-	if (!wait) {
-		make_pio_request(file, offset, page);
-		return 0;
-	}
-	
-	down(&inode->i_sem);
+	fs_down(&inode->i_sem);
 	result = do_write_page(inode, file, (const char *) page, offset);
-	up(&inode->i_sem);
+	fs_up(&inode->i_sem);
 	fput(file);
 	return result;
 }
@@ -1208,7 +1174,7 @@
  */
 int filemap_swapout(struct vm_area_struct * vma, struct page * page)
 {
-	return filemap_write_page(vma, page->offset, page_address(page), 0);
+	return filemap_write_page(vma, page->offset, page_address(page));
 }
 
 static inline int filemap_sync_pte(pte_t * ptep, struct vm_area_struct *vma,
@@ -1245,7 +1211,7 @@
 			return 0;
 		}
 	}
-	error = filemap_write_page(vma, address - vma->vm_start + vma->vm_offset, page, 1);
+	error = filemap_write_page(vma, address - vma->vm_start + vma->vm_offset, page);
 	page_cache_free(page);
 	return error;
 }
@@ -1417,9 +1383,9 @@
 			if (file) {
 				struct dentry * dentry = file->f_dentry;
 				struct inode * inode = dentry->d_inode;
-				down(&inode->i_sem);
+				fs_down(&inode->i_sem);
 				error = file_fsync(file, dentry);
-				up(&inode->i_sem);
+				fs_up(&inode->i_sem);
 			}
 		}
 		return error;
@@ -1746,130 +1712,6 @@
 	clear_bit(PG_locked, &page->flags);
 	wake_up(&page->wait);
 	page_cache_release(page);
-}
-
-
-/* Add request for page IO to the queue */
-
-static inline void put_pio_request(struct pio_request *p)
-{
-	*pio_last = p;
-	p->next = NULL;
-	pio_last = &p->next;
-}
-
-/* Take the first page IO request off the queue */
-
-static inline struct pio_request * get_pio_request(void)
-{
-	struct pio_request * p = pio_first;
-	pio_first = p->next;
-	if (!pio_first)
-		pio_last = &pio_first;
-	return p;
-}
-
-/* Make a new page IO request and queue it to the kpiod thread */
-
-static inline void make_pio_request(struct file *file,
-				    unsigned long offset,
-				    unsigned long page)
-{
-	struct pio_request *p;
-
-	atomic_inc(&page_cache_entry(page)->count);
-
-	/* 
-	 * We need to allocate without causing any recursive IO in the
-	 * current thread's context.  We might currently be swapping out
-	 * as a result of an allocation made while holding a critical
-	 * filesystem lock.  To avoid deadlock, we *MUST* not reenter
-	 * the filesystem in this thread.
-	 *
-	 * We can wait for kswapd to free memory, or we can try to free
-	 * pages without actually performing further IO, without fear of
-	 * deadlock.  --sct
-	 */
-
-	while ((p = kmem_cache_alloc(pio_request_cache, GFP_BUFFER)) == NULL) {
-		if (try_to_free_pages(__GFP_WAIT))
-			continue;
-		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout(HZ/10);
-	}
-	
-	p->file   = file;
-	p->offset = offset;
-	p->page   = page;
-
-	put_pio_request(p);
-	wake_up(&pio_wait);
-}
-
-
-/*
- * This is the only thread which is allowed to write out filemap pages
- * while swapping.
- * 
- * To avoid deadlock, it is important that we never reenter this thread.
- * Although recursive memory allocations within this thread may result
- * in more page swapping, that swapping will always be done by queuing
- * another IO request to the same thread: we will never actually start
- * that IO request until we have finished with the current one, and so
- * we will not deadlock.  
- */
-
-int kpiod(void * unused)
-{
-	struct task_struct *tsk = current;
-	struct wait_queue wait = { tsk, };
-	struct inode * inode;
-	struct dentry * dentry;
-	struct pio_request * p;
-	
-	tsk->session = 1;
-	tsk->pgrp = 1;
-	strcpy(tsk->comm, "kpiod");
-	sigfillset(&tsk->blocked);
-	init_waitqueue(&pio_wait);
-	/*
-	 * Mark this task as a memory allocator - we don't want to get caught
-	 * up in the regular mm freeing frenzy if we have to allocate memory
-	 * in order to write stuff out.
-	 */
-	tsk->flags |= PF_MEMALLOC;
-
-	lock_kernel();
-	
-	pio_request_cache = kmem_cache_create("pio_request", 
-					      sizeof(struct pio_request),
-					      0, SLAB_HWCACHE_ALIGN, 
-					      NULL, NULL);
-	if (!pio_request_cache)
-		panic ("Could not create pio_request slab cache");
-
-	while (1) {
-		tsk->state = TASK_INTERRUPTIBLE;
-		add_wait_queue(&pio_wait, &wait);
-		if (!pio_first)
-			schedule();
-		remove_wait_queue(&pio_wait, &wait);
-		tsk->state = TASK_RUNNING;
-
-		while (pio_first) {
-			p = get_pio_request();
-			dentry = p->file->f_dentry;
-			inode = dentry->d_inode;
-			
-			down(&inode->i_sem);
-			do_write_page(inode, p->file,
-				      (const char *) p->page, p->offset);
-			up(&inode->i_sem);
-			fput(p->file);
-			page_cache_free(p->page);
-			kmem_cache_free(pio_request_cache, p);
-		}
-	}
 }
 
 void __init page_cache_init(unsigned long memory_size)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/mm/memory.c linux.19p18/mm/memory.c
--- linux.vanilla/mm/memory.c	Mon Dec 11 22:13:08 2000
+++ linux.19p18/mm/memory.c	Thu Feb 15 16:15:17 2001
@@ -935,6 +935,7 @@
 	pte_t * pte;
 	int ret;
 
+	current->state = TASK_RUNNING;
 	pgd = pgd_offset(vma->vm_mm, address);
 	pmd = pmd_alloc(pgd, address);
 	if (!pmd)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/mm/page_alloc.c linux.19p18/mm/page_alloc.c
--- linux.vanilla/mm/page_alloc.c	Sat Sep  9 18:42:51 2000
+++ linux.19p18/mm/page_alloc.c	Sat Dec 16 17:21:48 2000
@@ -93,34 +93,69 @@
  */
 spinlock_t page_alloc_lock = SPIN_LOCK_UNLOCKED;
 
+#define list(x) (mem_map+(x))
+#define __free_pages_ok(map_nr, mask, area, index)		\
+	nr_free_pages -= (mask);				\
+	while ((mask) + (1 << (NR_MEM_LISTS-1))) {		\
+		if (!test_and_change_bit((index), (area)->map))	\
+			break;					\
+		(area)->count--;				\
+		remove_mem_queue(list((map_nr) ^ -(mask)));	\
+		(mask) <<= 1;					\
+		(area)++;					\
+		(index) >>= 1;					\
+		(map_nr) &= (mask);				\
+	}							\
+	add_mem_queue(area, list(map_nr));
+
+static void free_local_pages(struct page * page) {
+	unsigned long order = page->offset;
+	unsigned int type = PageDMA(page) ? 1 : 0;
+	struct free_area_struct *area;
+	unsigned long map_nr = page - mem_map;
+	unsigned long mask = (~0UL) << order;
+	unsigned long index = map_nr >> (1 + order);
+
+	area = free_area[type] + order;
+	__free_pages_ok(map_nr, mask, area, index);
+}
+
 static inline void free_pages_ok(unsigned long map_nr, unsigned long order, unsigned type)
 {
-	struct free_area_struct *area = free_area[type] + order;
-	unsigned long index = map_nr >> (1 + order);
-	unsigned long mask = (~0UL) << order;
+	struct free_area_struct *area;
+	unsigned long index;
+	unsigned long mask;
 	unsigned long flags;
+	struct page * page;
 
-	spin_lock_irqsave(&page_alloc_lock, flags);
-
-#define list(x) (mem_map+(x))
+	if (current->flags & PF_FREE_PAGES)
+		goto local_freelist;
+ back_local_freelist:
 
+	index = map_nr >> (1 + order);
+	mask = (~0UL) << order;
 	map_nr &= mask;
-	nr_free_pages -= mask;
-	while (mask + (1 << (NR_MEM_LISTS-1))) {
-		if (!test_and_change_bit(index, area->map))
-			break;
-		area->count--;
-		remove_mem_queue(list(map_nr ^ -mask));
-		mask <<= 1;
-		area++;
-		index >>= 1;
-		map_nr &= mask;
-	}
-	add_mem_queue(area, list(map_nr));
-
-#undef list
 
+	spin_lock_irqsave(&page_alloc_lock, flags);
+	area = free_area[type] + order;
+	__free_pages_ok(map_nr, mask, area, index);
 	spin_unlock_irqrestore(&page_alloc_lock, flags);
+	return;
+
+ local_freelist:
+	/*
+	 * This is a little subtle: if the allocation order
+	 * wanted is major than zero we'd better take all the pages
+	 * local since we must deal with fragmentation too and we
+	 * can't rely on the nr_local_pages information.
+	 */
+	if (current->nr_local_pages && !current->allocation_order)
+		goto back_local_freelist;
+
+	page = mem_map + map_nr;
+	list_add((struct list_head *) page, &current->local_pages);
+	page->offset = order;
+	current->nr_local_pages++;
 }
 
 void __free_pages(struct page *page, unsigned long order)
@@ -179,13 +214,32 @@
 	atomic_set(&map->count, 1); \
 } while (0)
 
+static void refile_local_pages(void)
+{
+	if (current->nr_local_pages) {
+		struct page * page;
+		struct list_head * entry;
+		int nr_pages = current->nr_local_pages;
+
+		while ((entry = current->local_pages.next) != &current->local_pages) {
+			list_del(entry);
+			page = (struct page *) entry;
+			free_local_pages(page);
+			if (!nr_pages--)
+				panic("__get_free_pages local_pages list corrupted I");
+		}
+		if (nr_pages)
+			panic("__get_free_pages local_pages list corrupted II");
+		current->nr_local_pages = 0;
+	}
+}
+
 unsigned long __get_free_pages(int gfp_mask, unsigned long order)
 {
 	unsigned long flags;
-	static atomic_t free_before_allocate = ATOMIC_INIT(0);
 
 	if (order >= NR_MEM_LISTS)
-		goto nopage;
+		goto out;
 
 #ifdef ATOMIC_MEMORY_DEBUGGING
 	if ((gfp_mask & __GFP_WAIT) && in_interrupt()) {
@@ -194,26 +248,24 @@
 			printk("gfp called nonatomically from interrupt %p\n",
 				__builtin_return_address(0));
 		}
-		goto nopage;
+		goto out;
 	}
 #endif
 
 	/*
+	 * Acquire lock before reading nr_free_pages to make sure it
+	 * won't change from under us.
+	 */
+	spin_lock_irqsave(&page_alloc_lock, flags);
+
+	/*
 	 * If this is a recursive call, we'd better
 	 * do our best to just allocate things without
 	 * further thought.
 	 */
 	if (!(current->flags & PF_MEMALLOC)) {
-		int freed;
 		extern struct wait_queue * kswapd_wait;
 
-		/* Somebody needs to free pages so we free some of our own. */
-		if (atomic_read(&free_before_allocate)) {
-			current->flags |= PF_MEMALLOC;
-			try_to_free_pages(gfp_mask);
-			current->flags &= ~PF_MEMALLOC;
-		}
-
 		if (nr_free_pages > freepages.low)
 			goto ok_to_allocate;
 
@@ -223,35 +275,44 @@
 		/* Do we have to block or can we proceed? */
 		if (nr_free_pages > freepages.min)
 			goto ok_to_allocate;
+		if (gfp_mask & __GFP_WAIT) {
+			int freed;
+			/*
+			 * If the task is ok to sleep it's fine also
+			 * if we release irq here.
+			 */
+			spin_unlock_irq(&page_alloc_lock);
+
+			current->flags |= PF_MEMALLOC|PF_FREE_PAGES;
+			current->allocation_order = order;
+			freed = try_to_free_pages(gfp_mask);
+			current->flags &= ~(PF_MEMALLOC|PF_FREE_PAGES);
+
+			spin_lock_irq(&page_alloc_lock);
+			refile_local_pages();
+
+			/*
+			 * Re-check we're still low on memory after we blocked
+			 * for some time. Somebody may have released lots of
+			 * memory from under us while we was trying to free
+			 * the pages. We check against pages_high to be sure
+			 * to succeed only if lots of memory is been released.
+			 */
+			if (nr_free_pages > freepages.high)
+				goto ok_to_allocate;
 
-		current->flags |= PF_MEMALLOC;
-		atomic_inc(&free_before_allocate);
-		freed = try_to_free_pages(gfp_mask);
-		atomic_dec(&free_before_allocate);
-		current->flags &= ~PF_MEMALLOC;
-
-		/*
-		 * Re-check we're still low on memory after we blocked
-		 * for some time. Somebody may have released lots of
-		 * memory from under us while we was trying to free
-		 * the pages. We check against pages_high to be sure
-		 * to succeed only if lots of memory is been released.
-		 */
-		if (nr_free_pages > freepages.high)
-			goto ok_to_allocate;
-
-		if (!freed && !(gfp_mask & (__GFP_MED | __GFP_HIGH)))
-			goto nopage;
+			if (!freed && !(gfp_mask & (__GFP_MED | __GFP_HIGH)))
+				goto nopage;
+		}
 	}
 ok_to_allocate:
-	spin_lock_irqsave(&page_alloc_lock, flags);
 	/* if it's not a dma request, try non-dma first */
 	if (!(gfp_mask & __GFP_DMA))
 		RMQUEUE_TYPE(order, 0);
 	RMQUEUE_TYPE(order, 1);
+ nopage:
 	spin_unlock_irqrestore(&page_alloc_lock, flags);
-
-nopage:
+ out:
 	return 0;
 }
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/mm/swap_state.c linux.19p18/mm/swap_state.c
--- linux.vanilla/mm/swap_state.c	Fri Apr 21 12:47:02 2000
+++ linux.19p18/mm/swap_state.c	Sat Dec 16 17:21:48 2000
@@ -63,6 +63,7 @@
 		return 0;
 	}
 	atomic_inc(&page->count);
+	page->flags = page->flags & ~((1 << PG_uptodate) | (1 << PG_error) | (1 << PG_referenced));
 	page->inode = &swapper_inode;
 	page->offset = entry;
 	add_page_to_hash_queue(page, &swapper_inode, entry);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/mm/vmscan.c linux.19p18/mm/vmscan.c
--- linux.vanilla/mm/vmscan.c	Sat Sep  9 18:42:51 2000
+++ linux.19p18/mm/vmscan.c	Sat Dec 16 17:21:48 2000
@@ -96,6 +96,9 @@
 	 * some real work in the future in "shrink_mmap()".
 	 */
 	if (!pte_dirty(pte)) {
+		if (page_map->inode && pgcache_under_min())
+			/* unmapping this page would be useless */
+			return 0;
 		flush_cache_page(vma, address);
 		pte_clear(page_table);
 		goto drop_pte;
@@ -106,7 +109,7 @@
 	 * we cannot do I/O! Avoid recursing on FS
 	 * locks etc.
 	 */
-	if (!(gfp_mask & __GFP_IO))
+	if (!(gfp_mask & __GFP_IO) || current->fs_locks)
 		return 0;
 
 	/*
@@ -208,6 +211,8 @@
 		result = try_to_swap_out(tsk, vma, address, pte, gfp_mask);
 		if (result)
 			return result;
+		if (current->need_resched)
+			return 2;
 		address += PAGE_SIZE;
 		pte++;
 	} while (address < end);
@@ -327,7 +332,7 @@
 	 * Think of swap_cnt as a "shadow rss" - it tells us which process
 	 * we want to page out (always try largest first).
 	 */
-	counter = nr_tasks / (priority+1);
+	counter = nr_tasks / priority;
 	if (counter < 1)
 		counter = 1;
 
@@ -361,8 +366,13 @@
 			goto out;
 		}
 
-		if (swap_out_process(pbest, gfp_mask))
+		switch (swap_out_process(pbest, gfp_mask)) {
+		case 1:
 			return 1;
+		case 2:
+			current->state = TASK_RUNNING;
+			schedule();
+		}
 	}
 out:
 	return 0;
@@ -377,11 +387,9 @@
  * cluster them so that we get good swap-out behaviour. See
  * the "free_memory()" macro for details.
  */
-static int do_try_to_free_pages(unsigned int gfp_mask)
+int try_to_free_pages(unsigned int gfp_mask)
 {
 	int priority;
-	int ret = 0;
-	int swapcount;
 	int count = SWAP_CLUSTER_MAX;
 
 	lock_kernel();
@@ -389,41 +397,34 @@
 	/* Always trim SLAB caches when memory gets low. */
 	kmem_cache_reap(gfp_mask);
 
-	priority = 6;
+	priority = 5;
 	do {
 		while (shrink_mmap(priority, gfp_mask)) {
-			ret = 1;
 			if (!--count)
 				goto done;
 		}
 
 		/* Try to get rid of some shared memory pages.. */
-		if (gfp_mask & __GFP_IO) {
+		if (gfp_mask & __GFP_IO && !current->fs_locks) {
 			while (shm_swap(priority, gfp_mask)) {
-				ret = 1;
 				if (!--count)
 					goto done;
 			}
 		}
 
 		/* Then, try to page stuff out.. */
-		swapcount = count;
 		while (swap_out(priority, gfp_mask)) {
-			ret = 1;
-			if (!--swapcount)
-				break;
+			if (!--count)
+				goto done;
 		}
 
 		shrink_dcache_memory(priority, gfp_mask);
-	} while (--priority >= 0);
+	} while (--priority > 0);
 done:
 	unlock_kernel();
 
-	if (!ret)
-		printk("VM: do_try_to_free_pages failed for %s...\n",
-				current->comm);
 	/* Return success if we freed a page. */
-	return ret;
+	return priority > 0;
 }
 
 /*
@@ -499,7 +500,7 @@
 
 		while (nr_free_pages < freepages.high)
 		{
-			if (do_try_to_free_pages(GFP_KSWAPD))
+			if (try_to_free_pages(GFP_KSWAPD))
 			{
 				if (tsk->need_resched)
 					schedule();
@@ -510,17 +511,3 @@
 		}
 	}
 }
-
-/*
- * Called by non-kswapd processes when kswapd really cannot
- * keep up with the demand for free memory.
- */
-int try_to_free_pages(unsigned int gfp_mask)
-{
-	int retval = 1;
-
-	if (gfp_mask & __GFP_WAIT)
-		retval = do_try_to_free_pages(gfp_mask);
-	return retval;
-}
-	
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/Changes linux.19p18/net/Changes
--- linux.vanilla/net/Changes	Fri Apr 21 12:47:11 2000
+++ linux.19p18/net/Changes	Thu Jan  1 01:00:00 1970
@@ -1,45 +0,0 @@
---------------- Things That Need Doing Before 2.2 ------------------
-
-o	insw_and_csum
-
--------------------------- Bugs to fix ------------------------------
-
-o	Should unix domain connect never block ?
-o	Screend loadable firewall module
-o	Fix merging the bridge code
-o	Remove kernel RARP and replace with user mode daemon.
-o	Merge ARM half word trap fixes for ethernet headers
-o	Stop route addition to downed interfaces
-o	Make sure route add window functionality is back or documented
-	equivalences are clear
-o	Merge ATM 
-o	Merge IRDA
-
-Possible projects for victim^H^H^H^H^Holunteers
-
-9.	Implementing streams. Not as a blind slow SYS5.4 style copy but actually
-working out how to do it so it runs like greased lightning. Quite a big
-problem. [See the LiS project]
-
-11.	IP over SCSI. [worked on]
-
-14.	Bidirectional PLIP. Also PLIP for the newer style parallel ports.
-
-15.	802.2LLC and thus Netbeui sockets. Becoming less important since the
-rumour is microsoft are phasing out netbeui for netbios/IP. Microsoft have
-gone for netbios/funny-ipx-variant it seems in Win95, but TCP is selectable.
-
-17.	PPP multilink. Another nasty job.
-
-19.	IPv4 IP-AH and IP-ESP.
-
-20.	(userspace) GUI interface to the bandwidth allocators so mere
-	mortals can do this
-
-
-BTW: Don't let the magic words 'kernel programming' worry you. Its like DOS
-- you make a mistake you have to reboot. You do at least get dumps and a
-kernel logger that is reliable. There is now a loadable module allowing
-use of gdb on the kernel (no breakpoints though!). No magic involved.
-
-Alan
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/Config.in linux.19p18/net/Config.in
--- linux.vanilla/net/Config.in	Mon Dec 11 22:13:08 2000
+++ linux.19p18/net/Config.in	Wed Feb  7 09:46:49 2001
@@ -56,15 +56,16 @@
   bool 'Fast switching (read help!)' CONFIG_NET_FASTROUTE
   bool 'Forwarding between high speed interfaces' CONFIG_NET_HW_FLOWCONTROL
   bool 'CPU is too slow to handle full bandwidth' CONFIG_CPU_IS_SLOW
-  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  mainmenu_option next_comment
-  comment 'QoS and/or fair queueing'
-  bool 'QoS and/or fair queueing' CONFIG_NET_SCHED
-  if [ "$CONFIG_NET_SCHED" = "y" ]; then
-    source net/sched/Config.in
-  fi
-#  bool 'Network code profiler' CONFIG_NET_PROFILE
-  endmenu
-  fi
 fi
+
+mainmenu_option next_comment
+comment 'QoS and/or fair queueing'
+bool 'QoS and/or fair queueing' CONFIG_NET_SCHED
+if [ "$CONFIG_NET_SCHED" = "y" ]; then
+  source net/sched/Config.in
+fi
+endmenu
+
+#bool 'Network code profiler' CONFIG_NET_PROFILE
+
 endmenu
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ax25/af_ax25.c linux.19p18/net/ax25/af_ax25.c
--- linux.vanilla/net/ax25/af_ax25.c	Mon Dec 11 22:13:09 2000
+++ linux.19p18/net/ax25/af_ax25.c	Thu Feb 15 16:24:42 2001
@@ -720,6 +720,9 @@
 	if (get_user(len, optlen))
 		return -EFAULT;
 
+	if (len < 0)
+		return -EINVAL;
+		
 	switch (optname) {
 		case AX25_WINDOW:
 			val = sk->protinfo.ax25->window;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ax25/ax25_in.c linux.19p18/net/ax25/ax25_in.c
--- linux.vanilla/net/ax25/ax25_in.c	Fri Apr 21 12:47:10 2000
+++ linux.19p18/net/ax25/ax25_in.c	Mon Feb 12 14:53:33 2001
@@ -36,6 +36,7 @@
  *	AX.25 036	Jonathan(G4KLX)	Move DAMA code into own file.
  *			Joerg(DL1BKE)	Fixed DAMA Slave.
  *	AX.25 037	Jonathan(G4KLX)	New timer architecture.
+ *			Thomas(DL9SAU)  Fixed missing initialization of skb->protocol.
  */
 
 #include <linux/config.h>
@@ -159,6 +160,7 @@
 		skb->nh.raw   = skb->data;
 		skb->dev      = ax25->ax25_dev->dev;
 		skb->pkt_type = PACKET_HOST;
+		skb->protocol = htons(ETH_P_IP);
 		ip_rcv(skb, skb->dev, NULL);	/* Wrong ptype */
 		return 1;
 	}
@@ -293,6 +295,7 @@
 				skb->nh.raw   = skb->data;
 				skb->dev      = dev;
 				skb->pkt_type = PACKET_HOST;
+				skb->protocol = htons(ETH_P_IP);
 				ip_rcv(skb, dev, ptype);	/* Note ptype here is the wrong one, fix me later */
 				break;
 
@@ -302,6 +305,7 @@
 				skb->nh.raw   = skb->data;
 				skb->dev      = dev;
 				skb->pkt_type = PACKET_HOST;
+				skb->protocol = htons(ETH_P_ARP);
 				arp_rcv(skb, dev, ptype);	/* Note ptype here is wrong... */
 				break;
 #endif
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/core/dev.c linux.19p18/net/core/dev.c
--- linux.vanilla/net/core/dev.c	Mon Dec 11 22:13:09 2000
+++ linux.19p18/net/core/dev.c	Tue Jan  9 11:55:08 2001
@@ -649,7 +649,7 @@
 
 
 /*=======================================================================
-			Receiver rotutines
+			Receiver routines
   =======================================================================*/
 
 int netdev_dropping = 0;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/core/filter.c linux.19p18/net/core/filter.c
--- linux.vanilla/net/core/filter.c	Fri Apr 21 12:47:11 2000
+++ linux.19p18/net/core/filter.c	Tue Feb 20 13:28:13 2001
@@ -196,7 +196,7 @@
 			case BPF_LD|BPF_W|BPF_ABS:
 				k = fentry->k;
 load_w:
-				if(k+sizeof(u32) <= len) {
+				if((unsigned int)(k+sizeof(u32)) <= len) {
 					A = ntohl(*(u32*)&data[k]);
 					continue;
 				}
@@ -215,7 +215,7 @@
 			case BPF_LD|BPF_H|BPF_ABS:
 				k = fentry->k;
 load_h:
-				if(k + sizeof(u16) <= len) {
+				if((unsigned int) (k + sizeof(u16)) <= len) {
 					A = ntohs(*(u16*)&data[k]);
 					continue;
 				}
@@ -234,7 +234,7 @@
 			case BPF_LD|BPF_B|BPF_ABS:
 				k = fentry->k;
 load_b:
-				if(k < len) {
+				if((unsigned int)k < len) {
 					A = data[k];
 					continue;
 				}
@@ -271,7 +271,7 @@
 
 			case BPF_LDX|BPF_B|BPF_MSH:
 				k = fentry->k;
-				if(k >= len)
+				if((unsigned int)k >= len)
 					return (0);
 				X = (data[k] & 0xf) << 2;
 				continue;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/core/sock.c linux.19p18/net/core/sock.c
--- linux.vanilla/net/core/sock.c	Mon Dec 11 22:13:09 2000
+++ linux.19p18/net/core/sock.c	Thu Feb 15 16:24:23 2001
@@ -79,6 +79,7 @@
  *		Jay Schulist	:	Added SO_ATTACH_FILTER and SO_DETACH_FILTER.
  *		Andi Kleen	:	Add sock_kmalloc()/sock_kfree_s()
  *		Andi Kleen	:	Fix write_space callback
+ *		Chris Evans	:	Security fixes - signedness again
  *
  * To Fix:
  *
@@ -381,6 +382,9 @@
   	if(get_user(len,optlen))
   		return -EFAULT;
 
+	if(len < 0)
+		return -EINVAL;
+		
   	switch(optname) 
   	{
 		case SO_DEBUG:		
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/icmp.c linux.19p18/net/ipv4/icmp.c
--- linux.vanilla/net/ipv4/icmp.c	Mon Dec 11 22:13:10 2000
+++ linux.19p18/net/ipv4/icmp.c	Wed Feb  7 09:45:05 2001
@@ -3,7 +3,7 @@
  *	
  *		Alan Cox, <alan@redhat.com>
  *
- *	Version: $Id: icmp.c,v 1.52.2.6 2000/08/31 23:49:16 davem Exp $
+ *	Version: $Id: icmp.c,v 1.52.2.7 2001/02/02 01:27:08 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -989,13 +989,21 @@
 
 int icmp_chkaddr(struct sk_buff *skb)
 {
-	struct icmphdr *icmph=(struct icmphdr *)(skb->nh.raw + skb->nh.iph->ihl*4);
+	unsigned short size = skb->nh.iph->ihl*4;
+	unsigned short clen = ntohs(skb->nh.iph->tot_len) - size;
+	struct icmphdr *icmph=(struct icmphdr *)(skb->nh.raw + size);
 	struct iphdr *iph = (struct iphdr *) (icmph + 1);
-	void (*handler)(struct icmphdr *icmph, struct sk_buff *skb, int len) = icmp_pointers[icmph->type].handler;
+	void (*handler)(struct icmphdr *icmph, struct sk_buff *skb, int len);
 
+	if (clen < sizeof(struct icmphdr)) return 0;
+	handler = icmp_pointers[icmph->type].handler;
 	if (handler == icmp_unreach || handler == icmp_redirect) {
 		struct sock *sk;
-
+		
+		clen -= sizeof(struct icmphdr);
+		if (clen < sizeof(struct iphdr) ||
+			clen < iph->ihl * 4 + sizeof(struct udphdr))
+			return 0;
 		switch (iph->protocol) {
 		case IPPROTO_TCP:
 			{
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/igmp.c linux.19p18/net/ipv4/igmp.c
--- linux.vanilla/net/ipv4/igmp.c	Fri Apr 21 12:47:12 2000
+++ linux.19p18/net/ipv4/igmp.c	Thu Feb  1 15:03:36 2001
@@ -8,7 +8,7 @@
  *	the older version didn't come out right using gcc 2.5.8, the newer one
  *	seems to fall out with gcc 2.6.2.
  *
- *	Version: $Id: igmp.c,v 1.30.2.1 1999/07/23 15:29:22 davem Exp $
+ *	Version: $Id: igmp.c,v 1.30.2.2 2001/01/10 10:04:07 davem Exp $
  *
  *	Authors:
  *		Alan Cox <Alan.Cox@linux.org>
@@ -442,8 +442,8 @@
 	im->timer.function=&igmp_timer_expire;
 	im->unsolicit_count = IGMP_Unsolicited_Report_Count;
 	im->reporter = 0;
-	im->loaded = 0;
 #endif
+	im->loaded = 0;
 	im->next=in_dev->mc_list;
 	in_dev->mc_list=im;
 	igmp_group_added(im);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/ip_input.c linux.19p18/net/ipv4/ip_input.c
--- linux.vanilla/net/ipv4/ip_input.c	Fri Apr 21 12:47:14 2000
+++ linux.19p18/net/ipv4/ip_input.c	Wed Feb  7 09:45:05 2001
@@ -5,7 +5,7 @@
  *
  *		The Internet Protocol (IP) module.
  *
- * Version:	$Id: ip_input.c,v 1.37 1999/04/22 10:38:36 davem Exp $
+ * Version:	$Id: ip_input.c,v 1.37.2.4 2001/01/04 04:20:16 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/ip_masq.c linux.19p18/net/ipv4/ip_masq.c
--- linux.vanilla/net/ipv4/ip_masq.c	Fri Apr 21 12:47:14 2000
+++ linux.19p18/net/ipv4/ip_masq.c	Wed Feb  7 09:45:05 2001
@@ -4,7 +4,7 @@
  *
  * 	Copyright (c) 1994 Pauline Middelink
  *
- *	$Id: ip_masq.c,v 1.34.2.2 1999/08/07 10:56:28 davem Exp $
+ *	$Id: ip_masq.c,v 1.34.2.14 2001/02/02 01:27:08 davem Exp $
  *
  *
  *	See ip_fw.c for original log
@@ -236,7 +236,7 @@
 	
 tcp_state_out:
 	if (new_state!=ms->state)
-		IP_MASQ_DEBUG(1, "%s %s [%c%c%c%c] %08lX:%04X-%08lX:%04X state: %s->%s\n",
+		IP_MASQ_DEBUG(1, "%s %s [%c%c%c%c] %08X:%04X-%08X:%04X state: %s->%s\n",
 				masq_proto_name(ms->protocol),
 				output? "output" : "input ",
 				th->syn? 'S' : '.',
@@ -798,7 +798,7 @@
 	 */
 	atomic_inc(&ms->refcnt);
 
-	IP_MASQ_DEBUG(1, "Masqueraded %s %08lX:%04X expired\n",
+	IP_MASQ_DEBUG(1, "Masqueraded %s %08X:%04X expired\n",
 			masq_proto_name(ms->protocol),
 			ntohl(ms->saddr),ntohs(ms->sport));
 
@@ -846,7 +846,7 @@
 	}
 
 masq_expire_later:
-	IP_MASQ_DEBUG(0, "masq_expire delayed: %s %08lX:%04X->%08lX:%04X masq.refcnt-1=%d masq.n_control=%d\n",
+	IP_MASQ_DEBUG(0, "masq_expire delayed: %s %08X:%04X->%08X:%04X masq.refcnt-1=%d masq.n_control=%d\n",
 		masq_proto_name(ms->protocol),
 		ntohl(ms->saddr), ntohs(ms->sport),
 		ntohl(ms->daddr), ntohs(ms->dport),
@@ -1223,7 +1223,7 @@
 
 	/* h.raw = (char*) iph + iph->ihl * 4; */
 
- 	IP_MASQ_DEBUG(2, "Outgoing %s %08lX:%04X -> %08lX:%04X\n",
+ 	IP_MASQ_DEBUG(2, "Outgoing %s %08X:%04X -> %08X:%04X\n",
   		masq_proto_name(iph->protocol),
   		ntohl(iph->saddr), ntohs(h.portp[0]),
   		ntohl(iph->daddr), ntohs(h.portp[1]));
@@ -1294,6 +1294,8 @@
 					0);
                 if (ms == NULL)
 			return -1;
+		if (!ms->app && skb->fwmark)
+			ip_masq_bind_app_fwmark(ms, skb->fwmark);
  	}
 
 	/*
@@ -1387,7 +1389,7 @@
 	}
 	ip_send_check(iph);
 
-  	IP_MASQ_DEBUG(2, "O-routed from %08lX:%04X with masq.addr %08lX\n",
+  	IP_MASQ_DEBUG(2, "O-routed from %08X:%04X with masq.addr %08X\n",
 		ntohl(ms->maddr),ntohs(ms->mport),ntohl(maddr));
 
 	masq_set_state(ms, 1, iph, h.portp);
@@ -1485,8 +1487,9 @@
 	__u16	        *pptr;	/* port numbers from TCP/UDP contained header */
 	struct ip_masq	*ms;
 	unsigned short   len   = ntohs(iph->tot_len) - (iph->ihl * 4);
+	unsigned short	clen, csize;
 
- 	IP_MASQ_DEBUG(2, "Incoming forward ICMP (%d,%d) %lX -> %lX\n",
+ 	IP_MASQ_DEBUG(2, "Incoming forward ICMP (%d,%d) %X -> %X\n",
 	        icmph->type, ntohs(icmp_id(icmph)),
  		ntohl(iph->saddr), ntohl(iph->daddr));
 
@@ -1496,7 +1499,7 @@
 	    (icmph->type == ICMP_INFO_REQUEST ) ||
 	    (icmph->type == ICMP_ADDRESS )) {
 
-		IP_MASQ_DEBUG(2, "icmp request rcv %lX->%lX  id %d type %d\n",
+		IP_MASQ_DEBUG(2, "icmp request rcv %X->%X  id %d type %d\n",
 		       ntohl(iph->saddr),
 		       ntohl(iph->daddr),
 		       ntohs(icmp_id(icmph)),
@@ -1547,7 +1550,7 @@
 		icmph->checksum = 0;
 		icmph->checksum = ip_compute_csum((unsigned char *)icmph, len);
 
-		IP_MASQ_DEBUG(2, "icmp request rwt %lX->%lX id %d type %d\n",
+		IP_MASQ_DEBUG(2, "icmp request rwt %X->%X id %d type %d\n",
 		       ntohl(iph->saddr),
 		       ntohl(iph->daddr),
 		       ntohs(icmp_id(icmph)),
@@ -1574,18 +1577,24 @@
 		return 0;
 
 	/* Now find the contained IP header */
+	clen = len - sizeof(struct icmphdr);
+	if (clen < sizeof(struct iphdr)) return -1;
 	ciph = (struct iphdr *) (icmph + 1);
+	csize = ciph->ihl << 2;
+	if (clen < csize) return -1;
 
 #ifdef CONFIG_IP_MASQUERADE_ICMP
 	if (ciph->protocol == IPPROTO_ICMP) {
 		/*
 		 * This section handles ICMP errors for ICMP packets
 		 */
-		struct icmphdr  *cicmph = (struct icmphdr *)((char *)ciph + 
-							     (ciph->ihl<<2));
+		struct icmphdr  *cicmph;
 
+		if (clen < csize + sizeof(struct icmphdr)) return -1;
 
-		IP_MASQ_DEBUG(2, "fw icmp/icmp rcv %lX->%lX id %d type %d\n",
+		cicmph = (struct icmphdr *)((char *)ciph + csize);
+
+		IP_MASQ_DEBUG(2, "fw icmp/icmp rcv %X->%X id %d type %d\n",
 		       ntohl(ciph->saddr),
 		       ntohl(ciph->daddr),
 		       ntohs(icmp_id(cicmph)),
@@ -1621,7 +1630,7 @@
 		icmph->checksum = ip_compute_csum((unsigned char *) icmph, len);
 
 
-		IP_MASQ_DEBUG(2, "fw icmp/icmp rwt %lX->%lX id %d type %d\n",
+		IP_MASQ_DEBUG(2, "fw icmp/icmp rwt %X->%X id %d type %d\n",
 		       ntohl(ciph->saddr),
 		       ntohl(ciph->daddr),
 		       ntohs(icmp_id(cicmph)),
@@ -1635,12 +1644,15 @@
 	if ((ciph->protocol != IPPROTO_UDP) && (ciph->protocol != IPPROTO_TCP))
 		return 0;
 
+	/* This is a hack: we need at least the TCP/UDP ports */
+	if (clen < csize + sizeof(struct udphdr)) return -1;
+
 	/*
 	 * Find the ports involved - this packet was
 	 * incoming so the ports are right way round
 	 * (but reversed relative to outer IP header!)
 	 */
-	pptr = (__u16 *)&(((char *)ciph)[ciph->ihl*4]);
+	pptr = (__u16 *)&(((char *)ciph)[csize]);
 #if 0
 	if (ntohs(pptr[1]) < PORT_MASQ_BEGIN ||
  	    ntohs(pptr[1]) > PORT_MASQ_END)
@@ -1657,7 +1669,7 @@
 	}
 
 
- 	IP_MASQ_DEBUG(2, "Handling forward ICMP for %08lX:%04X -> %08lX:%04X\n",
+ 	IP_MASQ_DEBUG(2, "Handling forward ICMP for %08X:%04X -> %08X:%04X\n",
 	       ntohl(ciph->saddr), ntohs(pptr[0]),
 	       ntohl(ciph->daddr), ntohs(pptr[1]));
 
@@ -1695,7 +1707,7 @@
 	icmph->checksum = ip_compute_csum((unsigned char *) icmph, len);
 
 
- 	IP_MASQ_DEBUG(2, "Rewrote forward ICMP to %08lX:%04X -> %08lX:%04X\n",
+ 	IP_MASQ_DEBUG(2, "Rewrote forward ICMP to %08X:%04X -> %08X:%04X\n",
 	       ntohl(ciph->saddr), ntohs(pptr[0]),
 	       ntohl(ciph->daddr), ntohs(pptr[1]));
 
@@ -1743,9 +1755,10 @@
 	__u16	        *pptr;	/* port numbers from TCP/UDP contained header */
 	struct ip_masq	*ms;
 	unsigned short   len   = ntohs(iph->tot_len) - (iph->ihl * 4);
+	unsigned short	clen, csize;
 
 
- 	IP_MASQ_DEBUG(2, "icmp in/rev (%d,%d) %lX -> %lX\n",
+ 	IP_MASQ_DEBUG(2, "icmp in/rev (%d,%d) %X -> %X\n",
 	        icmph->type, ntohs(icmp_id(icmph)),
  		ntohl(iph->saddr), ntohl(iph->daddr));
 
@@ -1756,7 +1769,7 @@
 	    (icmph->type == ICMP_INFO_REPLY) ||
 	    (icmph->type == ICMP_ADDRESSREPLY))	{
 
-		IP_MASQ_DEBUG(2, "icmp reply rcv %lX->%lX id %d type %d, req %d\n",
+		IP_MASQ_DEBUG(2, "icmp reply rcv %X->%X id %d type %d, req %d\n",
 		       ntohl(iph->saddr),
 		       ntohl(iph->daddr),
 		       ntohs(icmp_id(icmph)),
@@ -1793,7 +1806,7 @@
 
 
 
-		IP_MASQ_DEBUG(2, "icmp reply rwt %lX->%lX id %d type %d\n",
+		IP_MASQ_DEBUG(2, "icmp reply rwt %X->%X id %d type %d\n",
 		       ntohl(iph->saddr),
 		       ntohl(iph->daddr),
 		       ntohs(icmp_id(icmph)),
@@ -1817,7 +1830,11 @@
 	 * Now find the contained IP header
 	 */
 
+	clen = len - sizeof(struct icmphdr);
+	if (clen < sizeof(struct iphdr)) return -1;
 	ciph = (struct iphdr *) (icmph + 1);
+	csize = ciph->ihl << 2;
+	if (clen < csize) return -1;
 
 #ifdef CONFIG_IP_MASQUERADE_ICMP
 	if (ciph->protocol == IPPROTO_ICMP) {
@@ -1826,11 +1843,13 @@
 		 *
 		 * First get a new ICMP header structure out of the IP packet
 		 */
-		struct icmphdr  *cicmph = (struct icmphdr *)((char *)ciph + 
-							     (ciph->ihl<<2));
+		struct icmphdr  *cicmph;
+
+		if (clen < csize + sizeof(struct icmphdr)) return -1;
 
+		cicmph = (struct icmphdr *)((char *)ciph +  csize);
 
-		IP_MASQ_DEBUG(2, "rv icmp/icmp rcv %lX->%lX id %d type %d\n",
+		IP_MASQ_DEBUG(2, "rv icmp/icmp rcv %X->%X id %d type %d\n",
 		       ntohl(ciph->saddr),
 		       ntohl(ciph->daddr),
 		       ntohs(icmp_id(cicmph)),
@@ -1872,7 +1891,7 @@
 		icmph->checksum = ip_compute_csum((unsigned char *) icmph, len);
 
 
-		IP_MASQ_DEBUG(2, "rv icmp/icmp rwt %lX->%lX id %d type %d\n",
+		IP_MASQ_DEBUG(2, "rv icmp/icmp rwt %X->%X id %d type %d\n",
 		       ntohl(ciph->saddr),
 		       ntohl(ciph->daddr),
 		       ntohs(icmp_id(cicmph)),
@@ -1887,11 +1906,14 @@
 	    (ciph->protocol != IPPROTO_TCP))
 		return 0;
 
+	/* This is a hack: we need at least the TCP/UDP ports */
+	if (clen < csize + sizeof(struct udphdr)) return -1;
+
 	/*
 	 * Find the ports involved - remember this packet was
 	 * *outgoing* so the ports are reversed (and addresses)
 	 */
-	pptr = (__u16 *)&(((char *)ciph)[ciph->ihl*4]);
+	pptr = (__u16 *)&(((char *)ciph)[csize]);
 	if (ntohs(pptr[0]) < PORT_MASQ_BEGIN ||
  	    ntohs(pptr[0]) > PORT_MASQ_END)
  		return 0;
@@ -1906,7 +1928,7 @@
 	}
 
 
- 	IP_MASQ_DEBUG(2, "Handling reverse ICMP for %08lX:%04X -> %08lX:%04X\n",
+ 	IP_MASQ_DEBUG(2, "Handling reverse ICMP for %08X:%04X -> %08X:%04X\n",
 	       ntohl(ciph->saddr), ntohs(pptr[0]),
 	       ntohl(ciph->daddr), ntohs(pptr[1]));
 
@@ -1948,7 +1970,7 @@
 	icmph->checksum = ip_compute_csum((unsigned char *) icmph, len);
 
 
- 	IP_MASQ_DEBUG(2, "Rewrote reverse ICMP to %08lX:%04X -> %08lX:%04X\n",
+ 	IP_MASQ_DEBUG(2, "Rewrote reverse ICMP to %08X:%04X -> %08X:%04X\n",
 	       ntohl(ciph->saddr), ntohs(pptr[0]),
 	       ntohl(ciph->daddr), ntohs(pptr[1]));
 
@@ -2067,7 +2089,7 @@
 
 
 
- 	IP_MASQ_DEBUG(2, "Incoming %s %08lX:%04X -> %08lX:%04X\n",
+ 	IP_MASQ_DEBUG(2, "Incoming %s %08X:%04X -> %08X:%04X\n",
  		masq_proto_name(iph->protocol),
  		ntohl(iph->saddr), ntohs(h.portp[0]),
  		ntohl(iph->daddr), ntohs(h.portp[1]));
@@ -2082,8 +2104,11 @@
  	 * 	Give additional modules a chance to create an entry
 	 */
 #ifdef CONFIG_IP_MASQUERADE_MOD
-	if (!ms) 
+	if (!ms) {
 		ms = ip_masq_mod_in_create(skb, iph, maddr);
+		if (ms && !ms->app && skb->fwmark)
+			ip_masq_bind_app_fwmark(ms, skb->fwmark);
+	}
 
 	/*
  	 * 	Call module's input update hook
@@ -2138,7 +2163,7 @@
 
 			write_unlock(&__ip_masq_lock);
 
-                        IP_MASQ_DEBUG(1, "ip_fw_demasquerade(): filled daddr=%lX\n",
+                        IP_MASQ_DEBUG(1, "ip_fw_demasquerade(): filled daddr=%X\n",
                                ntohl(ms->daddr));
 
                 }
@@ -2208,7 +2233,7 @@
 		}
                 ip_send_check(iph);
 
-                IP_MASQ_DEBUG(2, "I-routed to %08lX:%04X\n",ntohl(iph->daddr),ntohs(h.portp[1]));
+                IP_MASQ_DEBUG(2, "I-routed to %08X:%04X\n",ntohl(iph->daddr),ntohs(h.portp[1]));
 
 		masq_set_state (ms, 0, iph, h.portp);
 		ip_masq_put(ms);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/ip_masq_app.c linux.19p18/net/ipv4/ip_masq_app.c
--- linux.vanilla/net/ipv4/ip_masq_app.c	Fri Apr 21 12:47:14 2000
+++ linux.19p18/net/ipv4/ip_masq_app.c	Wed Feb  7 09:45:05 2001
@@ -2,7 +2,7 @@
  *		IP_MASQ_APP application masquerading module
  *
  *
- * 	$Id: ip_masq_app.c,v 1.16 1998/08/29 23:51:14 davem Exp $
+ * 	$Id: ip_masq_app.c,v 1.16.2.2 2001/01/04 05:28:46 davem Exp $
  *
  * Author:	Juan Jose Ciarlante, <jjciarla@raiz.uncu.edu.ar>
  *
@@ -15,7 +15,8 @@
  * Fixes:
  *	JJC			: Implemented also input pkt hook
  *	Miquel van Smoorenburg	: Copy more stuff when resizing skb
- *
+ *	Juan Jose Ciarlante	: reworked register() (new _init_xxxx()  functions for nicer interface)
+ *	Juan Jose Ciarlante	: add INBOUND hooks (default to OUTBOUND)
  *
  * FIXME:
  *	- ip_masq_skb_replace(): use same skb if space available.
@@ -41,13 +42,27 @@
 
 #define IP_MASQ_APP_TAB_SIZE  16 /* must be power of 2 */
 
-#define IP_MASQ_APP_HASH(proto, port) ((port^proto) & (IP_MASQ_APP_TAB_SIZE-1))
-#define IP_MASQ_APP_TYPE(proto, port) ( proto<<16 | port )
-#define IP_MASQ_APP_PORT(type)        ( type & 0xffff )
-#define IP_MASQ_APP_PROTO(type)       ( (type>>16) & 0x00ff )
+/*
+ * 	ip_masq_app->type holds all the values needed to hook
+ * 	passing packet
+ * 		flags: 	(uses only upper 8bits: f_bits)
+ * 			INBOUND, OUTBOUND
+ * 			FWMARK
+ *
+ * 	if (flags & IP_MASQ_APP_FWMARK)
+ * 		[ f_bits][ fwmark (24 bits only)  ]
+ * 	else
+ * 		[ f_bits][ proto ][     port      ]
+ * 	        
+ * 	        <-----------  32 bits ------------>
+ * 	
+ */
+
+#define IP_MASQ_APP_HASH(type) (((type>>16)^(type)) & (IP_MASQ_APP_TAB_SIZE-1))
 
 
 EXPORT_SYMBOL(register_ip_masq_app);
+EXPORT_SYMBOL(register_ip_masq_app_type);
 EXPORT_SYMBOL(unregister_ip_masq_app);
 EXPORT_SYMBOL(ip_masq_skb_replace);
 
@@ -58,29 +73,53 @@
 struct ip_masq_app *ip_masq_app_base[IP_MASQ_APP_TAB_SIZE];
 
 /*
- * 	ip_masq_app registration routine
- *	port: host byte order.
+ * 	"raw" ip_masq_app registration routine if you 
+ * 	did ip_masq_app_init_xxxx() before to initialize (and check)
+ * 	type value
  */
 
-int register_ip_masq_app(struct ip_masq_app *mapp, unsigned short proto, __u16 port)
-{
+int register_ip_masq_app_type(struct ip_masq_app *mapp)  {
         unsigned long flags;
         unsigned hash;
+#ifdef CONFIG_IP_MASQ_DEBUG
         if (!mapp) {
                 IP_MASQ_ERR("register_ip_masq_app(): NULL arg\n");
                 return -EINVAL;
         }
-        mapp->type = IP_MASQ_APP_TYPE(proto, port);
+#endif
+	if (!mapp->type) {
+		IP_MASQ_DEBUG(1, "ip_masq_app_register_type(): ZERO type passed\n");
+		return -EINVAL;
+	}
+
         mapp->n_attach = 0;
-        hash = IP_MASQ_APP_HASH(proto, port);
+        hash = IP_MASQ_APP_HASH(mapp->type);
+	IP_MASQ_DEBUG(2, "ip_masq_app_register(): type=0x%x hash=0x%x\n", mapp->type, hash);
 
         save_flags(flags);
         cli();
         mapp->next = ip_masq_app_base[hash];
         ip_masq_app_base[hash] = mapp;
         restore_flags(flags);
+	return 0;
+}
 
-        return 0;
+/*
+ * 	ip_masq_app registration routine
+ *	port: host byte order.
+ *	proto:  (flags<<8) | ipproto 
+ */
+int register_ip_masq_app(struct ip_masq_app *mapp, unsigned proto, __u16 port)
+{
+#ifdef CONFIG_IP_MASQ_DEBUG
+        if (!mapp) {
+                IP_MASQ_ERR("register_ip_masq_app(): NULL arg\n");
+                return -EINVAL;
+        }
+#endif
+
+	ip_masq_app_init_proto_port(mapp, IP_MASQ_APP_OUTBOUND, proto, port);
+        return register_ip_masq_app_type(mapp);
 }
 
 /*
@@ -104,7 +143,7 @@
                        mapp->n_attach);
                 return -EINVAL;
         }
-        hash = IP_MASQ_APP_HASH(IP_MASQ_APP_PROTO(mapp->type), IP_MASQ_APP_PORT(mapp->type));
+        hash = IP_MASQ_APP_HASH(mapp->type);
 
         save_flags(flags);
         cli();
@@ -116,24 +155,26 @@
                 }
 
         restore_flags(flags);
-        IP_MASQ_ERR("unregister_ip_masq_app(proto=%s,port=%u): not hashed!\n",
-               masq_proto_name(IP_MASQ_APP_PROTO(mapp->type)), IP_MASQ_APP_PORT(mapp->type));
+        IP_MASQ_ERR("unregister_ip_masq_app(flags=0x%x, proto=%s,port=%u,fwmark=%d): not hashed!\n",
+			
+		IP_MASQ_APP_TYPE2FLAGS(mapp->type),
+		masq_proto_name(IP_MASQ_APP_TYPE2PROTO(mapp->type)), 
+		IP_MASQ_APP_TYPE2PORT(mapp->type),
+		IP_MASQ_APP_TYPE2FWMARK(mapp->type));
         return -EINVAL;
 }
 
 /*
- *	get ip_masq_app object by its proto and port (net byte order).
+ *	get ip_masq_app object by its proto and port (host byte order).
  */
 
-struct ip_masq_app * ip_masq_app_get(unsigned short proto, __u16 port)
+struct ip_masq_app * ip_masq_app_get_type(unsigned type)
 {
         struct ip_masq_app *mapp;
         unsigned hash;
-        unsigned type;
 
-        port = ntohs(port);
-        type = IP_MASQ_APP_TYPE(proto,port);
-        hash = IP_MASQ_APP_HASH(proto,port);
+        hash = IP_MASQ_APP_HASH(type);
+	IP_MASQ_DEBUG(2, "ip_masq_app_get(): type=0x%x hash=0x%x\n", type, hash);
         for(mapp = ip_masq_app_base[hash]; mapp ; mapp = mapp->next) {
                 if (type == mapp->type) return mapp;
         }
@@ -159,8 +200,8 @@
         if (n_at < 0) {
                 restore_flags(flags);
                 IP_MASQ_ERR("ip_masq_app: tried to set n_attach < 0 for (proto=%s,port==%d) ip_masq_app object.\n",
-                       masq_proto_name(IP_MASQ_APP_PROTO(mapp->type)),
-                       IP_MASQ_APP_PORT(mapp->type));
+                       masq_proto_name(IP_MASQ_APP_TYPE2PROTO(mapp->type)),
+                       IP_MASQ_APP_TYPE2PORT(mapp->type));
                 return -1;
         }
         mapp->n_attach = n_at;
@@ -169,41 +210,91 @@
 }
 
 /*
+ *	Actually bind pointers and call contructor
+ */
+
+static struct ip_masq_app *do_bind_app(struct ip_masq *ms, struct ip_masq_app *mapp) 
+{
+	/*
+	 *	don't allow binding if already bound
+	 */
+	if (ms->app != NULL) {
+		IP_MASQ_ERR("ip_masq_bind_app() called for already bound object.\n");
+		goto end;
+	}
+	IP_MASQ_DEBUG(1, "ip_masq_bind_app() : bound \"%s\" module\n", mapp->name);
+	ms->app = mapp;
+	if (mapp->masq_init_1) mapp->masq_init_1(mapp, ms);
+	ip_masq_app_bind_chg(mapp, +1);
+end:
+        return ms->app;
+}
+
+/*
  *	Bind ip_masq to its ip_masq_app based on proto and dport ALREADY
- *	set in ip_masq struct. Also calls constructor.
+ *	set in ip_masq struct. 
+ *	Only called from ip_masq_new() when creating NEW masq tunnel,
  */
 
 struct ip_masq_app * ip_masq_bind_app(struct ip_masq *ms)
 {
         struct ip_masq_app * mapp;
+	unsigned type;
 
 	if (ms->protocol != IPPROTO_TCP && ms->protocol != IPPROTO_UDP)
 		return NULL;
 
-        mapp = ip_masq_app_get(ms->protocol, ms->dport);
+	IP_MASQ_DEBUG(1, "ip_masq_bind_app() : called for dst=%d.%d.%d.%d:%d src=%d.%d.%d.%d:%d masq=%d.%d.%d.%d:%d\n",
+			NIPQUAD(ms->daddr), ntohs(ms->dport),
+			NIPQUAD(ms->saddr), ntohs(ms->sport),
+			NIPQUAD(ms->maddr), ntohs(ms->mport));
 
-#if 0000
-/* #ifdef CONFIG_IP_MASQUERADE_IPAUTOFW */
-	if (mapp == NULL)
-		mapp = ip_masq_app_get(ms->protocol, ms->sport);
-/* #endif */
-#endif
+	/*
+	 * 	Lookup "normal" case (client's active open inside)  	
+	 */
+	type = IP_MASQ_APP_TYPE_PP(IP_MASQ_APP_OUTBOUND, ms->protocol, ntohs(ms->dport));
+        mapp = ip_masq_app_get_type(type);
 
-        if (mapp != NULL) {
-                /*
-                 *	don't allow binding if already bound
-                 */
-
-                if (ms->app != NULL) {
-                        IP_MASQ_ERR("ip_masq_bind_app() called for already bound object.\n");
-                        return ms->app;
-                }
+	if (mapp==NULL) {
+		/*	
+		 *	lookup "reverse" case (server waiting inside,
+		 *	for portfw and friends)
+		 */
+		type = IP_MASQ_APP_TYPE_PP(IP_MASQ_APP_INBOUND, ms->protocol, ntohs(ms->mport));
+		mapp = ip_masq_app_get_type(type);
+	}
 
-                ms->app = mapp;
-                if (mapp->masq_init_1) mapp->masq_init_1(mapp, ms);
-                ip_masq_app_bind_chg(mapp, +1);
-        }
-        return mapp;
+        if (mapp != NULL) 
+		mapp=do_bind_app(ms, mapp);
+	return mapp;
+}
+/*
+ *	Bind ip_masq to its ip_masq_app based on firewall mark
+ */
+struct ip_masq_app * ip_masq_bind_app_fwmark(struct ip_masq *ms, __u32 fwmark) {
+	struct ip_masq_app *mapp;
+	unsigned type;
+
+	IP_MASQ_DEBUG(1, "ip_masq_bind_app_fwmark() : called for fwmark=0x%x, dst=%d.%d.%d.%d:%d src=%d.%d.%d.%d:%d masq=%d.%d.%d.%d:%d\n",
+			fwmark,
+			NIPQUAD(ms->daddr), ntohs(ms->dport),
+			NIPQUAD(ms->saddr), ntohs(ms->sport),
+			NIPQUAD(ms->maddr), ntohs(ms->mport));
+
+	type = IP_MASQ_APP_TYPE_FWMARK(IP_MASQ_APP_OUTBOUND, fwmark);
+        mapp = ip_masq_app_get_type(type);
+
+	if (mapp==NULL) {
+		/*	
+		 *	lookup "reverse" case (server waiting inside,
+		 *	for portfw and friends)
+		 */
+		type = IP_MASQ_APP_TYPE_FWMARK(IP_MASQ_APP_INBOUND, fwmark);
+		mapp = ip_masq_app_get_type(type);
+	}
+        if (mapp != NULL) 
+		mapp=do_bind_app(ms, mapp);
+	return mapp;
 }
 
 /*
@@ -269,10 +360,14 @@
          * Adjust ack_seq with delta-offset for
          * the packets AFTER most recent resized pkt has caused a shift
          * for packets before most recent resized pkt, use previous_delta
+	 *
+	 * Compare acks against  (remote SEQs space is +delta)
+	 * 	(ms_seq->init_seq + ms_seq->delta), not ms_seq->init_seq
+	 * 		-- R.R. 27/08/00
          */
 
         if (ms_seq->delta || ms_seq->previous_delta) {
-                if(after(ack_seq,ms_seq->init_seq)) {
+                if(after(ack_seq,ms_seq->init_seq + ms_seq->delta)) {
                         th->ack_seq = htonl(ack_seq-ms_seq->delta);
                         IP_MASQ_DEBUG(1, "masq_fix_ack_seq() : subtracted delta (%d) from ack_seq\n",ms_seq->delta);
 
@@ -455,8 +550,8 @@
 				continue;
 
                         len += sprintf(buffer+len, "%-3s  %-7u %-7d  %-17s\n",
-                                       masq_proto_name(IP_MASQ_APP_PROTO(mapp->type)),
-                                       IP_MASQ_APP_PORT(mapp->type), mapp->n_attach,
+                                       masq_proto_name(IP_MASQ_APP_TYPE2PROTO(mapp->type)),
+                                       IP_MASQ_APP_TYPE2PORT(mapp->type), mapp->n_attach,
 				       mapp->name);
 
                         if(len >= length)
@@ -497,7 +592,7 @@
  *	Replace a segment (of skb->data) with a new one.
  *	FIXME: Should re-use same skb if space available, this could
  *	       be done if n_len < o_len, unless some extra space
- *	       were already allocated at driver level :P .
+ *	       were already allocated at link level :P .
  */
 
 static struct sk_buff * skb_replace(struct sk_buff *skb, int pri, char *o_buf, int o_len, char *n_buf, int n_len)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/ip_masq_ftp.c linux.19p18/net/ipv4/ip_masq_ftp.c
--- linux.vanilla/net/ipv4/ip_masq_ftp.c	Fri Apr 21 12:47:14 2000
+++ linux.19p18/net/ipv4/ip_masq_ftp.c	Wed Dec 13 22:22:39 2000
@@ -2,7 +2,7 @@
  *		IP_MASQ_FTP ftp masquerading module
  *
  *
- * Version:	@(#)ip_masq_ftp.c 0.04   02/05/96
+ * Version:	@(#)ip_masq_ftp.c 0.10   20/09/00
  *
  * Author:	Wouter Gadeyne
  *		
@@ -17,12 +17,15 @@
  *	Juan Jose Ciarlante	:	use ip_masq_listen() 
  *	Juan Jose Ciarlante	: 	use private app_data for own flag(s)
  *  Bjarni R. Einarsson :	Added protection against "extended FTP ALG attack"
- *
+ *	Neil Toronto		: portfw FTP support
+ *	Juan Jose Ciarlante	: reimplemented parsing logic, merged portfw FTP support for PASV (new "in_ports" module param), use th->doff for data offset
+ *	Juan Jose Ciarlante	: safe_mem_eq2() and size adjustments for less CPU
+ *	Juan Jose Ciarlante	: fwmark hook-able
  *
  *	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.
+ *	2 of the License.
  *	
  * Multiple Port Support
  *	The helper can be made to handle up to MAX_MASQ_APP_PORTS (normally 12)
@@ -34,6 +37,16 @@
  *	/etc/conf.modules (or /etc/modules.conf depending on your config)
  *	where modload will pick it up should you use modload to load your
  *	modules.
+ * Additional portfw Port Support
+ * 	Module parameter "in_ports" specifies the list of forwarded ports
+ * 	at firewall (portfw and friends) that must be hooked to allow 
+ * 	PASV connections to inside servers.
+ * 	Same as before:
+ * 		in_ports=fw1,fw2,...
+ *	Eg: 
+ *		ipmasqadm portfw -a -P tcp -L a.b.c.d 2021 -R 192.168.1.1 21
+ *		ipmasqadm portfw -a -P tcp -L a.b.c.d 8021 -R 192.168.1.1 21
+ *		modprobe ip_masq_ftp in_ports=2021,8021
  * 
  * Protection against the "extended FTP ALG vulnerability".
  *	This vulnerability was reported in:
@@ -66,22 +79,52 @@
 /* #define IP_MASQ_NDEBUG */
 #include <net/ip_masq.h>
 
+/*	
+ * 	paranoid, CPU care offset handling
+ */
+/* #define MASQ_FTP_RELAXED 1 */
+#ifdef MASQ_FTP_RELAXED
+#define _N(x) 	0
+#else
+#define _N(x)	(x)
+#endif
+
+#define IP_MASQ_FTP_RPAREN 0x01 /* stream has ')' char */
 
+/*
+ * 	Eat 1 port (last elem) for holding firewall mark instance
+ */
+#define MAX_MASQ_FTP_PORTS (MAX_MASQ_APP_PORTS-1)
+#define MAX_MASQ_FTP_PORTS_MODPARM 11
 /* 
  * List of ports (up to MAX_MASQ_APP_PORTS) to be handled by helper
  * First port is set to the default port.
  */
-static int ports[MAX_MASQ_APP_PORTS] = {21}; /* I rely on the trailing items being set to zero */
-struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS];
+static int ports[MAX_MASQ_FTP_PORTS] = {21}; /* I rely on the trailing items being set to zero */
+static struct ip_masq_app *masq_ftp_objs[MAX_MASQ_APP_PORTS];
+
+/*
+ * 	in (forwarded) ports
+ */
+static int in_ports[MAX_MASQ_FTP_PORTS] = {0}; 
+static struct ip_masq_app *masq_in_ftp_objs[MAX_MASQ_APP_PORTS];
+
+#define masq_ftp_mark masq_ftp_objs[MAX_MASQ_APP_PORTS-1]
+#define masq_in_ftp_mark masq_in_ftp_objs[MAX_MASQ_APP_PORTS-1]
 
 /*
  * List of ports (up to MAX_MASQ_APP_PORTS) we don't allow ftp-data 
  * connections to.  Default is to block connections to port 6000 (X servers).
  * This is in addition to all ports under 1024.
  */
-static int noport[MAX_MASQ_APP_PORTS] = {6000, 0}; /* I rely on the trailing items being set to zero */
+static int noport[MAX_MASQ_FTP_PORTS] = {6000, 0}; /* I rely on the trailing items being set to zero */
 
 /*
+ *	Firewall marks for "normal" and "forw" cases
+ */
+static int mark=0;
+static int in_mark=0;
+/*
  *	Debug level
  */
 #ifdef CONFIG_IP_MASQ_DEBUG
@@ -89,12 +132,56 @@
 MODULE_PARM(debug, "i");
 #endif
 
-MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
-MODULE_PARM(noport, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
+MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_FTP_PORTS_MODPARM) "i");
+MODULE_PARM(in_ports, "1-" __MODULE_STRING(MAX_MASQ_FTP_PORTS_MODPARM) "i");
+MODULE_PARM(noport, "1-" __MODULE_STRING(MAX_MASQ_FTP_PORTS_MODPARM) "i");
+MODULE_PARM(mark, "i");
+MODULE_PARM(in_mark, "i");
 
 /*	Dummy variable */
 static int masq_ftp_pasv;
 
+/*
+ * This function parses the IP address and Port number found in PORT commands
+ * and PASV responses.  This used to be done in-line, but with four cases it
+ * seemed worth encapsulating.  It returns the IP address, or zero if an
+ * error is detected.
+ */
+static __u32 parse_ip_port( char **datap, __u16 *portp )
+{
+	char	*data = *datap;
+#if CONFIG_IP_MASQ_DEBUG
+	char *data0=data;
+#endif
+	unsigned char p1,p2,p3,p4,p5,p6;
+
+	p1 = simple_strtoul(data, &data, 10);
+	if (*data != ',')
+		return 0;
+	p2 = simple_strtoul(data+1, &data, 10);
+	if (*data != ',')
+		return 0;
+	p3 = simple_strtoul(data+1, &data, 10);
+	if (*data != ',')
+		return 0;
+	p4 = simple_strtoul(data+1, &data, 10);
+	if (*data != ',')
+		return 0;
+	p5 = simple_strtoul(data+1, &data, 10);
+	if (*data != ',')
+		return 0;
+	p6 = simple_strtoul(data+1, &data, 10);
+
+	IP_MASQ_DEBUG(2-debug, "FTP: parse_ip_port() Ok: \"%*s\" size=%d\n",	
+			data-data0,
+			data0,
+			data-data0);
+	*datap = data;
+	*portp = (p5<<8) | p6;
+	return (p1<<24) | (p2<<16) | (p3<<8) | p4;
+}
+
+
 static int
 masq_ftp_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
 {
@@ -109,138 +196,221 @@
         return 0;
 }
 
+
+static int masq_ftp_unsafe(__u32 from_ip, __u16 from_port) {
+	int i;
+	if (from_port < 1024) 
+	{
+		IP_MASQ_DEBUG(1-debug, "Unsafe PORT %d.%d.%d.%d:%d detected, ignored\n",NIPQUAD(from_ip),from_port);
+		return 1;
+	}
+
+	for (i = 0; (i < MAX_MASQ_FTP_PORTS) && (noport[i]); i++)
+		if (from_port == noport[i])
+		{
+			IP_MASQ_DEBUG(1-debug, "Unsafe (module parm) PORT %d.%d.%d.%d:%d detected, ignored\n",NIPQUAD(from_ip),from_port);
+			return 1;
+		}
+	return 0;
+}
+/*
+ * carefully compare with any of these 2 strings, eating stream pointer
+ * as it proceeds
+ * Returns:
+ * 	NULL	not matched
+ * 	!NULL	last matched char*
+ */
+static char* safe_mem_eq2(char *data, const char *data_limit, int size, const char *str1, const char *str2) {
+#if CONFIG_IP_MASQ_DEBUG
+	const char *data0=data;
+	if (!data) {
+		IP_MASQ_ERR("FTP: NULL data passed to safe_mem_eq2()!!!");
+		return NULL;
+	}
+#endif
+	IP_MASQ_DEBUG(3-debug, "FTP: safe_mem_equal(): datalimit-data=%d, size=%d\n", data_limit-data, size);
+
+	/*	No point in going after data_limit for "size" comparison */
+	data_limit -= size;
+
+	while (data <= data_limit) {
+		if (memcmp(data,str1,size)==0) 
+			goto equal_ok;
+		if (str2 && memcmp(data,str2,size)==0) 
+			goto equal_ok;
+		data++;
+	}
+	IP_MASQ_DEBUG(2-debug, "FTP: safe_mem_equal(): \"%s\" not matched)\n", str1);
+	return NULL;
+equal_ok:
+	IP_MASQ_DEBUG(2-debug, "FTP: safe_mem_equal(): \"%s\" matched at offset %d\n",
+				str1, data-data0);
+	return data+size;
+}
 int
 masq_ftp_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
 {
         struct sk_buff *skb;
 	struct iphdr *iph;
 	struct tcphdr *th;
-	char *p, *data, *data_limit;
-	unsigned char p1,p2,p3,p4,p5,p6;
-	__u32 from;
+	char *p, *data, *data0, *data_limit;
+	__u32 from=0;
+	__u32 from_n;
 	__u16 port;
 	struct ip_masq *n_ms;
-	char buf[24];		/* xxx.xxx.xxx.xxx,ppp,ppp\000 */
+	char buf[25];		/* xxx.xxx.xxx.xxx,ppp,ppp)\000 */
+        unsigned flags=0;    	/* processing flags */
         unsigned buf_len;
-	int diff, i, unsafe;
+	int diff=0;
+
+	/*	Only useful for established  sessions */
+	if (ms->state != IP_MASQ_S_ESTABLISHED) 
+		return 0;
 
         skb = *skb_p;
 	iph = skb->nh.iph;
         th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
-        data = (char *)&th[1];
+        data = (char *)th + (((struct tcphdr*)th)->doff << 2);
+	data0 = data;
+        data_limit = skb->h.raw + skb->len;
+
+	IP_MASQ_DEBUG(2-debug, "FTP: called masq_ftp_out() for type=0x%x datasize=%d\n",
+			mapp->type,
+			data_limit-data);
 
-        data_limit = skb->h.raw + skb->len - 18;
-        if (skb->len >= 6 && (memcmp(data, "PASV\r\n", 6) == 0 || memcmp(data, "pasv\r\n", 6) == 0))
-		ms->app_data = &masq_ftp_pasv;
+	/*	Only useful for actual data 	*/
+	if (data_limit<=data)
+		return 0;
 
-	while (data < data_limit)
-	{
-		if (memcmp(data,"PORT ",5) && memcmp(data,"port ",5))
-		{
-			data ++;
-			continue;
+	/*
+	 * 	We are about to hack an OUT (from firewall) packet,
+	 *	check if 
+	 *		OUTBOUND: 	internal client stream
+	 *		INBOUND: 	internal server stream
+	 */
+	
+	if (IP_MASQ_APP_TYPE2FLAGS(mapp->type)&IP_MASQ_APP_OUTBOUND) {
+		IP_MASQ_DEBUG(1-debug, "FTP: in->out client stream\n");
+
+		/* 
+		 * Minimum sizes ...
+		 *              PORT x,x,x,x,y,y+...  + \r\n
+		 *                   <---------- 11   + 2 = 13
+		 */
+		if (!(data=safe_mem_eq2(data, data_limit-_N(13),
+				5, "PORT ", "port ")) ) {
+			if (safe_mem_eq2(data0, data_limit, 6, "PASV\r\n", "pasv\r\n")) {
+				/*	Flags this tunnel as pasv, return */
+				ms->app_data = &masq_ftp_pasv;
+			}
+			return 0;
 		}
-		p = data+5;
- 		p1 = simple_strtoul(data+5,&data,10);
-		if (*data!=',')
-			continue;
-		p2 = simple_strtoul(data+1,&data,10);
-		if (*data!=',')
-			continue;
-		p3 = simple_strtoul(data+1,&data,10);
-		if (*data!=',')
-			continue;
-		p4 = simple_strtoul(data+1,&data,10);
-		if (*data!=',')
-			continue;
-		p5 = simple_strtoul(data+1,&data,10);
-		if (*data!=',')
-			continue;
-		p6 = simple_strtoul(data+1,&data,10);
-		if (*data!='\r' && *data!='\n')
-			continue;
+		p = data;
+		from = parse_ip_port(&data, &port);
+		if (masq_ftp_unsafe(from,port)) 
+			return 0;
+		IP_MASQ_DEBUG(1-debug,"FTP: out: PORT %d.%d.%d.%d:%d detected\n",
+				NIPQUAD(from), port);
 
-		from = (p1<<24) | (p2<<16) | (p3<<8) | p4;
-		port = (p5<<8) | p6;
+	} else if (IP_MASQ_APP_TYPE2FLAGS(mapp->type)&IP_MASQ_APP_INBOUND) {
+		IP_MASQ_DEBUG(1-debug, "FTP: in->out server stream\n");
 
-		if (port < 1024) 
-		{
-			IP_MASQ_DEBUG(1-debug, "Unsafe PORT %X:%X detected, ignored\n",from,port);
-			continue;
-		}
+		/* 
+		 * Minimum sizes...
+		 *  	Entering Passive Mode (x,x,x,x,y,y)+...  + \r\n
+		 *  	         <------------------------- 26   + 2 = 28
+		 *  	                 <----------------- 18   + 2 = 20
+		 *  	                      <------------ 13   + 2 = 15
+		 */
+		if (!(data=safe_mem_eq2(data, data_limit-_N(28), 8, "ntering ", "NTERING ")))
+			return 0;
+		if (!(data=safe_mem_eq2(data+_N(1), data_limit-_N(20), 7, "assive ", "ASSIVE ")))
+			return 0;
+		if (!(data=safe_mem_eq2(data+_N(1), data_limit-_N(15), 4, "ode ", "ODE ")))
+			return 0;
+		do {
+			if (data >= data_limit)
+				return 0;
+		} while (*data++ != '(');
 
-		for (unsafe = i = 0; (i < MAX_MASQ_APP_PORTS) && (noport[i]); i++)
-		  if (port == noport[i])
-		{
-			IP_MASQ_DEBUG(1-debug, "Unsafe PORT %X:%X detected, ignored\n",from,port);
-			unsafe = 1;
-		}
-		if (unsafe) continue;
+		p = data;
+		from = parse_ip_port(&data, &port);
+		if ((from == 0) || (*data++ !=')'))
+			return 0;
 
-		IP_MASQ_DEBUG(1-debug, "PORT %X:%X detected\n",from,port);
+ 		flags |= IP_MASQ_FTP_RPAREN;
 
-		/*
-		 * Now update or create an masquerade entry for it
-		 */
+	}  else 
+		return 0; 
 
-		IP_MASQ_DEBUG(1-debug, "protocol %d %lX:%X %X:%X\n", iph->protocol, htonl(from), htons(port), iph->daddr, 0);
+	/* no from detected, give up */
+	if (from == 0)
+		return 0;
 
-		n_ms = ip_masq_out_get(iph->protocol,
-					 htonl(from), htons(port),
-					 iph->daddr, 0);
-		if (!n_ms) {
-			n_ms = ip_masq_new(IPPROTO_TCP,
-					   maddr, 0,
-					   htonl(from), htons(port),
-					   iph->daddr, 0,
-					   IP_MASQ_F_NO_DPORT);
+	/* store from in network byte order */
+	from_n = htonl(from);
+	/*
+	 * Now update or create an masquerade entry for it
+	 */
 
-			if (n_ms==NULL)
-				return 0;
-			ip_masq_control_add(n_ms, ms);
-		}
+	IP_MASQ_DEBUG(1-debug, "FTP: out: %d.%d.%d.%d:%d -> %d.%d.%d.%d:%d\n", 
+			NIPQUAD(from_n), htons(port), 
+			NIPQUAD(iph->daddr), 0);
 
-		/*
-		 * Replace the old PORT with the new one
-		 */
-		from = ntohl(n_ms->maddr);
-		port = ntohs(n_ms->mport);
-		sprintf(buf,"%d,%d,%d,%d,%d,%d",
-			from>>24&255,from>>16&255,from>>8&255,from&255,
-			port>>8&255,port&255);
-		buf_len = strlen(buf);
+	n_ms = ip_masq_out_get(iph->protocol,
+				 from_n, htons(port),
+				 iph->daddr, 0);
+	if (!n_ms) {
+		n_ms = ip_masq_new(IPPROTO_TCP,
+				   maddr, 0,
+				   from_n, htons(port),
+				   iph->daddr, 0,
+				   IP_MASQ_F_NO_DPORT);
 
-		IP_MASQ_DEBUG(1-debug, "new PORT %X:%X\n",from,port);
+		if (n_ms==NULL)
+			return 0;
+		ip_masq_control_add(n_ms, ms);
+	}
 
-		/*
-		 * Calculate required delta-offset to keep TCP happy
-		 */
-		
-		diff = buf_len - (data-p);
-		
-		/*
-		 *	No shift.
-		 */
-		
-		if (diff==0) {
-			/*
-			 * simple case, just replace the old PORT cmd
- 			 */
- 			memcpy(p,buf,buf_len);
- 		} else {
+	/*
+	 * Replace the old PORT with the new one
+	 */
+	from = ntohl(n_ms->maddr);
+	port = ntohs(n_ms->mport);
+	sprintf(buf,"%d,%d,%d,%d,%d,%d%c",
+		from>>24&255,from>>16&255,from>>8&255,from&255,
+		port>>8&255,port&255,
+		(flags&IP_MASQ_FTP_RPAREN)? ')':0);
+	buf_len = strlen(buf);
 
-			*skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC, p, data-p, buf, buf_len);
-		}
-                /*
-                 * 	Move tunnel to listen state
-                 */
-		ip_masq_listen(n_ms);
-		ip_masq_put(n_ms);
+	IP_MASQ_DEBUG(1-debug, "FTP: new PORT %d.%d.%d.%d:%d\n",NIPQUAD(maddr),port);
+
+	/*
+	 * Calculate required delta-offset to keep TCP happy
+	 */
+
+	diff = buf_len - (data-p);
+
+	/*
+	 *	No shift.
+	 */
 
-                return diff;
+	if (diff==0) {
+		/*
+		 * simple case, just replace the old PORT cmd
+		 */
+		memcpy(p,buf,buf_len);
+	} else {
 
+		*skb_p = ip_masq_skb_replace(skb, GFP_ATOMIC, p, data-p, buf, buf_len);
 	}
-	return 0;
+	/*
+	 * 	Move tunnel to listen state
+	 */
+	ip_masq_listen(n_ms);
+	ip_masq_put(n_ms);
+
+	return diff;
 
 }
 
@@ -269,53 +439,92 @@
 	struct iphdr *iph;
 	struct tcphdr *th;
 	char *data, *data_limit;
-	unsigned char p1,p2,p3,p4,p5,p6;
 	__u32 to;
+	__u32 from_n;
 	__u16 port;
 	struct ip_masq *n_ms;
 
-	if (ms->app_data != &masq_ftp_pasv)
-		return 0;	/* quick exit if no outstanding PASV */
+	/*	Only useful for established  sessions */
+	if (ms->state != IP_MASQ_S_ESTABLISHED) 
+		return 0;
 
 	skb = *skb_p;
 	iph = skb->nh.iph;
 	th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
-	data = (char *)&th[1];
+        data = (char *)th + (((struct tcphdr*)th)->doff << 2);
 	data_limit = skb->h.raw + skb->len;
 
-	while (data < data_limit && *data != ' ')
-		++data;	
-	while (data < data_limit && *data == ' ')
-		++data;	
-	data += 22;
-	if (data >= data_limit || *data != '(')
-		return 0;
-	p1 = simple_strtoul(data+1, &data, 10);
-	if (data >= data_limit || *data != ',')
-		return 0;
-	p2 = simple_strtoul(data+1, &data, 10);
-	if (data >= data_limit || *data != ',')
-		return 0;
-	p3 = simple_strtoul(data+1, &data, 10);
-	if (data >= data_limit || *data != ',')
-		return 0;
-	p4 = simple_strtoul(data+1, &data, 10);
-	if (data >= data_limit || *data != ',')
-		return 0;
-	p5 = simple_strtoul(data+1, &data, 10);
-	if (data >= data_limit || *data != ',')
-		return 0;
-	p6 = simple_strtoul(data+1, &data, 10);
-	if (data >= data_limit || *data != ')')
+	IP_MASQ_DEBUG(2-debug, "FTP: called masq_ftp_in() for type=0x%x datasize=%d\n", 
+			mapp->type,
+			data_limit-data);
+
+	/*	Only useful for actual data 	*/
+	if (data_limit<=data)
 		return 0;
 
-	to = (p1<<24) | (p2<<16) | (p3<<8) | p4;
-	port = (p5<<8) | p6;
+	/*
+	 * 	We are about to hack an IN (to firewall) packet,
+	 *	check if 
+	 *		OUTBOUND: 	internal client stream
+	 *		INBOUND: 	internal server stream
+	 */
+
+	if (IP_MASQ_APP_TYPE2FLAGS(mapp->type)&IP_MASQ_APP_OUTBOUND) {
+		IP_MASQ_DEBUG(1-debug, "FTP: out->in client stream\n");
+		/* 	
+		 * 	For OUTBOUND only parse on input for linking PASV
+		 * 	data tunnel with control.
+		 * 	Exit quickly if no outstanding PASV 
+		 */
+		if (ms->app_data != &masq_ftp_pasv)
+			return 0;
+
+		/* 
+		 * Minimum sizes...
+		 *  	Entering Passive Mode (x,x,x,x,y,y)+...  + \r\n
+		 *  	         <------------------------- 26   + 2 = 28
+		 *  	                 <----------------- 18   + 2 = 20
+		 *  	                      <------------ 13   + 2 = 15
+		 */
+		if (!(data=safe_mem_eq2(data, data_limit-_N(28), 8, "ntering ", "NTERING ")))
+			return 0;
+		if (!(data=safe_mem_eq2(data+_N(1), data_limit-_N(20), 6, "ssive ", "SSIVE ")))
+			return 0;
+		if (!(data=safe_mem_eq2(data+_N(1), data_limit-_N(15), 4, "ode ", "ODE ")))
+			return 0;
+		do {
+			if (data >= data_limit)
+				return 0;
+		} while (*data++ != '(');
+
+		to = parse_ip_port(&data, &port);
+		if (to == 0 || *data != ')')
+			return 0;
+
+		from_n = ntohl(ms->saddr);
+		IP_MASQ_DEBUG(1-debug, "FTP: PASV response %d.%d.%d.%d:%d -> %d.%d.%d.%d:%d detected\n", 
+			NIPQUAD(from_n), 0, 
+			NIPQUAD(to), port);
 
+	} else if (IP_MASQ_APP_TYPE2FLAGS(mapp->type)&IP_MASQ_APP_INBOUND) {
+		IP_MASQ_DEBUG(1-debug, "FTP: out->in server stream\n");
+
+		if (!(data=safe_mem_eq2(data, data_limit-_N(13), 
+				5, "PORT ", "port ")) )
+			return 0;
+		to = parse_ip_port(&data, &port);
+		if (to == 0 || (*data != '\r' && *data != '\n'))
+			return 0;
+
+		from_n = ntohl(ms->saddr);
+		IP_MASQ_DEBUG(1-debug, "FTP: PORT  %d.%d.%d.%d:%d -> %d.%d.%d.%d:%d detected\n", 
+			NIPQUAD(from_n), 0, 
+			NIPQUAD(to), port);
+	} else
+		return 0;
 	/*
 	 * Now update or create an masquerade entry for it
 	 */
-	IP_MASQ_DEBUG(1-debug, "PASV response %lX:%X %X:%X detected\n", ntohl(ms->saddr), 0, to, port);
 
 	n_ms = ip_masq_out_get(iph->protocol,
 				 ms->saddr, 0,
@@ -356,58 +565,120 @@
         masq_ftp_out,           /* pkt_out */
         masq_ftp_in,            /* pkt_in */
 };
-
-/*
- * 	ip_masq_ftp initialization
- */
-
-__initfunc(int ip_masq_ftp_init(void))
+static struct ip_masq_app *make_instance(const struct ip_masq_app *mapp_class, int *err)
 {
-	int i, j;
+	struct ip_masq_app *mapp = NULL;
+	if ((mapp = kmalloc(sizeof(struct ip_masq_app), GFP_KERNEL)))
+		memcpy(mapp , mapp_class, sizeof(struct ip_masq_app));
+	else
+		*err= -ENOMEM;
+	return mapp;
+}
 
-	for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
+/*	
+ *	Register all solicited ports (last array element is
+ * 	reserved for firewall "mark" object
+ */
+static int register_ports(struct ip_masq_app *mapp_instances[], int *ports, unsigned flags) {
+	int i;
+	int err=0;
+	struct ip_masq_app  *mapp;
+	for (i=0; (i<MAX_MASQ_FTP_PORTS_MODPARM); i++) {
 		if (ports[i]) {
-			if ((masq_incarnations[i] = kmalloc(sizeof(struct ip_masq_app),
-							    GFP_KERNEL)) == NULL)
-				return -ENOMEM;
-			memcpy(masq_incarnations[i], &ip_masq_ftp, sizeof(struct ip_masq_app));
-			if ((j = register_ip_masq_app(masq_incarnations[i], 
-						      IPPROTO_TCP, 
-						      ports[i]))) {
-				return j;
-			}
-			IP_MASQ_DEBUG(1-debug, "Ftp: loaded support on port[%d] = %d\n",
-			       i, ports[i]);
+			if (!(mapp = make_instance(&ip_masq_ftp, &err)))
+				goto end;
+			if ((err=ip_masq_app_init_proto_port(mapp, flags, IPPROTO_TCP, ports[i]))) 
+				goto end_kfree;
+
+			if ((err=register_ip_masq_app_type(mapp)))
+				goto end_kfree;
+			mapp_instances[i]=mapp;
+			IP_MASQ_DEBUG(1-debug, "FTP: loaded support on %sport[%d] = %d, type=0x%x\n", 
+					(flags&IP_MASQ_APP_INBOUND)? "in_":"",
+					i, ports[i], mapp->type);
 		} else {
 			/* To be safe, force the incarnation table entry to NULL */
-			masq_incarnations[i] = NULL;
+			mapp_instances[i] = NULL;
 		}
 	}
 	return 0;
+end_kfree:
+	kfree_s(mapp, sizeof(struct ip_masq_app));
+end:
+	IP_MASQ_ERR("FTP: registration error, quitting\n");
+	return err;
 }
-
 /*
- * 	ip_masq_ftp fin.
+ * 	Unregister ALL ports, _including_ the (possible) firewall
+ * 	mark.
  */
-
-int ip_masq_ftp_done(void)
-{
-	int i, j, k;
-
-	k=0;
+static int unregister_ports(struct ip_masq_app *mapp_instances[]) {
+	int i, j, k=0;
 	for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
-		if (masq_incarnations[i]) {
-			if ((j = unregister_ip_masq_app(masq_incarnations[i]))) {
+		if (mapp_instances[i]) {
+			if ((j = unregister_ip_masq_app(mapp_instances[i]))) {
 				k = j;
 			} else {
-				kfree(masq_incarnations[i]);
-				masq_incarnations[i] = NULL;
-				IP_MASQ_DEBUG(1-debug, "Ftp: unloaded support on port[%d] = %d\n",
-				       i, ports[i]);
+				IP_MASQ_DEBUG(1-debug, "FTP: unloaded support on port[%d] = %d, type=0x%x\n",
+				       i, ports[i], mapp_instances[i]->type);
+				kfree(mapp_instances[i]);
+				mapp_instances[i] = NULL;
 			}
 		}
 	}
 	return k;
+}
+
+/*
+ * 	ip_masq_ftp initialization
+ */
+
+__initfunc(int ip_masq_ftp_init(void))
+{
+	int ret=0;
+	struct ip_masq_app *mapp;
+	if (
+	(ret=register_ports(masq_ftp_objs, ports, IP_MASQ_APP_OUTBOUND)) ||
+	(ret=register_ports(masq_in_ftp_objs, in_ports, IP_MASQ_APP_INBOUND))
+	)
+		goto end;
+
+	if (mark) {
+		if (!(mapp=make_instance(&ip_masq_ftp, &ret)))
+			goto end;
+		if ((ret=ip_masq_app_init_fwmark(mapp, IP_MASQ_APP_OUTBOUND, mark))) {
+			kfree_s(mapp, sizeof (struct ip_masq_app));
+			goto end;
+		}
+		if ((ret=register_ip_masq_app_type(mapp)))
+			goto end;
+		masq_ftp_mark=mapp;
+	}
+	if (in_mark) {
+		if (!(mapp=make_instance(&ip_masq_ftp, &ret)))
+			goto end;
+		if ((ret=ip_masq_app_init_fwmark(mapp, IP_MASQ_APP_INBOUND, in_mark))) {
+			kfree_s(mapp, sizeof (struct ip_masq_app));
+			goto end;
+		}
+		if ((ret=register_ip_masq_app_type(mapp)))
+			goto end;
+		masq_in_ftp_mark=mapp;
+	}
+end:
+	return ret;
+}
+
+/*
+ * 	ip_masq_ftp fin.
+ */
+
+int ip_masq_ftp_done(void)
+{
+	int ret;
+	ret = unregister_ports(masq_ftp_objs);
+	ret += unregister_ports(masq_in_ftp_objs);
+	return ret;
 }
 
 #ifdef MODULE
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/ip_masq_mod.c linux.19p18/net/ipv4/ip_masq_mod.c
--- linux.vanilla/net/ipv4/ip_masq_mod.c	Sun Jun 11 21:44:23 2000
+++ linux.19p18/net/ipv4/ip_masq_mod.c	Wed Feb  7 09:45:05 2001
@@ -4,7 +4,7 @@
  *
  * Author:	Juan Jose Ciarlante, <jjciarla@raiz.uncu.edu.ar>
  *
- * 	$Id: ip_masq_mod.c,v 1.5.2.1 1999/07/02 10:10:03 davem Exp $
+ * 	$Id: ip_masq_mod.c,v 1.5.2.3 2001/01/04 04:20:16 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/ip_masq_raudio.c linux.19p18/net/ipv4/ip_masq_raudio.c
--- linux.vanilla/net/ipv4/ip_masq_raudio.c	Fri Apr 21 12:47:14 2000
+++ linux.19p18/net/ipv4/ip_masq_raudio.c	Wed Feb  7 09:45:05 2001
@@ -2,7 +2,7 @@
  *		IP_MASQ_RAUDIO  - Real Audio masquerading module
  *
  *
- * Version:	@(#)$Id: ip_masq_raudio.c,v 1.11 1998/10/06 04:49:04 davem Exp $
+ * Version:	@(#)$Id: ip_masq_raudio.c,v 1.11.2.1 2001/01/10 01:52:33 davem Exp $
  *
  * Author:	Nigel Metheringham
  *		Real Time Streaming code by Progressive Networks
@@ -169,7 +169,10 @@
         skb = *skb_p;
 	iph = skb->nh.iph;
         th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
-        data = (char *)&th[1];
+
+	/* Make sure we take into account the size of the TCP packet.  This is
+	 * because there may be TCP options in the TCP packet */
+	data = ((char *)&th[0]) + (th->doff * 4);
 
         data_limit = skb->h.raw + skb->len;
 
@@ -315,7 +318,10 @@
         skb = *skb_p;
 	iph = skb->nh.iph;
         th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
-        data = (char *)&th[1];
+
+	/* Make sure we take into account the size of the TCP packet.  This is
+	 * because there may be TCP options in the TCP packet */
+	data = ((char *)&th[0]) + (th->doff * 4);
 
         data_limit = skb->h.raw + skb->len;
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/ip_masq_user.c linux.19p18/net/ipv4/ip_masq_user.c
--- linux.vanilla/net/ipv4/ip_masq_user.c	Mon Dec 11 22:13:10 2000
+++ linux.19p18/net/ipv4/ip_masq_user.c	Wed Feb  7 09:45:05 2001
@@ -2,7 +2,7 @@
  *	IP_MASQ_USER user space control module
  *
  *
- *	$Id: ip_masq_user.c,v 1.1.2.4 2000/02/29 23:50:24 davem Exp $
+ *	$Id: ip_masq_user.c,v 1.1.2.6 2001/01/04 04:20:16 davem Exp $
  */
 
 #include <linux/config.h>
@@ -35,7 +35,6 @@
  */
 static int debug=0;
 
-MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
 MODULE_PARM(debug, "i");
 
 /*
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/ip_sockglue.c linux.19p18/net/ipv4/ip_sockglue.c
--- linux.vanilla/net/ipv4/ip_sockglue.c	Fri Apr 21 12:47:15 2000
+++ linux.19p18/net/ipv4/ip_sockglue.c	Thu Feb 15 16:25:39 2001
@@ -636,6 +636,9 @@
 	if(get_user(len,optlen))
 		return -EFAULT;
 
+	if(len < 0)
+		return -EINVAL;
+		
 	switch(optname)
 	{
 		case IP_OPTIONS:
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/ipmr.c linux.19p18/net/ipv4/ipmr.c
--- linux.vanilla/net/ipv4/ipmr.c	Fri Apr 21 12:47:12 2000
+++ linux.19p18/net/ipv4/ipmr.c	Thu Feb 15 16:25:55 2001
@@ -877,6 +877,10 @@
 		return -EFAULT;
 
 	olr=min(olr,sizeof(int));
+	
+	if(olr < 0)
+		return -EINVAL;
+		
 	if(put_user(olr,optlen))
 		return -EFAULT;
 	if(optname==MRT_VERSION)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/raw.c linux.19p18/net/ipv4/raw.c
--- linux.vanilla/net/ipv4/raw.c	Fri Apr 21 12:47:15 2000
+++ linux.19p18/net/ipv4/raw.c	Thu Feb 15 16:26:20 2001
@@ -497,6 +497,8 @@
 
 	if (get_user(len,optlen))
 		return -EFAULT;
+	if (len < 0)
+		return -EINVAL;
 	if (len > sizeof(struct icmp_filter))
 		len = sizeof(struct icmp_filter);
 	if (put_user(len, optlen))
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/route.c linux.19p18/net/ipv4/route.c
--- linux.vanilla/net/ipv4/route.c	Mon Dec 11 22:13:10 2000
+++ linux.19p18/net/ipv4/route.c	Wed Feb  7 10:03:24 2001
@@ -1927,7 +1927,7 @@
 		return -EINVAL;
 }
 
-static int ipv4_sysctl_rtcache_flush_strategy(ctl_table *table, int *name, int nlen,
+static int ipv4_sysctl_rtcache_flush_strategy(ctl_table *table, int *name, unsigned nlen,
 			 void *oldval, size_t *oldlenp,
 			 void *newval, size_t newlen, 
 			 void **context)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/sysctl_net_ipv4.c linux.19p18/net/ipv4/sysctl_net_ipv4.c
--- linux.vanilla/net/ipv4/sysctl_net_ipv4.c	Mon Dec 11 22:13:10 2000
+++ linux.19p18/net/ipv4/sysctl_net_ipv4.c	Wed Feb  7 10:03:24 2001
@@ -87,7 +87,7 @@
 	return ret;
 }
 
-static int ipv4_sysctl_forward_strategy(ctl_table *table, int *name, int nlen,
+static int ipv4_sysctl_forward_strategy(ctl_table *table, int *name, unsigned nlen,
 			 void *oldval, size_t *oldlenp,
 			 void *newval, size_t newlen, 
 			 void **context)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/tcp.c linux.19p18/net/ipv4/tcp.c
--- linux.vanilla/net/ipv4/tcp.c	Mon Dec 11 22:13:10 2000
+++ linux.19p18/net/ipv4/tcp.c	Thu Feb 15 16:27:02 2001
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp.c,v 1.140.2.15 2000/10/06 23:29:33 davem Exp $
+ * Version:	$Id: tcp.c,v 1.140.2.16 2001/01/04 05:28:46 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -1619,6 +1619,7 @@
 	struct wait_queue wait = { current, NULL };
 	struct open_request *req;
 
+	current->task_exclusive = 1;
 	add_wait_queue(sk->sleep, &wait);
 	for (;;) {
 		current->state = TASK_INTERRUPTIBLE;
@@ -1632,6 +1633,8 @@
 			break;
 	}
 	current->state = TASK_RUNNING;
+	wmb();
+	current->task_exclusive = 0;
 	remove_wait_queue(sk->sleep, &wait);
 	return req;
 }
@@ -1776,6 +1779,9 @@
 		return -EFAULT;
 
 	len = min(len, sizeof(int));
+	
+	if(len < 0)
+		return -EINVAL;
 
 	switch(optname) {
 	case TCP_MAXSEG:
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/tcp_input.c linux.19p18/net/ipv4/tcp_input.c
--- linux.vanilla/net/ipv4/tcp_input.c	Mon Dec 11 22:13:10 2000
+++ linux.19p18/net/ipv4/tcp_input.c	Sat Mar 10 23:09:42 2001
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_input.c,v 1.164.2.18 2000/12/08 20:29:33 davem Exp $
+ * Version:	$Id: tcp_input.c,v 1.164.2.21 2001/03/06 05:39:39 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -246,26 +246,22 @@
 }
 
 
-static int __tcp_sequence(struct tcp_opt *tp, u32 seq, u32 end_seq)
+/* Check segment sequence number for validity.
+ *
+ * Segment controls are considered valid, if the segment
+ * fits to the window after truncation to the window. Acceptability
+ * of data (and SYN, FIN, of course) is checked separately.
+ * See tcp_data_queue(), for example.
+ *
+ * Also, controls (RST is main one) are accepted using last_ack_sent instead
+ * of RCV.NXT. Peer still did not advance his SND.UNA when we
+ * delayed ACK, so that hisSND.UNA<=last_ack_sent.
+ * (borrowed from freebsd)
+ */
+static inline int tcp_sequence(struct tcp_opt *tp, u32 seq, u32 end_seq)
 {
-	u32 end_window = tp->rcv_wup + tp->rcv_wnd;
-
-	if (tp->rcv_wnd &&
-	    after(end_seq, tp->rcv_nxt) &&
-	    before(seq, end_window))
-		return 1;
-	if (seq != end_window)
-		return 0;
-	return (seq == end_seq);
-}
-
-/* This functions checks to see if the tcp header is actually acceptable. */
-extern __inline__ int tcp_sequence(struct tcp_opt *tp, u32 seq, u32 end_seq)
-{
-	if (seq == tp->rcv_nxt)
-		return (tp->rcv_wnd || (end_seq == seq));
-
-	return __tcp_sequence(tp, seq, end_seq);
+	return	!before(end_seq, tp->last_ack_sent) &&
+		!after(seq, tp->rcv_nxt + tcp_receive_window(tp));
 }
 
 /* When we get a reset we do this. */
@@ -1415,6 +1411,11 @@
 	if (TCP_SKB_CB(skb)->seq == tp->rcv_nxt) {
 		/* Ok. In sequence. */
 	queue_and_out:
+		if (tcp_receive_window(tp) == 0)
+			goto out_of_window;
+
+		/* We know it is in window now too. */
+
 		dst_confirm(sk->dst_cache);
 		__skb_queue_tail(&sk->receive_queue, skb);
 		tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
@@ -1441,6 +1442,8 @@
 		/* A retransmit, 2nd most common case.  Force an imediate ack. */
 		SOCK_DEBUG(sk, "retransmit received: seq %X\n", TCP_SKB_CB(skb)->seq);
 		tcp_enter_quickack_mode(tp);
+out_of_window:
+		tp->delayed_acks++;
 		kfree_skb(skb);
 		return;
 	}
@@ -1454,6 +1457,16 @@
 		goto queue_and_out;
 	}
 
+	/* Out of window. F.e. zero window probe.
+	 *
+	 * Note: it is highly possible that we may open window and enqueue
+	 * this segment now. However, this will be known only after we queue
+	 * it, which will result in queue full of successive 1 byte BSD
+	 * window probes, it is SWS in fact. So, always reject it and send ACK.
+	 */
+	if (!before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt+tcp_receive_window(tp)))
+		goto out_of_window;
+
 	/* Ok. This is an out_of_order segment, force an ack. */
 	tp->delayed_acks++;
 	tcp_enter_quickack_mode(tp);
@@ -1671,6 +1684,9 @@
 	if (after(tp->copied_seq, ptr))
 		return;
 
+	if (before(ptr, tp->rcv_nxt))
+		return;
+
 	/* Do we already have a newer (or duplicate) urgent pointer? */
 	if (tp->urg_data && !after(ptr, tp->urg_seq))
 		return;
@@ -1689,8 +1705,10 @@
 	 * as data, nor can we alter copied_seq until this data arrives
 	 * or we break the sematics of SIOCATMARK (and thus sockatmark())
 	 */
-	if (tp->urg_seq == tp->copied_seq)
-		tp->copied_seq++;	/* Move the copied sequence on correctly */
+	if (tp->urg_seq == tp->copied_seq && tp->urg_data &&
+	    !sk->urginline &&
+	    tp->copied_seq != tp->rcv_nxt)
+		tp->copied_seq++;
 	tp->urg_data = URG_NOTYET;
 	tp->urg_seq = ptr;
 
@@ -1709,7 +1727,7 @@
 
 	/* Do we wait for any urgent data? - normally not... */
 	if (tp->urg_data == URG_NOTYET) {
-		u32 ptr = tp->urg_seq - ntohl(th->seq) + (th->doff*4);
+		u32 ptr = tp->urg_seq - ntohl(th->seq) + (th->doff*4) - th->syn;
 
 		/* Is the urgent pointer pointing into this packet? */	 
 		if (ptr < len) {
@@ -2197,6 +2215,7 @@
 			tp->snd_wnd = htons(th->window);
 			tp->snd_wl1 = TCP_SKB_CB(skb)->seq;
 			tp->snd_wl2 = TCP_SKB_CB(skb)->ack_seq;
+			tp->syn_seq = TCP_SKB_CB(skb)->seq;
 			tp->fin_seq = TCP_SKB_CB(skb)->seq;
 
 			tcp_set_state(sk, TCP_ESTABLISHED);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/tcp_ipv4.c linux.19p18/net/ipv4/tcp_ipv4.c
--- linux.vanilla/net/ipv4/tcp_ipv4.c	Mon Dec 11 22:13:10 2000
+++ linux.19p18/net/ipv4/tcp_ipv4.c	Wed Feb  7 09:45:05 2001
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_ipv4.c,v 1.175.2.17 2000/10/31 22:42:58 davem Exp $
+ * Version:	$Id: tcp_ipv4.c,v 1.175.2.18 2001/02/02 01:27:08 davem Exp $
  *
  *		IPv4 specific functions
  *
@@ -1109,6 +1109,8 @@
 	struct tcphdr *th = (struct tcphdr *)(skb->nh.raw + iph->ihl*4);
 	struct sock *sk;
 
+	if (ntohs(iph->tot_len) - iph->ihl*4 < sizeof(struct tcphdr))
+		return 0;
 	sk = tcp_v4_lookup(iph->saddr, th->source, iph->daddr,
 			   th->dest, skb->dev->ifindex);
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv4/udp.c linux.19p18/net/ipv4/udp.c
--- linux.vanilla/net/ipv4/udp.c	Sun Jun 11 21:44:24 2000
+++ linux.19p18/net/ipv4/udp.c	Wed Feb  7 09:45:05 2001
@@ -5,7 +5,7 @@
  *
  *		The User Datagram Protocol (UDP).
  *
- * Version:	$Id: udp.c,v 1.66.2.4 2000/03/10 00:16:05 davem Exp $
+ * Version:	$Id: udp.c,v 1.66.2.6 2001/02/02 01:27:09 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -159,7 +159,7 @@
 		next:
 		}
 		result = best;
-		for(;; result += UDP_HTABLE_SIZE) {
+		for(i = 0; i < (1 << 16)/UDP_HTABLE_SIZE; i++, result += UDP_HTABLE_SIZE) {
 			if (result > sysctl_local_port_range[1])
 				result = sysctl_local_port_range[0]
 					+ ((result - sysctl_local_port_range[0]) &
@@ -167,6 +167,8 @@
 			if (!udp_lport_inuse(result))
 				break;
 		}
+		if (i >= (1 << 16) / UDP_HTABLE_SIZE)
+			goto fail;
 gotit:
 		udp_port_rover = snum = result;
 	} else {
@@ -1044,6 +1046,8 @@
 	struct udphdr *uh = (struct udphdr *)(skb->nh.raw + iph->ihl*4);
 	struct sock *sk;
 
+	if (ntohs(iph->tot_len) - iph->ihl*4 < sizeof(struct udphdr))
+		return 0;
 	sk = udp_v4_lookup(iph->saddr, uh->source, iph->daddr, uh->dest, skb->dev->ifindex);
 	if (!sk)
 		return 0;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv6/ipv6_sockglue.c linux.19p18/net/ipv6/ipv6_sockglue.c
--- linux.vanilla/net/ipv6/ipv6_sockglue.c	Fri Apr 21 12:47:16 2000
+++ linux.19p18/net/ipv6/ipv6_sockglue.c	Fri Feb 16 09:08:49 2001
@@ -230,6 +230,10 @@
 
 		if (optlen == 0)
 			goto update;
+		
+		retv = -EINVAL;
+		if(optlen > 1024)
+			break;
 
 		opt = sock_kmalloc(sk, sizeof(*opt) + optlen, GFP_KERNEL);
 		retv = -ENOBUFS;
@@ -359,6 +363,8 @@
 		return -ENOPROTOOPT;
 	if (get_user(len, optlen))
 		return -EFAULT;
+	if(len < 0)
+		return -EINVAL;
 	switch (optname) {
 	case IPV6_PKTOPTIONS:
 	{
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipv6/raw.c linux.19p18/net/ipv6/raw.c
--- linux.vanilla/net/ipv6/raw.c	Fri Apr 21 12:47:16 2000
+++ linux.19p18/net/ipv6/raw.c	Thu Feb 15 16:28:31 2001
@@ -492,6 +492,8 @@
 	case ICMPV6_FILTER:
 		if (get_user(len, optlen))
 			return -EFAULT;
+		if (len < 0)
+			return -EINVAL;
 		if (len > sizeof(struct icmp6_filter))
 			len = sizeof(struct icmp6_filter);
 		if (put_user(len, optlen))
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/ipx/af_ipx.c linux.19p18/net/ipx/af_ipx.c
--- linux.vanilla/net/ipx/af_ipx.c	Mon Dec 11 22:13:10 2000
+++ linux.19p18/net/ipx/af_ipx.c	Thu Feb 15 16:29:06 2001
@@ -1769,6 +1769,10 @@
 		return (-EFAULT);
 
 	len = min(len, sizeof(int));
+	
+	if(len < 0)
+		return -EINVAL;
+		
 	if(put_user(len, optlen))
 		return (-EFAULT);
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/irda/af_irda.c linux.19p18/net/irda/af_irda.c
--- linux.vanilla/net/irda/af_irda.c	Sat Sep  9 18:42:51 2000
+++ linux.19p18/net/irda/af_irda.c	Thu Feb 15 16:29:30 2001
@@ -1842,6 +1842,9 @@
 	if (get_user(len, optlen))
 		return -EFAULT;
 
+	if (len < 0)
+		return -EINVAL;
+		
 	switch (optname) {
 	case IRLMP_ENUMDEVICES:
 		/* Tell IrLMP we want to be notified */
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/netrom/af_netrom.c linux.19p18/net/netrom/af_netrom.c
--- linux.vanilla/net/netrom/af_netrom.c	Fri Apr 21 12:47:17 2000
+++ linux.19p18/net/netrom/af_netrom.c	Thu Feb 15 16:30:01 2001
@@ -407,6 +407,9 @@
 	if (get_user(len, optlen))
 		return -EFAULT;
 
+	if (len < 0)
+		return -EINVAL;
+		
 	switch (optname) {
 		case NETROM_T1:
 			val = sk->protinfo.nr->t1 / HZ;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/netsyms.c linux.19p18/net/netsyms.c
--- linux.vanilla/net/netsyms.c	Mon Dec 11 22:13:10 2000
+++ linux.19p18/net/netsyms.c	Wed Dec 13 21:48:45 2000
@@ -208,7 +208,7 @@
 
 /* Needed by unix.o */
 EXPORT_SYMBOL(scm_fp_dup);
-EXPORT_SYMBOL(max_files);
+EXPORT_SYMBOL(files_stat);
 EXPORT_SYMBOL(do_mknod);
 EXPORT_SYMBOL(memcpy_toiovec);
 EXPORT_SYMBOL(csum_partial);
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/rose/af_rose.c linux.19p18/net/rose/af_rose.c
--- linux.vanilla/net/rose/af_rose.c	Fri Apr 21 12:47:17 2000
+++ linux.19p18/net/rose/af_rose.c	Thu Feb 15 16:30:21 2001
@@ -471,6 +471,9 @@
 		
 	if (get_user(len, optlen))
 		return -EFAULT;
+		
+	if (len < 0)
+		return -EINVAL;
 	
 	switch (optname) {
 		case ROSE_DEFER:
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/sched/cls_u32.c linux.19p18/net/sched/cls_u32.c
--- linux.vanilla/net/sched/cls_u32.c	Fri Apr 21 12:47:17 2000
+++ linux.19p18/net/sched/cls_u32.c	Wed Feb  7 09:45:06 2001
@@ -254,7 +254,7 @@
 	do {
 		if (++tp_c->hgenerator == 0x7FF)
 			tp_c->hgenerator = 1;
-	} while (i>0 && u32_lookup_ht(tp_c, (tp_c->hgenerator|0x800)<<20));
+	} while (--i>0 && u32_lookup_ht(tp_c, (tp_c->hgenerator|0x800)<<20));
 
 	return i > 0 ? (tp_c->hgenerator|0x800)<<20 : 0;
 }
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/socket.c linux.19p18/net/socket.c
--- linux.vanilla/net/socket.c	Mon Dec 11 22:13:10 2000
+++ linux.19p18/net/socket.c	Thu Feb 15 16:23:49 2001
@@ -1048,7 +1048,10 @@
 {
 	int err;
 	struct socket *sock;
-	
+
+	if(optlen < 0)	
+		return -EINVAL;
+		
 	lock_kernel();
 	if ((sock = sockfd_lookup(fd, &err))!=NULL)
 	{
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/sunrpc/Makefile linux.19p18/net/sunrpc/Makefile
--- linux.vanilla/net/sunrpc/Makefile	Fri Apr 21 12:47:17 2000
+++ linux.19p18/net/sunrpc/Makefile	Mon Feb 12 14:50:24 2001
@@ -11,7 +11,7 @@
 O_OBJS   := clnt.o xprt.o sched.o \
 	    auth.o auth_null.o auth_unix.o \
 	    svc.o svcsock.o svcauth.o \
-	    pmap_clnt.o xdr.o sysctl.o
+	    pmap_clnt.o ping.o xdr.o sysctl.o
 OX_OBJS  := sunrpc_syms.o
 
 ifeq ($(CONFIG_PROC_FS),y)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/sunrpc/clnt.c linux.19p18/net/sunrpc/clnt.c
--- linux.vanilla/net/sunrpc/clnt.c	Mon Dec 11 22:13:10 2000
+++ linux.19p18/net/sunrpc/clnt.c	Mon Feb 12 14:50:24 2001
@@ -55,8 +55,8 @@
 static void	call_refreshresult(struct rpc_task *task);
 static void	call_timeout(struct rpc_task *task);
 static void	call_reconnect(struct rpc_task *task);
-static u32 *	call_header(struct rpc_task *task);
-static u32 *	call_verify(struct rpc_task *task);
+static void	call_ping(struct rpc_task *task);
+static void	call_pingresult(struct rpc_task *task);
 
 
 /*
@@ -487,7 +487,7 @@
 
 	/* Encode header and provided arguments */
 	encode = rpcproc_encode(clnt, task->tk_msg.rpc_proc);
-	if (!(p = call_header(task))) {
+	if (!(p = rpc_call_header(task))) {
 		printk(KERN_INFO "RPC: call_header failed, exit EIO\n");
 		rpc_exit(task, -EIO);
 	} else
@@ -592,11 +592,10 @@
 			task->tk_action = call_reconnect;
 			break;
 		}
-		/*
-		 * Sleep and dream of an open connection
-		 */
-		task->tk_timeout = 5 * HZ;
-		rpc_sleep_on(&xprt->sending, task, NULL, NULL);
+		if (RPCXPRT_SUPERCONGESTED(clnt->cl_xprt)) {
+			task->tk_action = call_ping;
+			break;
+		}
 	case -ENOMEM:
 	case -EAGAIN:
 		task->tk_action = call_transmit;
@@ -620,6 +619,7 @@
 {
 	struct rpc_clnt	*clnt = task->tk_client;
 	struct rpc_rqst	*req = task->tk_rqstp;
+	int major = 0;
 
 	if (req) {
 		struct rpc_timeout *to = &req->rq_timeout;
@@ -644,16 +644,7 @@
 		rpc_exit(task, -EIO);
 		return;
 	}
-
-	if (clnt->cl_chatty && !(task->tk_flags & RPC_CALL_MAJORSEEN)) {
-		task->tk_flags |= RPC_CALL_MAJORSEEN;
-		printk(KERN_NOTICE "%s: server %s not responding, timed out\n",
-		       clnt->cl_protname, clnt->cl_server);
-	} else if (clnt->cl_chatty) {
-		printk(KERN_NOTICE "%s: server %s not responding, still trying\n",
-		       clnt->cl_protname, clnt->cl_server);
-	}
-
+	major = 1;
 	if (clnt->cl_autobind)
 		clnt->cl_port = 0;
 
@@ -666,6 +657,8 @@
 	} else if (clnt->cl_xprt->stream && !xprt_connected(clnt->cl_xprt)) {
 		task->tk_action = call_reconnect;
 		clnt->cl_stats->rpcretrans++;
+	} else if (major && RPCXPRT_SUPERCONGESTED(clnt->cl_xprt)) {
+		task->tk_action = call_ping;
 	} else {
 		task->tk_action = call_transmit;
 		clnt->cl_stats->rpcretrans++;
@@ -687,21 +680,20 @@
 	dprintk("RPC: %4d call_decode (status %d)\n", 
 				task->tk_pid, task->tk_status);
 
-	if (clnt->cl_chatty && (task->tk_flags & RPC_CALL_MAJORSEEN)) {
-		printk(KERN_NOTICE "%s: server %s OK\n",
-			clnt->cl_protname, clnt->cl_server);
-		task->tk_flags &= ~RPC_CALL_MAJORSEEN;
-	}
-
 	if (task->tk_status < 12) {
-		printk(KERN_WARNING "%s: too small RPC reply size (%d bytes)\n",
-			clnt->cl_protname, task->tk_status);
-		rpc_exit(task, -EIO);
+		if (!clnt->cl_softrtry) {
+			task->tk_action = call_transmit;
+			clnt->cl_stats->rpcretrans++;
+		} else {
+			printk(KERN_WARNING "%s: too small RPC reply size (%d bytes)\n",
+				clnt->cl_protname, task->tk_status);
+			rpc_exit(task, -EIO);
+		}
 		return;
 	}
 
 	/* Verify the RPC header */
-	if (!(p = call_verify(task)))
+	if (!(p = rpc_call_verify(task)))
 		return;
 
 	/*
@@ -760,8 +752,8 @@
 /*
  * Call header serialization
  */
-static u32 *
-call_header(struct rpc_task *task)
+u32 *
+rpc_call_header(struct rpc_task *task)
 {
 	struct rpc_clnt *clnt = task->tk_client;
 	struct rpc_xprt *xprt = clnt->cl_xprt;
@@ -781,10 +773,61 @@
 }
 
 /*
+ * Ping a non-responding server
+ */
+static void
+call_ping(struct rpc_task *task)
+{
+	task->tk_action = call_pingresult;
+	rpc_ping(task);
+}
+
+/*
+ * Interpret the result from ping
+ */
+static void
+call_pingresult(struct rpc_task *task)
+{
+	struct rpc_clnt	*clnt = task->tk_client;
+	struct rpc_xprt	*xprt = clnt->cl_xprt;
+	int		status = task->tk_status;
+
+	task->tk_status = 0;
+	if (status >= 0) {
+		task->tk_action = call_transmit;
+		return;
+	}
+	switch(status) {
+	case -ECONNREFUSED:
+	case -ENOTCONN:
+		if (clnt->cl_autobind || !clnt->cl_port) {
+			clnt->cl_port = 0;
+			task->tk_action = call_bind;
+			break;
+		}
+		if (xprt->stream) {
+			task->tk_action = call_reconnect;
+			break;
+		}
+	case -ENOMEM:
+	case -ENOBUFS:
+		rpc_delay(task, HZ >> 4);
+	case -ETIMEDOUT:
+		task->tk_action = call_ping;
+		break;
+	default:
+		if (clnt->cl_chatty)
+			printk("%s: RPC call returned error %d\n",
+			       clnt->cl_protname, -status);
+		rpc_exit(task,status);
+	}
+}
+
+/*
  * Reply header verification
  */
-static u32 *
-call_verify(struct rpc_task *task)
+u32 *
+rpc_call_verify(struct rpc_task *task)
 {
 	u32	*p = task->tk_rqstp->rq_rvec[0].iov_base, n;
 
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/sunrpc/ping.c linux.19p18/net/sunrpc/ping.c
--- linux.vanilla/net/sunrpc/ping.c	Thu Jan  1 01:00:00 1970
+++ linux.19p18/net/sunrpc/ping.c	Mon Feb 12 14:50:24 2001
@@ -0,0 +1,218 @@
+/*
+ * linux/net/sunrpc/ping.c
+ *
+ * Ping routing.
+ *
+ * Copyright (C) 2000, Trond Myklebust <trond.myklebust@fys.uio.no>
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/uio.h>
+#include <linux/in.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/xprt.h>
+#include <linux/sunrpc/sched.h>
+
+
+#define RPC_SLACK_SPACE		512	/* total overkill */
+#define RPC_PING_DELAY		(15*HZ)
+
+#ifdef RPC_DEBUG
+# define RPCDBG_FACILITY	RPCDBG_XPRT
+#endif
+
+static void ping_call_reserve(struct rpc_task *);
+static void ping_call_allocate(struct rpc_task *);
+static void ping_call_encode(struct rpc_task *);
+static void ping_call_transmit(struct rpc_task *);
+static void ping_call_receive(struct rpc_task *);
+static void ping_call_exit(struct rpc_task *);
+
+
+static void
+ping_call_reserve(struct rpc_task *task)
+{
+	dprintk("RPC: %4d, ping_call_reserve\n", task->tk_pid);
+	task->tk_status = 0;
+	task->tk_action  = ping_call_allocate;
+	task->tk_timeout = task->tk_client->cl_timeout.to_resrvval;
+	xprt_ping_reserve(task);
+}
+
+static void
+ping_call_allocate(struct rpc_task *task)
+{
+	struct rpc_clnt	*clnt = task->tk_client;
+	struct rpc_rqst	*req = task->tk_rqstp;
+	unsigned int	bufsiz;
+
+	dprintk("RPC: %4d, ping_call_allocate (status %d)\n",
+		task->tk_pid, task->tk_status);
+
+	task->tk_action = ping_call_exit;
+	if (task->tk_status < 0)
+		return;
+
+	bufsiz = rpcproc_bufsiz(clnt, task->tk_msg.rpc_proc) + RPC_SLACK_SPACE;
+	if (!(task->tk_buffer = rpc_malloc(task, bufsiz << 1))) {
+		task->tk_status = -ENOMEM;
+		return;
+	}
+	req->rq_svec[0].iov_base = (void *)task->tk_buffer;
+	req->rq_svec[0].iov_len	 = bufsiz;
+	req->rq_slen		 = 0;
+	req->rq_snr		 = 1;
+	req->rq_rvec[0].iov_base = (void *)((char *)task->tk_buffer + bufsiz);
+	req->rq_rvec[0].iov_len	 = bufsiz;
+	req->rq_rlen		 = bufsiz;
+	req->rq_rnr		 = 1;
+	task->tk_action		 = ping_call_encode;
+}
+
+static void
+ping_call_encode(struct rpc_task *task)
+{
+	struct rpc_rqst	*req = task->tk_rqstp;
+	u32		*p;
+
+	dprintk("RPC: %4d, ping_call_encode (status %d)\n",
+		task->tk_pid, task->tk_status);
+
+	if (task->tk_status < 0) {
+		task->tk_action = ping_call_exit;
+		return;
+	}
+	p = rpc_call_header(task);
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	task->tk_action = ping_call_transmit;
+}
+
+static void
+ping_call_transmit(struct rpc_task *task)
+{
+	dprintk("RPC: %4d, ping_call_transmit\n", task->tk_pid);
+	task->tk_action = ping_call_receive;
+	xprt_transmit(task);
+}
+
+static void
+ping_call_receive(struct rpc_task *task)
+{
+	struct rpc_clnt	*clnt = task->tk_client;
+	struct rpc_xprt	*xprt = clnt->cl_xprt;
+	struct rpc_rqst *req = task->tk_rqstp;
+	struct rpc_timeout *to = &req->rq_timeout;
+	u32 *p;
+
+	dprintk("RPC: %4d, ping_call_receive (status %d)\n",
+		task->tk_pid, task->tk_status);
+
+	if (task->tk_status >= 0)
+		p = rpc_call_verify(task);
+
+	task->tk_action = ping_call_exit;
+
+	if (task->tk_status >= 0 || task->tk_status == -EACCES) {
+		task->tk_status = 0;
+		if (xprt_norespond(xprt)) {
+			if (clnt->cl_chatty)
+				printk(KERN_NOTICE "%s: server %s OK\n",
+				       clnt->cl_protname, clnt->cl_server);
+			xprt_clear_norespond(xprt);
+		}
+		return;
+	}
+
+	switch (task->tk_status) {
+	case -ENOTCONN:
+		break;
+	case -ENOMEM:
+	case -EAGAIN:
+	case -ECONNREFUSED:
+	case -ETIMEDOUT:
+		if (!xprt_adjust_timeout(to)) {
+			task->tk_status = 0;
+			task->tk_action = ping_call_transmit;
+			break;
+		}
+	default:
+		if (clnt->cl_softrtry) {
+			task->tk_status = -EIO;
+			break;
+		}
+		if (clnt->cl_chatty) {
+			if (!xprt_test_and_set_norespond(xprt)) {
+				printk(KERN_NOTICE
+				       "%s: server %s is not responding\n",
+				       clnt->cl_protname, clnt->cl_server);
+			} else {
+				printk(KERN_NOTICE
+				       "%s: server %s still not responding\n",
+				       clnt->cl_protname, clnt->cl_server);
+			}
+		}
+		rpc_delay(task, RPC_PING_DELAY);
+	}
+}
+
+static void
+ping_call_exit(struct rpc_task *task)
+{
+	struct rpc_xprt	*xprt = task->tk_xprt;
+
+	dprintk("RPC: %4d, ping_call_exit (status %d)\n",
+		task->tk_pid, task->tk_status);
+
+	task->tk_action = NULL;
+	xprt_ping_release(task);
+
+	/* Sigh. rpc_delay() clears task->tk_status */
+	if (task->tk_status == 0 && xprt_norespond(xprt))
+		task->tk_status = -ETIMEDOUT;
+
+	xprt_clear_pinging(xprt);
+	rpc_wake_up_status(&xprt->pingwait, task->tk_status);
+}
+
+void
+rpc_ping(struct rpc_task *task)
+{
+	struct rpc_clnt *clnt = task->tk_client;
+	struct rpc_xprt	*xprt = clnt->cl_xprt;
+	struct rpc_task	*child;
+	struct rpc_message msg = {0, NULL, NULL, NULL};
+
+	dprintk("RPC: %4d, rpc_ping\n", task->tk_pid);
+
+ again:
+	if (xprt_test_and_set_pinging(xprt)) {
+		rpc_sleep_on(&xprt->pingwait, task, NULL, 0);
+		if (!xprt_pinging(xprt)) {
+			rpc_wake_up_task(task);
+			goto again;
+		}
+		dprintk("RPC: %4d, rpc_ping, waiting on completion\n",
+			task->tk_pid);
+		return;
+	}
+
+	child = rpc_new_child(clnt, task);
+	if (!child) {
+		dprintk("RPC: %4d, rpc_ping, failed to create child process\n",
+			task->tk_pid);
+		xprt_clear_pinging(xprt);
+		rpc_wake_up_status(&xprt->pingwait, -ENOMEM);
+		task->tk_status = -ENOMEM;
+		return;
+	}
+	rpc_call_setup(child, &msg, 0);
+	child->tk_action = ping_call_reserve;
+
+	dprintk("RPC: %4d, rpc_ping, running child process %4d\n",
+		task->tk_pid, child->tk_pid);
+	rpc_run_child(task, child, NULL);
+}
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/sunrpc/sched.c linux.19p18/net/sunrpc/sched.c
--- linux.vanilla/net/sunrpc/sched.c	Mon Dec 11 22:13:10 2000
+++ linux.19p18/net/sunrpc/sched.c	Mon Feb 12 14:50:24 2001
@@ -259,7 +259,7 @@
 		printk(KERN_ERR "RPC: task w/ running timer in rpc_make_runnable!!\n");
 		return;
 	}
-	task->tk_running = 1;
+	rpc_set_running(task);
 	if (RPC_IS_ASYNC(task)) {
 		if (RPC_IS_SLEEPING(task)) {
 			int status;
@@ -267,12 +267,13 @@
 			if (status < 0) {
 				printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status);
 				task->tk_status = status;
-			} else
-				task->tk_sleeping = 0;
+				return;
+			}
+			rpc_clear_sleeping(task);
+			wake_up(&rpciod_idle);
 		}
-		wake_up(&rpciod_idle);
 	} else {
-		task->tk_sleeping = 0;
+		rpc_clear_sleeping(task);
 		wake_up(&task->tk_wait);
 	}
 }
@@ -287,7 +288,7 @@
 	if (RPC_IS_ACTIVATED(task))
 		return;
 	task->tk_active = 1;
-	task->tk_sleeping = 1;
+	rpc_set_sleeping(task);
 	__rpc_make_runnable(task);
 }
 
@@ -327,7 +328,7 @@
 	/* Mark the task as being activated if so needed */
 	if (!RPC_IS_ACTIVATED(task)) {
 		task->tk_active = 1;
-		task->tk_sleeping = 1;
+		rpc_set_sleeping(task);
 	}
 
 	status = __rpc_add_wait_queue(q, task);
@@ -335,7 +336,7 @@
 		printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status);
 		task->tk_status = status;
 	} else {
-		task->tk_running = 0;
+		rpc_clear_running(task);
 		task->tk_callback = action;
 		__rpc_add_timer(task, timer);
 	}
@@ -609,21 +610,15 @@
 
 		/*
 		 * Check whether task is sleeping.
-		 * Note that if the task goes to sleep in tk_action,
-		 * and the RPC reply arrives before we get here, it will
-		 * have state RUNNING, but will still be on schedq.
-		 * 27/9/99: The above has been attempted fixed by
-		 *          introduction of task->tk_sleeping.
 		 */
 		spin_lock_irqsave(&rpc_queue_lock, oldflags);
 		if (!RPC_IS_RUNNING(task)) {
-			task->tk_sleeping = 1;
+			rpc_set_sleeping(task);
 			if (RPC_IS_ASYNC(task)) {
 				spin_unlock_irqrestore(&rpc_queue_lock, oldflags);
 				return 0;
 			}
-		} else
-			task->tk_sleeping = 0;
+		}
 		spin_unlock_irqrestore(&rpc_queue_lock, oldflags);
 
 		while (RPC_IS_SLEEPING(task)) {
@@ -689,18 +684,23 @@
 int
 rpc_execute(struct rpc_task *task)
 {
+	int status = -EIO;
 	if (rpc_inhibit) {
 		printk(KERN_INFO "RPC: execution inhibited!\n");
-		return -EIO;
+		goto out_release;
 	}
-	task->tk_running = 1;
 	if (task->tk_active) {
 		printk(KERN_ERR "RPC: active task was run twice!\n");
-		return -EWOULDBLOCK;
+		goto out_err;
 	}
 	task->tk_active = 1;
+	rpc_set_running(task);
 	
 	return __rpc_execute(task);
+ out_release:
+	rpc_release_task(task);
+ out_err:
+	return status;
 }
 
 /*
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/sunrpc/svcsock.c linux.19p18/net/sunrpc/svcsock.c
--- linux.vanilla/net/sunrpc/svcsock.c	Mon Dec 11 22:13:11 2000
+++ linux.19p18/net/sunrpc/svcsock.c	Mon Feb 12 14:50:24 2001
@@ -773,7 +773,6 @@
 			"svc_recv: service %p, wait queue active!\n",
 			 rqstp);
 
-again:
 	/* Initialize the buffers */
 	rqstp->rq_argbuf = rqstp->rq_defbuf;
 	rqstp->rq_resbuf = rqstp->rq_defbuf;
@@ -818,7 +817,7 @@
 	/* No data, incomplete (TCP) read, or accept() */
 	if (len == 0 || len == -EAGAIN) {
 		svc_sock_release(rqstp);
-		goto again;
+		return -EAGAIN;
 	}
 
 	rqstp->rq_secure  = ntohs(rqstp->rq_addr.sin_port) < 1024;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/sunrpc/xprt.c linux.19p18/net/sunrpc/xprt.c
--- linux.vanilla/net/sunrpc/xprt.c	Mon Dec 11 22:13:11 2000
+++ linux.19p18/net/sunrpc/xprt.c	Mon Feb 12 14:50:24 2001
@@ -1010,7 +1010,8 @@
 
 	switch (sk->state) {
 	case TCP_ESTABLISHED:
-		xprt_set_connected(xprt);
+		if (xprt_test_and_set_connected(xprt))
+			break;
 		if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->sending)
 			rpc_wake_up_task(xprt->snd_task);
 		rpc_wake_up(&xprt->reconn);
@@ -1045,16 +1046,14 @@
 	if (sock_wspace(sk) < min(sk->sndbuf,XPRT_MIN_WRITE_SPACE))
 		return;
 
-	spin_lock_irqsave(&xprt_sock_lock, oldflags);
-	if (xprt->write_space)
-		goto out_unlock;
-
-	xprt->write_space = 1;
+	if (xprt_test_and_set_wspace(xprt))
+		goto out;
 
+	spin_lock_irqsave(&xprt_sock_lock, oldflags);
 	if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->sending)
 		rpc_wake_up_task(xprt->snd_task);
- out_unlock:
 	spin_unlock_irqrestore(&xprt_sock_lock, oldflags);
+ out:
 	wake_up_interruptible(sk->sleep);
 }
 
@@ -1073,16 +1072,14 @@
 	if (sock_wspace(sk) < min(sk->sndbuf,XPRT_MIN_WRITE_SPACE))
 		return;
 
-	spin_lock_irqsave(&xprt_sock_lock, oldflags);
-	if (xprt->write_space)
-		goto out_unlock;
-
-	xprt->write_space = 1;
+	if (xprt_test_and_set_wspace(xprt))
+		goto out;
 
+	spin_lock_irqsave(&xprt_sock_lock, oldflags);
 	if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->sending)
 		rpc_wake_up_task(xprt->snd_task);
- out_unlock:
 	spin_unlock_irqrestore(&xprt_sock_lock, oldflags);
+ out:
 	wake_up_interruptible(sk->sleep);
 }
 
@@ -1115,8 +1112,10 @@
 {
 	struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt;
 	struct rpc_rqst	*req = task->tk_rqstp;
+	unsigned long	oldflags;
 
 	xprt_delete_tcp_timer(xprt);
+	spin_lock_irqsave(&xprt_sock_lock, oldflags);
 	if (xprt->snd_task && xprt->snd_task != task) {
 		dprintk("RPC: %4d TCP write queue full (task %d)\n",
 			task->tk_pid, xprt->snd_task->tk_pid);
@@ -1130,6 +1129,7 @@
 #endif
 		req->rq_bytes_sent = 0;
 	}
+	spin_unlock_irqrestore(&xprt_sock_lock, oldflags);
 	return xprt->snd_task == task;
 }
 
@@ -1142,9 +1142,12 @@
 	struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt;
 
 	if (xprt->snd_task && xprt->snd_task == task) {
+		unsigned long	oldflags;
+		spin_lock_irqsave(&xprt_sock_lock, oldflags);
 		xprt->snd_task = NULL;
 		if (!rpc_wake_up_next(&xprt->sending) && xprt->stream)
 			xprt_add_tcp_timer(xprt, RPCXPRT_TIMEOUT);
+		spin_unlock_irqrestore(&xprt_sock_lock, oldflags);
 	}
 }
 
@@ -1209,7 +1212,7 @@
 		if (!xprt->inet)
 			break;
 
-		xprt->write_space = 0;
+		xprt_clear_wspace(xprt);
 		status = -ENOMEM;
 		if (sock_wspace(xprt->inet) < req->rq_slen + MIN_WRITE_SPACE)
 			break;
@@ -1256,20 +1259,12 @@
 	case -ENOMEM:
 		/* Protect against (udp|tcp)_write_space */
 		spin_lock_irqsave(&xprt_sock_lock, oldflags);
-		if (!xprt->write_space) {
+		if (!xprt_wspace(xprt)) {
 			task->tk_timeout = req->rq_timeout.to_current;
 			rpc_sleep_on(&xprt->sending, task, NULL, NULL);
 		}
 		spin_unlock_irqrestore(&xprt_sock_lock, oldflags);
 		return;
-	case -EAGAIN:
-	case -ECONNREFUSED:
-	case -ENOTCONN:
-		/* Keep holding the socket if it is blocked */
-		if (!xprt->stream) {
-			rpc_delay(task, HZ>>4);
-			return;
-		}
 	default:
 		goto out_release;
 	}
@@ -1297,7 +1292,7 @@
 
 	dprintk("RPC: %4d xprt_receive\n", task->tk_pid);
 
-	req->rq_received= 0;
+	req->rq_received = 0;
 	task->tk_timeout = 0;
 	rpc_sleep_locked(&xprt->pending, task, NULL, NULL);
 }
@@ -1420,6 +1415,62 @@
 }
 
 /*
+ * Reserve a ping RPC call slot.
+ */
+int
+xprt_ping_reserve(struct rpc_task *task)
+{
+	struct rpc_xprt	*xprt = task->tk_xprt;
+	struct rpc_rqst	*req;
+
+	/* We already have an initialized request. */
+	if (task->tk_rqstp)
+		return 0;
+	if (xprt->shutdown)
+		task->tk_status = -EIO;
+
+	dprintk("RPC: %4d xprt_ping_reserve cong = %ld cwnd = %ld\n",
+				task->tk_pid, xprt->cong, xprt->cwnd);
+	start_bh_atomic();
+	if ((req = xprt->free) != NULL) {
+		xprt->free = req->rq_next;
+		req->rq_next = NULL;
+		task->tk_rqstp = req;
+		xprt_request_init(task, xprt);
+	} else
+		task->tk_status = -ENOBUFS;
+	end_bh_atomic();
+	dprintk("RPC: %4d xprt_ping_reserve returns %d\n",
+				task->tk_pid, task->tk_status);
+	if (!req)
+		BUG();
+	return task->tk_status;
+}
+
+/*
+ * Release an RPC call slot
+ */
+void
+xprt_ping_release(struct rpc_task *task)
+{
+	struct rpc_xprt	*xprt = task->tk_xprt;
+	struct rpc_rqst	*req;
+
+	xprt_up_transmit(task);
+	if (!(req = task->tk_rqstp))
+		return;
+	task->tk_rqstp = NULL;
+	memset(req, 0, sizeof(*req));	/* mark unused */
+
+	dprintk("RPC: %4d release request %p\n", task->tk_pid, req);
+
+	start_bh_atomic();
+	req->rq_next = xprt->free;
+	xprt->free   = req;
+	end_bh_atomic();
+}
+
+/*
  * Set default timeout parameters
  */
 void
@@ -1490,6 +1541,7 @@
 	xprt->sending = RPC_INIT_WAITQ("xprt_sending");
 	xprt->backlog = RPC_INIT_WAITQ("xprt_backlog");
 	xprt->reconn  = RPC_INIT_WAITQ("xprt_reconn");
+	xprt->pingwait  = RPC_INIT_WAITQ("xprt_pingwait");
 
 	/* initialize free list */
 	for (i = 0, req = xprt->slot; i < RPC_MAXREQS-1; i++, req++)
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/unix/af_unix.c linux.19p18/net/unix/af_unix.c
--- linux.vanilla/net/unix/af_unix.c	Mon Dec 11 22:13:12 2000
+++ linux.19p18/net/unix/af_unix.c	Wed Feb  7 09:45:06 2001
@@ -8,7 +8,7 @@
  *		as published by the Free Software Foundation; either version
  *		2 of the License, or (at your option) any later version.
  *
- * Version:	$Id: af_unix.c,v 1.76.2.5 2000/10/17 09:08:37 davem Exp $
+ * Version:	$Id: af_unix.c,v 1.76.2.6 2001/01/04 05:28:48 davem Exp $
  *
  * Fixes:
  *		Linus Torvalds	:	Assorted bug cures.
@@ -417,7 +417,7 @@
 {
 	struct sock *sk;
 
-	if (atomic_read(&unix_nr_socks) >= 2*max_files)
+	if (atomic_read(&unix_nr_socks) >= 2*files_stat.max_files)
 		return NULL;
 
 	MOD_INC_USE_COUNT;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/net/x25/af_x25.c linux.19p18/net/x25/af_x25.c
--- linux.vanilla/net/x25/af_x25.c	Mon Dec 11 22:13:12 2000
+++ linux.19p18/net/x25/af_x25.c	Thu Feb 15 16:31:00 2001
@@ -389,6 +389,9 @@
 	if (get_user(len, optlen))
 		return -EFAULT;
 
+	if (len < 0)
+		return -EINVAL;
+		
 	switch (optname) {
 		case X25_QBITINCL:
 			val = sk->protinfo.x25->qbitincl;
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/scripts/Configure linux.19p18/scripts/Configure
--- linux.vanilla/scripts/Configure	Sat Sep  9 18:42:51 2000
+++ linux.19p18/scripts/Configure	Tue Dec 19 02:16:58 2000
@@ -422,7 +422,18 @@
 function string () {
 	old=$(eval echo "\${$2}")
 	def=${old:-$3}
-	readln "$1 ($2) [$def] " "$def" "$old"
+	while :; do
+          if [ "$old" = "?" ]; then
+             readln "$1 ($2) [$def] " "$def" ""
+          else
+	     readln "$1 ($2) [$def] " "$def" "$old"
+          fi
+	  if [ "$ans" = "?" ]; then
+	    help "$2"
+	  else
+	    break
+	  fi
+	done
 	define_string "$2" "$ans"
 }
 #
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/scripts/kwhich linux.19p18/scripts/kwhich
--- linux.vanilla/scripts/kwhich	Mon Dec 11 22:13:12 2000
+++ linux.19p18/scripts/kwhich	Tue Jan  9 11:59:53 2001
@@ -7,7 +7,7 @@
         exit 1
 fi
 
-IFS=:
+IFS=":$IFS"
 for cmd in $*
 do
         for path in $PATH
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/scripts/lxdialog/checklist.c linux.19p18/scripts/lxdialog/checklist.c
--- linux.vanilla/scripts/lxdialog/checklist.c	Fri Apr 21 12:47:18 2000
+++ linux.19p18/scripts/lxdialog/checklist.c	Thu Feb  1 14:59:53 2001
@@ -51,6 +51,10 @@
     mvwaddch(win, choice, item_x, item[0]);
     wattrset (win, selected ? item_selected_attr : item_attr);
     waddstr (win, (char *)item+1);
+    if (selected) {
+	wmove (win, choice, check_x+1);
+	wrefresh (win);
+    }
 }
 
 /*
@@ -104,8 +108,8 @@
     print_button (dialog, "Select", y, x, selected == 0);
     print_button (dialog, " Help ", y, x + 14, selected == 1);
 
-    wmove(dialog, y, x+1 + 14*selected);
-    wrefresh (dialog);
+    /*    wmove(dialog, y, x+1 + 14*selected);
+    wrefresh (dialog);*/
 }
 
 /*
@@ -215,7 +219,7 @@
     print_buttons(dialog, height, width, 0);
 
     while (key != ESC) {
-	key = wgetch (dialog);
+	key = wgetch (list);
 
     	for (i = 0; i < max_choice; i++)
             if (toupper(key) == toupper(items[(scroll+i)*3+1][0]))
@@ -245,7 +249,7 @@
     		    print_arrows(dialog, choice, item_no, scroll,
 				box_y, box_x + check_x + 5, list_height);
 
-		    wrefresh (dialog);
+		    wnoutrefresh (dialog);
 
 		    continue;	/* wait for another key press */
 		} else
@@ -273,7 +277,7 @@
     		    print_arrows(dialog, choice, item_no, scroll,
 				box_y, box_x + check_x + 5, list_height);
 
-		    wrefresh (dialog);
+		    wnoutrefresh (dialog);
 
 		    continue;	/* wait for another key press */
 		} else
@@ -288,7 +292,7 @@
 		print_item (list, items[(scroll + choice) * 3 + 1],
 			    status[scroll + choice], choice, TRUE);
 		wnoutrefresh (list);
-		wrefresh (dialog);
+		wnoutrefresh (dialog);
 	    }
 	    continue;		/* wait for another key press */
 	}
@@ -306,7 +310,7 @@
 			? 1 : (button > 1 ? 0 : button);
 
 	    print_buttons(dialog, height, width, button);
-	    wrefresh (dialog);
+	    wnoutrefresh (dialog);
 	    break;
 	case 'S':
 	case 's':
@@ -329,7 +333,7 @@
 		    }
 		}
 		wnoutrefresh (list);
-		wrefresh (dialog);
+		wnoutrefresh (dialog);
             
 		for (i = 0; i < item_no; i++) {
 		    if (status[i]) {
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/scripts/lxdialog/menubox.c linux.19p18/scripts/lxdialog/menubox.c
--- linux.vanilla/scripts/lxdialog/menubox.c	Fri Apr 21 12:47:18 2000
+++ linux.19p18/scripts/lxdialog/menubox.c	Thu Feb  1 14:59:53 2001
@@ -91,6 +91,10 @@
     	wattrset (win, selected ? tag_key_selected_attr : tag_key_attr);
     	mvwaddch(win, choice, item_x+j, menu_item[j]);
     }
+    if (selected) {
+wmove (win, choice, item_x+1);
+wrefresh (win);
+    }
 }
 
 /*
@@ -267,9 +271,11 @@
 		 box_y, box_x+item_x+1, menu_height);
 
     print_buttons (dialog, height, width, 0);
+    wmove (menu, choice, item_x+1);
+    wrefresh (menu);
 
     while (key != ESC) {
-	key = wgetch(dialog);
+	key = wgetch(menu);
 
 	if (key < 256 && isalpha(key)) key = tolower(key);
 
@@ -372,8 +378,8 @@
             print_arrows(dialog, item_no, scroll,
                          box_y, box_x+item_x+1, menu_height);
 
-            wnoutrefresh (menu);
-            wrefresh (dialog);
+            wnoutrefresh (dialog);
+            wrefresh (menu);
 
 	    continue;		/* wait for another key press */
         }
@@ -386,7 +392,7 @@
 			? 2 : (button > 2 ? 0 : button);
 
 	    print_buttons(dialog, height, width, button);
-	    wrefresh (dialog);
+	    wrefresh (menu);
 	    break;
 	case ' ':
 	case 's':
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/scripts/makelst linux.19p18/scripts/makelst
--- linux.vanilla/scripts/makelst	Sat Sep  9 18:42:51 2000
+++ linux.19p18/scripts/makelst	Mon Feb 19 18:33:37 2001
@@ -2,7 +2,8 @@
 # A script to dump mixed source code & assembly
 # with correct relocations from System.map
 # Requires the following lines in Rules.make.
-#
+# Author(s): DJ Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) 
+#            William Stearns <wstearns@pobox.com>
 #%.lst: %.c
 #	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -g -c -o $*.o $<
 #	$(TOPDIR)/scripts/makelst $* $(TOPDIR) $(OBJDUMP)
@@ -16,6 +17,6 @@
 t3=`grep $t2 $2/System.map`
 t4=`echo $t3 | gawk '{ print $1 }'`
 t5=`echo $t1 | gawk '{ print $1 }'`
-t6=`echo $t4 - $t5 | sed s/a/A/g | sed s/b/B/g | sed s/c/C/g | sed s/d/D/g | sed s/e/E/g | sed s/f/F/g`
+t6=`echo $t4 - $t5 | sed -e s/a/A/g -e s/b/B/g -e s/c/C/g -e s/d/D/g -e s/e/E/g -e s/f/F/g`
 t7=`( echo  ibase=16 ; echo $t6 ) | bc`
 $3 --source --adjust-vma=$t7 $2/$1.o > $2/$1.lst
diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla/scripts/ver_linux linux.19p18/scripts/ver_linux
--- linux.vanilla/scripts/ver_linux	Fri Apr 21 12:47:18 2000
+++ linux.19p18/scripts/ver_linux	Wed Feb 14 14:28:18 2001
@@ -5,28 +5,64 @@
 # differ on your system.
 #
 PATH=/sbin:/usr/sbin:/bin:/usr/bin:$PATH
-echo '-- Versions installed: (if some fields are empty or looks'
-echo '-- unusual then possibly you have very old versions)'
+echo 'If some fields are empty or look unusual you may have an old version.'
+echo 'Compare to the current minimal requirements in Documentation/Changes.'
+echo ' '
+
 uname -a
-insmod -V  2>&1 | awk 'NR==1 {print "Kernel modules        ",$NF}'
+echo ' '
+
 echo "Gnu C                 " `gcc --version`
+
+make --version 2>&1 | awk -F, '{print $1}' | awk \
+      '/GNU Make/{print "Gnu make              ",$NF}'
+
 ld -v 2>&1 | awk -F\) '{print $1}' | awk \
-      '/BFD/{print "Binutils              ",$NF}'
-ls -l `ldd /bin/sh | awk '/libc/{print $3}'` | sed -e 's/\.so$//' \
-  | awk -F'[.-]'   '{print "Linux C Library        " $(NF-2)"."$(NF-1)"."$NF}'
-echo -n "Dynamic linker         "
-ldd -v > /dev/null 2>&1 && ldd -v || ldd --version |head -1
+      '/BFD/{print "binutils              ",$NF}'
+
+mount --version | awk -F\- '{print "util-linux            ", $NF}'
+
+insmod -V  2>&1 | awk 'NR==1 {print "modutils              ",$NF}'
+
+tune2fs 2>&1 | grep tune2fs | sed 's/,//' |  awk \
+'NR==1 {print "e2fsprogs             ", $2}'
+
+reiserfsck 2>&1 | grep reiserfsprogs | awk \
+'NR==1{print "reiserfsprogs         ", $NF}'
+
+cardmgr -V 2>&1| grep version | awk \
+'NR==1{print "pcmcia-cs             ", $3}'
+
+pppd --version 2>&1| grep version | awk \
+'NR==1{print "PPP                   ", $3}'
+
+isdnctrl 2>&1 | grep version | awk \
+'NR==1{print "isdn4k-utils          ", $NF}'
+
+ls -l `ldd /bin/sh | awk '/libc/{print $3}'` | sed \
+-e 's/\.so$//' | awk -F'[.-]'   '{print "Linux C Library        " \
+$(NF-2)"."$(NF-1)"."$NF}'
+
+ldd -v > /dev/null 2>&1 && ldd -v || ldd --version |head -1 | awk \
+'NR==1{print "Dynamic linker (ldd)  ", $NF}'
+
 ls -l /usr/lib/lib{g,stdc}++.so  2>/dev/null | awk -F. \
        '{print "Linux C++ Library      " $4"."$5"."$6}'
+
 ps --version 2>&1 | awk 'NR==1{print "Procps                ", $NF}'
-mount --version | awk -F\- '{print "Mount                 ", $NF}'
-hostname -V 2>&1 | awk 'NR==1{print "Net-tools             ", $NF}'
+
+ifconfig --version 2>&1 | grep tools | awk \
+'NR==1{print "Net-tools             ", $NF}'
+
 # Kbd needs 'loadkeys -h',
 loadkeys -h 2>&1 | awk \
 '(NR==1 && ($3 !~ /option/)) {print "Kbd                   ", $3}'
+
 # while console-tools needs 'loadkeys -V'.
 loadkeys -V 2>&1 | awk \
 '(NR==1 && ($2 ~ /console-tools/)) {print "Console-tools         ", $3}'
-expr --v | awk 'NR==1{print "Sh-utils              ", $NF}'
+
+expr --v 2>&1 | awk 'NR==1{print "Sh-utils              ", $NF}'
+
 X=`cat /proc/modules | sed -e "s/ .*$//"`
 echo "Modules Loaded         "$X
